1 /* NeXT/Open/GNUstep / macOS communication module. -*- coding: utf-8 -*-
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2019 Free Software
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or (at
11 your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30 interpretation of even the system includes. */
36 #include <sys/types.h>
42 #include <c-strcase.h>
46 #include "blockinput.h"
47 #include "sysselect.h"
50 #include "character.h"
52 #include "composite.h"
55 #include "termhooks.h"
63 #ifdef NS_IMPL_GNUSTEP
71 static EmacsMenu *dockMenu;
73 static EmacsMenu *mainMenu;
76 /* ==========================================================================
78 NSTRACE, Trace support.
80 ========================================================================== */
84 /* The following use "volatile" since they can be accessed from
86 volatile int nstrace_num = 0;
87 volatile int nstrace_depth = 0;
89 /* When 0, no trace is emitted. This is used by NSTRACE_WHEN and
90 NSTRACE_UNLESS to silence functions called.
92 TODO: This should really be a thread-local variable, to avoid that
93 a function with disabled trace thread silence trace output in
94 another. However, in practice this seldom is a problem. */
95 volatile int nstrace_enabled_global = 1;
97 /* Called when nstrace_enabled goes out of scope. */
98 void nstrace_leave(int * pointer_to_nstrace_enabled)
100 if (*pointer_to_nstrace_enabled)
107 /* Called when nstrace_saved_enabled_global goes out of scope. */
108 void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
110 nstrace_enabled_global = *pointer_to_saved_enabled_global;
114 char const * nstrace_fullscreen_type_name (int fs_type)
118 case -1: return "-1";
119 case FULLSCREEN_NONE: return "FULLSCREEN_NONE";
120 case FULLSCREEN_WIDTH: return "FULLSCREEN_WIDTH";
121 case FULLSCREEN_HEIGHT: return "FULLSCREEN_HEIGHT";
122 case FULLSCREEN_BOTH: return "FULLSCREEN_BOTH";
123 case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
124 default: return "FULLSCREEN_?????";
130 /* ==========================================================================
132 NSColor, EmacsColor category.
134 ========================================================================== */
135 @implementation NSColor (EmacsColor)
136 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
137 blue:(CGFloat)blue alpha:(CGFloat)alpha
139 #if defined (NS_IMPL_COCOA) \
140 && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
141 if (ns_use_srgb_colorspace
142 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
143 && [NSColor respondsToSelector:
144 @selector(colorWithSRGBRed:green:blue:alpha:)]
147 return [NSColor colorWithSRGBRed: red
152 return [NSColor colorWithCalibratedRed: red
158 - (NSColor *)colorUsingDefaultColorSpace
160 /* FIXMES: We're checking for colorWithSRGBRed here so this will
161 only work in the same place as in the method above. It should
162 really be a check whether we're on macOS 10.7 or above. */
163 #if defined (NS_IMPL_COCOA) \
164 && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
165 if (ns_use_srgb_colorspace
166 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
167 && [NSColor respondsToSelector:
168 @selector(colorWithSRGBRed:green:blue:alpha:)]
171 return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
173 return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
178 /* ==========================================================================
182 ========================================================================== */
184 /* Convert a symbol indexed with an NSxxx value to a value as defined
185 in keyboard.c (lispy_function_key). I hope this is a correct way
186 of doing things... */
187 static unsigned convert_ns_to_X_keysym[] =
189 NSHomeFunctionKey, 0x50,
190 NSLeftArrowFunctionKey, 0x51,
191 NSUpArrowFunctionKey, 0x52,
192 NSRightArrowFunctionKey, 0x53,
193 NSDownArrowFunctionKey, 0x54,
194 NSPageUpFunctionKey, 0x55,
195 NSPageDownFunctionKey, 0x56,
196 NSEndFunctionKey, 0x57,
197 NSBeginFunctionKey, 0x58,
198 NSSelectFunctionKey, 0x60,
199 NSPrintFunctionKey, 0x61,
200 NSClearLineFunctionKey, 0x0B,
201 NSExecuteFunctionKey, 0x62,
202 NSInsertFunctionKey, 0x63,
203 NSUndoFunctionKey, 0x65,
204 NSRedoFunctionKey, 0x66,
205 NSMenuFunctionKey, 0x67,
206 NSFindFunctionKey, 0x68,
207 NSHelpFunctionKey, 0x6A,
208 NSBreakFunctionKey, 0x6B,
210 NSF1FunctionKey, 0xBE,
211 NSF2FunctionKey, 0xBF,
212 NSF3FunctionKey, 0xC0,
213 NSF4FunctionKey, 0xC1,
214 NSF5FunctionKey, 0xC2,
215 NSF6FunctionKey, 0xC3,
216 NSF7FunctionKey, 0xC4,
217 NSF8FunctionKey, 0xC5,
218 NSF9FunctionKey, 0xC6,
219 NSF10FunctionKey, 0xC7,
220 NSF11FunctionKey, 0xC8,
221 NSF12FunctionKey, 0xC9,
222 NSF13FunctionKey, 0xCA,
223 NSF14FunctionKey, 0xCB,
224 NSF15FunctionKey, 0xCC,
225 NSF16FunctionKey, 0xCD,
226 NSF17FunctionKey, 0xCE,
227 NSF18FunctionKey, 0xCF,
228 NSF19FunctionKey, 0xD0,
229 NSF20FunctionKey, 0xD1,
230 NSF21FunctionKey, 0xD2,
231 NSF22FunctionKey, 0xD3,
232 NSF23FunctionKey, 0xD4,
233 NSF24FunctionKey, 0xD5,
235 NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
236 NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
237 NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */
239 NSTabCharacter, 0x09,
240 0x19, 0x09, /* left tab->regular since pass shift */
241 NSCarriageReturnCharacter, 0x0D,
242 NSNewlineCharacter, 0x0D,
243 NSEnterCharacter, 0x8D,
245 0x41|NSEventModifierFlagNumericPad, 0xAE, /* KP_Decimal */
246 0x43|NSEventModifierFlagNumericPad, 0xAA, /* KP_Multiply */
247 0x45|NSEventModifierFlagNumericPad, 0xAB, /* KP_Add */
248 0x4B|NSEventModifierFlagNumericPad, 0xAF, /* KP_Divide */
249 0x4E|NSEventModifierFlagNumericPad, 0xAD, /* KP_Subtract */
250 0x51|NSEventModifierFlagNumericPad, 0xBD, /* KP_Equal */
251 0x52|NSEventModifierFlagNumericPad, 0xB0, /* KP_0 */
252 0x53|NSEventModifierFlagNumericPad, 0xB1, /* KP_1 */
253 0x54|NSEventModifierFlagNumericPad, 0xB2, /* KP_2 */
254 0x55|NSEventModifierFlagNumericPad, 0xB3, /* KP_3 */
255 0x56|NSEventModifierFlagNumericPad, 0xB4, /* KP_4 */
256 0x57|NSEventModifierFlagNumericPad, 0xB5, /* KP_5 */
257 0x58|NSEventModifierFlagNumericPad, 0xB6, /* KP_6 */
258 0x59|NSEventModifierFlagNumericPad, 0xB7, /* KP_7 */
259 0x5B|NSEventModifierFlagNumericPad, 0xB8, /* KP_8 */
260 0x5C|NSEventModifierFlagNumericPad, 0xB9, /* KP_9 */
262 0x1B, 0x1B /* escape */
265 /* On macOS picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
266 the maximum font size to NOT antialias. On GNUstep there is currently
267 no way to control this behavior. */
268 float ns_antialias_threshold;
270 NSArray *ns_send_types = 0, *ns_return_types = 0;
271 static NSArray *ns_drag_types = 0;
272 NSString *ns_app_name = @"Emacs"; /* default changed later */
274 /* Display variables */
275 struct ns_display_info *x_display_list; /* Chain of existing displays */
276 long context_menu_value = 0;
279 static int ns_window_num = 0;
280 static BOOL ns_fake_keydown = NO;
282 static BOOL ns_menu_bar_is_hidden = NO;
284 /*static int debug_lock = 0; */
287 static BOOL send_appdefined = YES;
288 #define NO_APPDEFINED_DATA (-8)
289 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
290 static NSTimer *timed_entry = 0;
291 static NSTimer *scroll_repeat_entry = nil;
292 static fd_set select_readfds, select_writefds;
293 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
294 static int select_nfds = 0, select_valid = 0;
295 static struct timespec select_timeout = { 0, 0 };
296 static int selfds[2] = { -1, -1 };
297 static pthread_mutex_t select_mutex;
298 static NSAutoreleasePool *outerpool;
299 static struct input_event *emacs_event = NULL;
300 static struct input_event *q_event_ptr = NULL;
301 static int n_emacs_events_pending = 0;
302 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
303 *ns_pending_service_args;
304 static BOOL ns_do_open_file = NO;
305 static BOOL ns_last_use_native_fullscreen;
307 /* Non-zero means that a HELP_EVENT has been generated since Emacs
310 static BOOL any_help_event_p = NO;
313 struct input_event *q;
319 static NSString *represented_filename = nil;
320 static struct frame *represented_frame = 0;
324 * State for pending menu activation:
325 * MENU_NONE Normal state
326 * MENU_PENDING A menu has been clicked on, but has been canceled so we can
327 * run lisp to update the menu.
328 * MENU_OPENING Menu is up to date, and the click event is redone so the menu
332 #define MENU_PENDING 1
333 #define MENU_OPENING 2
334 static int menu_will_open_state = MENU_NONE;
336 /* Saved position for menu click. */
337 static CGPoint menu_mouse_point;
340 /* Convert modifiers in a NeXTstep event to emacs style modifiers. */
341 #define NS_FUNCTION_KEY_MASK 0x800000
342 #define NSLeftControlKeyMask (0x000001 | NSEventModifierFlagControl)
343 #define NSRightControlKeyMask (0x002000 | NSEventModifierFlagControl)
344 #define NSLeftCommandKeyMask (0x000008 | NSEventModifierFlagCommand)
345 #define NSRightCommandKeyMask (0x000010 | NSEventModifierFlagCommand)
346 #define NSLeftAlternateKeyMask (0x000020 | NSEventModifierFlagOption)
347 #define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption)
348 #define EV_MODIFIERS2(flags) \
349 (((flags & NSEventModifierFlagHelp) ? \
350 hyper_modifier : 0) \
351 | (!EQ (ns_right_alternate_modifier, Qleft) && \
352 ((flags & NSRightAlternateKeyMask) \
353 == NSRightAlternateKeyMask) ? \
354 parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
355 | ((flags & NSEventModifierFlagOption) ? \
356 parse_solitary_modifier (ns_alternate_modifier) : 0) \
357 | ((flags & NSEventModifierFlagShift) ? \
358 shift_modifier : 0) \
359 | (!EQ (ns_right_control_modifier, Qleft) && \
360 ((flags & NSRightControlKeyMask) \
361 == NSRightControlKeyMask) ? \
362 parse_solitary_modifier (ns_right_control_modifier) : 0) \
363 | ((flags & NSEventModifierFlagControl) ? \
364 parse_solitary_modifier (ns_control_modifier) : 0) \
365 | ((flags & NS_FUNCTION_KEY_MASK) ? \
366 parse_solitary_modifier (ns_function_modifier) : 0) \
367 | (!EQ (ns_right_command_modifier, Qleft) && \
368 ((flags & NSRightCommandKeyMask) \
369 == NSRightCommandKeyMask) ? \
370 parse_solitary_modifier (ns_right_command_modifier) : 0) \
371 | ((flags & NSEventModifierFlagCommand) ? \
372 parse_solitary_modifier (ns_command_modifier):0))
373 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
375 #define EV_UDMODIFIERS(e) \
376 ((([e type] == NSEventTypeLeftMouseDown) ? down_modifier : 0) \
377 | (([e type] == NSEventTypeRightMouseDown) ? down_modifier : 0) \
378 | (([e type] == NSEventTypeOtherMouseDown) ? down_modifier : 0) \
379 | (([e type] == NSEventTypeLeftMouseDragged) ? down_modifier : 0) \
380 | (([e type] == NSEventTypeRightMouseDragged) ? down_modifier : 0) \
381 | (([e type] == NSEventTypeOtherMouseDragged) ? down_modifier : 0) \
382 | (([e type] == NSEventTypeLeftMouseUp) ? up_modifier : 0) \
383 | (([e type] == NSEventTypeRightMouseUp) ? up_modifier : 0) \
384 | (([e type] == NSEventTypeOtherMouseUp) ? up_modifier : 0))
386 #define EV_BUTTON(e) \
387 ((([e type] == NSEventTypeLeftMouseDown) || ([e type] == NSEventTypeLeftMouseUp)) ? 0 : \
388 (([e type] == NSEventTypeRightMouseDown) || ([e type] == NSEventTypeRightMouseUp)) ? 2 : \
389 [e buttonNumber] - 1)
391 /* Convert the time field to a timestamp in milliseconds. */
392 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
394 /* This is a piece of code which is common to all the event handling
395 methods. Maybe it should even be a function. */
396 #define EV_TRAILER(e) \
398 XSETFRAME (emacs_event->frame_or_window, emacsframe); \
402 #define EV_TRAILER2(e) \
404 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
407 Lisp_Object tem = Vinhibit_quit; \
408 Vinhibit_quit = Qt; \
409 n_emacs_events_pending++; \
410 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
411 Vinhibit_quit = tem; \
414 hold_event (emacs_event); \
415 EVENT_INIT (*emacs_event); \
416 ns_send_appdefined (-1); \
420 /* These flags will be OR'd or XOR'd with the NSWindow's styleMask
421 property depending on what we're doing. */
422 #define FRAME_DECORATED_FLAGS (NSWindowStyleMaskTitled \
423 | NSWindowStyleMaskResizable \
424 | NSWindowStyleMaskMiniaturizable \
425 | NSWindowStyleMaskClosable)
426 #define FRAME_UNDECORATED_FLAGS NSWindowStyleMaskBorderless
428 /* TODO: get rid of need for these forward declarations */
429 static void ns_condemn_scroll_bars (struct frame *f);
430 static void ns_judge_scroll_bars (struct frame *f);
433 /* ==========================================================================
437 ========================================================================== */
440 ns_set_represented_filename (NSString *fstr, struct frame *f)
442 represented_filename = [fstr retain];
443 represented_frame = f;
447 ns_init_events (struct input_event *ev)
454 ns_finish_events (void)
460 hold_event (struct input_event *event)
462 if (hold_event_q.nr == hold_event_q.cap)
464 if (hold_event_q.cap == 0) hold_event_q.cap = 10;
465 else hold_event_q.cap *= 2;
467 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
470 hold_event_q.q[hold_event_q.nr++] = *event;
471 /* Make sure ns_read_socket is called, i.e. we have input. */
473 send_appdefined = YES;
477 append2 (Lisp_Object list, Lisp_Object item)
478 /* --------------------------------------------------------------------------
479 Utility to append to a list
480 -------------------------------------------------------------------------- */
482 return CALLN (Fnconc, list, list1 (item));
487 ns_etc_directory (void)
488 /* If running as a self-contained app bundle, return as a string the
489 filename of the etc directory, if present; else nil. */
491 NSBundle *bundle = [NSBundle mainBundle];
492 NSString *resourceDir = [bundle resourcePath];
493 NSString *resourcePath;
494 NSFileManager *fileManager = [NSFileManager defaultManager];
497 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
498 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
500 if (isDir) return [resourcePath UTF8String];
508 /* If running as a self-contained app bundle, return as a path string
509 the filenames of the libexec and bin directories, ie libexec:bin.
510 Otherwise, return nil.
511 Normally, Emacs does not add its own bin/ directory to the PATH.
512 However, a self-contained NS build has a different layout, with
513 bin/ and libexec/ subdirectories in the directory that contains
515 We put libexec first, because init_callproc_1 uses the first
516 element to initialize exec-directory. An alternative would be
517 for init_callproc to check for invocation-directory/libexec.
520 NSBundle *bundle = [NSBundle mainBundle];
521 NSString *resourceDir = [bundle resourcePath];
522 NSString *binDir = [bundle bundlePath];
523 NSString *resourcePath, *resourcePaths;
525 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
526 NSFileManager *fileManager = [NSFileManager defaultManager];
528 NSEnumerator *pathEnum;
531 range = [resourceDir rangeOfString: @"Contents"];
532 if (range.location != NSNotFound)
534 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
536 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
540 paths = [binDir stringsByAppendingPaths:
541 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
542 pathEnum = [paths objectEnumerator];
545 while ((resourcePath = [pathEnum nextObject]))
547 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
550 if ([resourcePaths length] > 0)
552 = [resourcePaths stringByAppendingString: pathSeparator];
554 = [resourcePaths stringByAppendingString: resourcePath];
557 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
565 /* If running as a self-contained app bundle, return as a path string
566 the filenames of the site-lisp and lisp directories.
567 Ie, site-lisp:lisp. Otherwise, return nil. */
569 NSBundle *bundle = [NSBundle mainBundle];
570 NSString *resourceDir = [bundle resourcePath];
571 NSString *resourcePath, *resourcePaths;
572 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
573 NSFileManager *fileManager = [NSFileManager defaultManager];
575 NSArray *paths = [resourceDir stringsByAppendingPaths:
576 [NSArray arrayWithObjects:
577 @"site-lisp", @"lisp", nil]];
578 NSEnumerator *pathEnum = [paths objectEnumerator];
581 /* Hack to skip site-lisp. */
582 if (no_site_lisp) resourcePath = [pathEnum nextObject];
584 while ((resourcePath = [pathEnum nextObject]))
586 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
589 if ([resourcePaths length] > 0)
591 = [resourcePaths stringByAppendingString: pathSeparator];
593 = [resourcePaths stringByAppendingString: resourcePath];
596 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
603 ns_init_locale (void)
604 /* macOS doesn't set any environment variables for the locale when run
605 from the GUI. Get the locale from the OS and set LANG. */
607 NSLocale *locale = [NSLocale currentLocale];
609 NSTRACE ("ns_init_locale");
613 /* It seems macOS should probably use UTF-8 everywhere.
614 'localeIdentifier' does not specify the encoding, and I can't
615 find any way to get the OS to tell us which encoding to use,
616 so hard-code '.UTF-8'. */
617 NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
618 [locale localeIdentifier]];
620 /* Set LANG to locale, but not if LANG is already set. */
621 setenv("LANG", [localeID UTF8String], 0);
623 @catch (NSException *e)
625 NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
631 ns_release_object (void *obj)
632 /* --------------------------------------------------------------------------
633 Release an object (callable from C)
634 -------------------------------------------------------------------------- */
641 ns_retain_object (void *obj)
642 /* --------------------------------------------------------------------------
643 Retain an object (callable from C)
644 -------------------------------------------------------------------------- */
651 ns_alloc_autorelease_pool (void)
652 /* --------------------------------------------------------------------------
653 Allocate a pool for temporary objects (callable from C)
654 -------------------------------------------------------------------------- */
656 return [[NSAutoreleasePool alloc] init];
661 ns_release_autorelease_pool (void *pool)
662 /* --------------------------------------------------------------------------
663 Free a pool and temporary objects it refers to (callable from C)
664 -------------------------------------------------------------------------- */
666 ns_release_object (pool);
671 ns_menu_bar_should_be_hidden (void)
672 /* True, if the menu bar should be hidden. */
674 return !NILP (ns_auto_hide_menu_bar)
675 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
688 static struct EmacsMargins
689 ns_screen_margins (NSScreen *screen)
690 /* The parts of SCREEN used by the operating system. */
692 NSTRACE ("ns_screen_margins");
694 struct EmacsMargins margins;
696 NSRect screenFrame = [screen frame];
697 NSRect screenVisibleFrame = [screen visibleFrame];
699 /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
700 menu bar, check this explicitly. */
701 if (ns_menu_bar_should_be_hidden())
707 CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
708 CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
709 + screenVisibleFrame.size.height);
711 margins.top = frameTop - visibleFrameTop;
715 CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
716 CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
717 + screenVisibleFrame.size.width);
718 margins.right = frameRight - visibleFrameRight;
721 margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
722 margins.left = screenVisibleFrame.origin.x - screenFrame.origin.x;
724 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
734 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
735 assumed to contain a hidden dock. macOS currently use 4 pixels for
736 this, however, to be future compatible, a larger value is used. */
737 #define DOCK_IGNORE_LIMIT 6
739 static struct EmacsMargins
740 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
741 /* The parts of SCREEN used by the operating system, excluding the parts
742 reserved for an hidden dock. */
744 NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
746 struct EmacsMargins margins = ns_screen_margins(screen);
748 /* macOS (currently) reserved 4 pixels along the edge where a hidden
749 dock is located. Unfortunately, it's not possible to find the
750 location and information about if the dock is hidden. Instead,
751 it is assumed that if the margin of an edge is less than
752 DOCK_IGNORE_LIMIT, it contains a hidden dock. */
753 if (margins.left <= DOCK_IGNORE_LIMIT)
757 if (margins.right <= DOCK_IGNORE_LIMIT)
761 if (margins.top <= DOCK_IGNORE_LIMIT)
765 /* Note: This doesn't occur in current versions of macOS, but
766 included for completeness and future compatibility. */
767 if (margins.bottom <= DOCK_IGNORE_LIMIT)
772 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
783 ns_menu_bar_height (NSScreen *screen)
784 /* The height of the menu bar, if visible.
786 Note: Don't use this when fullscreen is enabled -- the screen
787 sometimes includes, sometimes excludes the menu bar area. */
789 struct EmacsMargins margins = ns_screen_margins(screen);
791 CGFloat res = margins.top;
793 NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
800 ns_row_rect (struct window *w, struct glyph_row *row,
801 enum glyph_row_area area)
802 /* Get the row as an NSRect. */
804 struct frame *f = XFRAME (WINDOW_FRAME (w));
806 int window_x, window_y, window_width;
808 window_box (w, area, &window_x, &window_y, &window_width, 0);
810 rect.origin.x = window_x;
811 rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
812 rect.origin.y = max (rect.origin.y, window_y);
813 rect.size.width = window_width;
814 rect.size.height = row->visible_height;
820 /* ==========================================================================
822 Focus (clipping) and screen update
824 ========================================================================== */
827 // Window constraining
828 // -------------------
830 // To ensure that the windows are not placed under the menu bar, they
831 // are typically moved by the call-back constrainFrameRect. However,
832 // by overriding it, it's possible to inhibit this, leaving the window
833 // in it's original position.
835 // It's possible to hide the menu bar. However, technically, it's only
836 // possible to hide it when the application is active. To ensure that
837 // this work properly, the menu bar and window constraining are
838 // deferred until the application becomes active.
840 // Even though it's not possible to manually move a window above the
841 // top of the screen, it is allowed if it's done programmatically,
842 // when the menu is hidden. This allows the editable area to cover the
843 // full screen height.
848 // Use the following extra files:
851 // ;; Hide menu and place frame slightly above the top of the screen.
852 // (setq ns-auto-hide-menu-bar t)
853 // (set-frame-position (selected-frame) 0 -20)
857 // emacs -Q -l init.el
859 // Result: No menu bar, and the title bar should be above the screen.
865 // Result: Menu bar visible, frame placed immediately below the menu.
868 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
870 NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
871 NSTRACE_ARG_RECT (frameRect));
873 // --------------------
874 // Collect information about the screen the frame is covering.
877 NSArray *screens = [NSScreen screens];
878 NSUInteger nr_screens = [screens count];
882 // The height of the menu bar, if present in any screen the frame is
884 int menu_bar_height = 0;
886 // A rectangle covering all the screen the frame is displayed in.
887 NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
888 for (i = 0; i < nr_screens; ++i )
890 NSScreen *s = [screens objectAtIndex: i];
891 NSRect scrRect = [s frame];
893 NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
894 i, NSTRACE_ARG_RECT (scrRect));
896 if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
898 multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
902 CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
903 menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
908 NSTRACE_RECT ("multiscreenRect", multiscreenRect);
910 NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
912 if (multiscreenRect.size.width == 0
913 || multiscreenRect.size.height == 0)
915 // Failed to find any monitor, give up.
916 NSTRACE_MSG ("multiscreenRect empty");
917 NSTRACE_RETURN_RECT (frameRect);
922 // --------------------
923 // Find a suitable placement.
926 if (ns_menu_bar_should_be_hidden())
928 // When the menu bar is hidden, the user may place part of the
929 // frame above the top of the screen, for example to hide the
932 // Hence, keep the original position.
936 // Ensure that the frame is below the menu bar, or below the top
939 // This assume that the menu bar is placed at the top in the
940 // rectangle that covers the monitors. (It doesn't have to be,
941 // but if it's not it's hard to do anything useful.)
942 CGFloat topOfWorkArea = (multiscreenRect.origin.y
943 + multiscreenRect.size.height
946 CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
947 if (topOfFrame > topOfWorkArea)
949 frameRect.origin.y -= topOfFrame - topOfWorkArea;
950 NSTRACE_RECT ("After placement adjust", frameRect);
954 // Include the following section to restrict frame to the screens.
955 // (If so, update it to allow the frame to stretch down below the
958 // --------------------
959 // Ensure frame doesn't stretch below the screens.
962 CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
966 frameRect.origin.y = multiscreenRect.origin.y;
967 frameRect.size.height -= diff;
971 NSTRACE_RETURN_RECT (frameRect);
977 ns_constrain_all_frames (void)
978 /* --------------------------------------------------------------------------
979 Ensure that the menu bar doesn't cover any frames.
980 -------------------------------------------------------------------------- */
982 Lisp_Object tail, frame;
984 NSTRACE ("ns_constrain_all_frames");
988 FOR_EACH_FRAME (tail, frame)
990 struct frame *f = XFRAME (frame);
993 EmacsView *view = FRAME_NS_VIEW (f);
995 if (![view isFullscreen])
998 setFrame:constrain_frame_rect([[view window] frame], false)
1009 ns_update_auto_hide_menu_bar (void)
1010 /* --------------------------------------------------------------------------
1011 Show or hide the menu bar, based on user setting.
1012 -------------------------------------------------------------------------- */
1014 #ifdef NS_IMPL_COCOA
1015 NSTRACE ("ns_update_auto_hide_menu_bar");
1019 if (NSApp != nil && [NSApp isActive])
1021 // Note, "setPresentationOptions" triggers an error unless the
1022 // application is active.
1023 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
1025 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
1027 NSApplicationPresentationOptions options
1028 = NSApplicationPresentationDefault;
1030 if (menu_bar_should_be_hidden)
1031 options |= NSApplicationPresentationAutoHideMenuBar
1032 | NSApplicationPresentationAutoHideDock;
1034 [NSApp setPresentationOptions: options];
1036 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
1038 if (!ns_menu_bar_is_hidden)
1040 ns_constrain_all_frames ();
1051 ns_update_begin (struct frame *f)
1052 /* --------------------------------------------------------------------------
1053 Prepare for a grouped sequence of drawing calls
1054 external (RIF) call; whole frame, called before update_window_begin
1055 -------------------------------------------------------------------------- */
1057 #ifdef NS_IMPL_COCOA
1058 EmacsView *view = FRAME_NS_VIEW (f);
1060 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1062 ns_update_auto_hide_menu_bar ();
1064 if ([view isFullscreen] && [view fsIsNative])
1066 // Fix reappearing tool bar in fullscreen for Mac OS X 10.7
1067 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1068 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1069 if (! tbar_visible != ! [toolbar isVisible])
1070 [toolbar setVisible: tbar_visible];
1077 ns_update_window_begin (struct window *w)
1078 /* --------------------------------------------------------------------------
1079 Prepare for a grouped sequence of drawing calls
1080 external (RIF) call; for one window, called after update_begin
1081 -------------------------------------------------------------------------- */
1083 struct frame *f = XFRAME (WINDOW_FRAME (w));
1084 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1086 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1087 w->output_cursor = w->cursor;
1091 if (f == hlinfo->mouse_face_mouse_frame)
1093 /* Don't do highlighting for mouse motion during the update. */
1094 hlinfo->mouse_face_defer = 1;
1096 /* If the frame needs to be redrawn,
1097 simply forget about any prior mouse highlighting. */
1098 if (FRAME_GARBAGED_P (f))
1099 hlinfo->mouse_face_window = Qnil;
1101 /* (further code for mouse faces ifdef'd out in other terms elided) */
1109 ns_update_window_end (struct window *w, bool cursor_on_p,
1110 bool mouse_face_overwritten_p)
1111 /* --------------------------------------------------------------------------
1112 Finished a grouped sequence of drawing calls
1113 external (RIF) call; for one window called before update_end
1114 -------------------------------------------------------------------------- */
1116 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1118 /* note: this fn is nearly identical in all terms */
1119 if (!w->pseudo_window_p)
1124 display_and_set_cursor (w, 1,
1125 w->output_cursor.hpos, w->output_cursor.vpos,
1126 w->output_cursor.x, w->output_cursor.y);
1128 if (draw_window_fringes (w, 1))
1130 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1131 x_draw_right_divider (w);
1133 x_draw_vertical_border (w);
1139 /* If a row with mouse-face was overwritten, arrange for
1140 frame_up_to_date to redisplay the mouse highlight. */
1141 if (mouse_face_overwritten_p)
1142 reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1147 ns_update_end (struct frame *f)
1148 /* --------------------------------------------------------------------------
1149 Finished a grouped sequence of drawing calls
1150 external (RIF) call; for whole frame, called after update_window_end
1151 -------------------------------------------------------------------------- */
1153 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1155 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1156 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1161 ns_clip_to_rect (struct frame *f, NSRect *r, int n)
1162 /* --------------------------------------------------------------------------
1163 Clip the drawing area to rectangle r in frame f. If drawing is not
1164 currently possible mark r as dirty and return NO, otherwise return
1166 -------------------------------------------------------------------------- */
1168 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_clip_to_rect");
1171 NSTRACE_RECT ("r", *r);
1173 if ([NSView focusView] == FRAME_NS_VIEW (f))
1175 [[NSGraphicsContext currentContext] saveGraphicsState];
1177 NSRectClipList (r, 2);
1185 NSView *view = FRAME_NS_VIEW (f);
1187 for (i = 0 ; i < n ; i++)
1188 [view setNeedsDisplayInRect:r[i]];
1197 ns_reset_clipping (struct frame *f)
1198 /* Internal: Restore the previous graphics state, unsetting any
1201 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_reset_clipping");
1203 [[NSGraphicsContext currentContext] restoreGraphicsState];
1207 /* ==========================================================================
1209 Visible bell and beep.
1211 ========================================================================== */
1214 // This bell implementation shows the visual bell image asynchronously
1215 // from the rest of Emacs. This is done by adding a NSView to the
1216 // superview of the Emacs window and removing it using a timer.
1218 // Unfortunately, some Emacs operations, like scrolling, is done using
1219 // low-level primitives that copy the content of the window, including
1220 // the bell image. To some extent, this is handled by removing the
1221 // image prior to scrolling and marking that the window is in need for
1224 // To test this code, make sure that there is no artifacts of the bell
1225 // image in the following situations. Use a non-empty buffer (like the
1226 // tutorial) to ensure that a scroll is performed:
1228 // * Single-window: C-g C-v
1230 // * Side-by-windows: C-x 3 C-g C-v
1232 // * Windows above each other: C-x 2 C-g C-v
1234 @interface EmacsBell : NSImageView
1236 // Number of currently active bell:s.
1237 unsigned int nestCount;
1241 - (void)show:(NSView *)view;
1246 @implementation EmacsBell
1250 NSTRACE ("[EmacsBell init]");
1251 if ((self = [super init]))
1255 #ifdef NS_IMPL_GNUSTEP
1256 // GNUstep doesn't provide named images. This was reported in
1257 // 2011, see https://savannah.gnu.org/bugs/?33396
1259 // As a drop in replacement, a semitransparent gray square is used.
1260 self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1261 [self.image lockFocus];
1262 [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1263 NSRectFill(NSMakeRect(0, 0, 32, 32));
1264 [self.image unlockFocus];
1266 self.image = [NSImage imageNamed:NSImageNameCaution];
1267 [self.image setSize:NSMakeSize(self.image.size.width * 5,
1268 self.image.size.height * 5)];
1274 - (void)show:(NSView *)view
1276 NSTRACE ("[EmacsBell show:]");
1277 NSTRACE_MSG ("nestCount: %u", nestCount);
1279 // Show the image, unless it's already shown.
1282 NSRect rect = [view bounds];
1284 pos.x = rect.origin.x + (rect.size.width - self.image.size.width )/2;
1285 pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1287 [self setFrameOrigin:pos];
1288 [self setFrameSize:self.image.size];
1292 [[[view window] contentView] addSubview:self
1293 positioned:NSWindowAbove
1299 [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1305 // Note: Trace output from this method isn't shown, reason unknown.
1306 // NSTRACE ("[EmacsBell hide]");
1311 // Remove the image once the last bell became inactive.
1321 NSTRACE ("[EmacsBell remove]");
1324 NSTRACE_MSG ("removeFromSuperview");
1325 [self removeFromSuperview];
1326 mView.needsDisplay = YES;
1334 static EmacsBell * bell_view = nil;
1337 ns_ring_bell (struct frame *f)
1338 /* --------------------------------------------------------------------------
1340 -------------------------------------------------------------------------- */
1342 NSTRACE ("ns_ring_bell");
1345 struct frame *frame = SELECTED_FRAME ();
1348 if (bell_view == nil)
1350 bell_view = [[EmacsBell alloc] init];
1356 view = FRAME_NS_VIEW (frame);
1359 [bell_view show:view];
1373 /* --------------------------------------------------------------------------
1374 Ensure the bell is hidden.
1375 -------------------------------------------------------------------------- */
1377 NSTRACE ("hide_bell");
1379 if (bell_view != nil)
1386 /* ==========================================================================
1388 Frame / window manager related functions
1390 ========================================================================== */
1394 ns_raise_frame (struct frame *f, BOOL make_key)
1395 /* --------------------------------------------------------------------------
1396 Bring window to foreground and if make_key is YES, give it focus.
1397 -------------------------------------------------------------------------- */
1401 check_window_system (f);
1402 view = FRAME_NS_VIEW (f);
1404 if (FRAME_VISIBLE_P (f))
1407 [[view window] makeKeyAndOrderFront: NSApp];
1409 [[view window] orderFront: NSApp];
1416 ns_lower_frame (struct frame *f)
1417 /* --------------------------------------------------------------------------
1419 -------------------------------------------------------------------------- */
1423 check_window_system (f);
1424 view = FRAME_NS_VIEW (f);
1426 [[view window] orderBack: NSApp];
1432 ns_frame_raise_lower (struct frame *f, bool raise)
1433 /* --------------------------------------------------------------------------
1435 -------------------------------------------------------------------------- */
1437 NSTRACE ("ns_frame_raise_lower");
1440 ns_raise_frame (f, YES);
1447 ns_frame_rehighlight (struct frame *frame)
1448 /* --------------------------------------------------------------------------
1449 External (hook): called on things like window switching within frame
1450 -------------------------------------------------------------------------- */
1452 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1453 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1455 NSTRACE ("ns_frame_rehighlight");
1456 if (dpyinfo->x_focus_frame)
1458 dpyinfo->x_highlight_frame
1459 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1460 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1461 : dpyinfo->x_focus_frame);
1462 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1464 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1465 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1469 dpyinfo->x_highlight_frame = 0;
1471 if (dpyinfo->x_highlight_frame &&
1472 dpyinfo->x_highlight_frame != old_highlight)
1476 x_update_cursor (old_highlight, 1);
1477 x_set_frame_alpha (old_highlight);
1479 if (dpyinfo->x_highlight_frame)
1481 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1482 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1489 x_make_frame_visible (struct frame *f)
1490 /* --------------------------------------------------------------------------
1491 External: Show the window (X11 semantics)
1492 -------------------------------------------------------------------------- */
1494 NSTRACE ("x_make_frame_visible");
1495 /* XXX: at some points in past this was not needed, as the only place that
1496 called this (frame.c:Fraise_frame ()) also called raise_lower;
1497 if this ends up the case again, comment this out again. */
1498 if (!FRAME_VISIBLE_P (f))
1500 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1501 NSWindow *window = [view window];
1503 SET_FRAME_VISIBLE (f, 1);
1504 ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f));
1506 /* Making a new frame from a fullscreen frame will make the new frame
1507 fullscreen also. So skip handleFS as this will print an error. */
1508 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1509 && [view isFullscreen])
1512 if (f->want_fullscreen != FULLSCREEN_NONE)
1519 /* Making a frame invisible seems to break the parent->child
1520 relationship, so reinstate it. */
1521 if ([window parentWindow] == nil && FRAME_PARENT_FRAME (f) != NULL)
1523 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1526 [parent addChildWindow: window
1527 ordered: NSWindowAbove];
1530 /* If the parent frame moved while the child frame was
1531 invisible, the child frame's position won't have been
1532 updated. Make sure it's in the right place now. */
1533 x_set_offset(f, f->left_pos, f->top_pos, 0);
1540 x_make_frame_invisible (struct frame *f)
1541 /* --------------------------------------------------------------------------
1542 External: Hide the window (X11 semantics)
1543 -------------------------------------------------------------------------- */
1546 NSTRACE ("x_make_frame_invisible");
1547 check_window_system (f);
1548 view = FRAME_NS_VIEW (f);
1549 [[view window] orderOut: NSApp];
1550 SET_FRAME_VISIBLE (f, 0);
1551 SET_FRAME_ICONIFIED (f, 0);
1556 x_iconify_frame (struct frame *f)
1557 /* --------------------------------------------------------------------------
1558 External: Iconify window
1559 -------------------------------------------------------------------------- */
1562 struct ns_display_info *dpyinfo;
1564 NSTRACE ("x_iconify_frame");
1565 check_window_system (f);
1566 view = FRAME_NS_VIEW (f);
1567 dpyinfo = FRAME_DISPLAY_INFO (f);
1569 if (dpyinfo->x_highlight_frame == f)
1570 dpyinfo->x_highlight_frame = 0;
1572 if ([[view window] windowNumber] <= 0)
1574 /* the window is still deferred. Make it very small, bring it
1575 on screen and order it out. */
1576 NSRect s = { { 100, 100}, {0, 0} };
1578 t = [[view window] frame];
1579 [[view window] setFrame: s display: NO];
1580 [[view window] orderBack: NSApp];
1581 [[view window] orderOut: NSApp];
1582 [[view window] setFrame: t display: NO];
1585 /* Processing input while Emacs is being minimized can cause a
1586 crash, so block it for the duration. */
1588 [[view window] miniaturize: NSApp];
1592 /* Free X resources of frame F. */
1595 x_free_frame_resources (struct frame *f)
1598 struct ns_display_info *dpyinfo;
1599 Mouse_HLInfo *hlinfo;
1601 NSTRACE ("x_free_frame_resources");
1602 check_window_system (f);
1603 view = FRAME_NS_VIEW (f);
1604 dpyinfo = FRAME_DISPLAY_INFO (f);
1605 hlinfo = MOUSE_HL_INFO (f);
1607 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1611 free_frame_menubar (f);
1612 free_frame_faces (f);
1614 if (f == dpyinfo->x_focus_frame)
1615 dpyinfo->x_focus_frame = 0;
1616 if (f == dpyinfo->x_highlight_frame)
1617 dpyinfo->x_highlight_frame = 0;
1618 if (f == hlinfo->mouse_face_mouse_frame)
1619 reset_mouse_highlight (hlinfo);
1620 /* Ensure that sendEvent does not attempt to dereference a freed
1621 frame. (bug#30800) */
1622 if (represented_frame == f)
1623 represented_frame = NULL;
1625 if (f->output_data.ns->miniimage != nil)
1626 [f->output_data.ns->miniimage release];
1628 [[view window] close];
1631 xfree (f->output_data.ns);
1637 x_destroy_window (struct frame *f)
1638 /* --------------------------------------------------------------------------
1639 External: Delete the window
1640 -------------------------------------------------------------------------- */
1642 NSTRACE ("x_destroy_window");
1644 /* If this frame has a parent window, detach it as not doing so can
1645 cause a crash in GNUStep. */
1646 if (FRAME_PARENT_FRAME (f) != NULL)
1648 NSWindow *child = [FRAME_NS_VIEW (f) window];
1649 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1651 [parent removeChildWindow: child];
1654 check_window_system (f);
1655 x_free_frame_resources (f);
1661 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1662 /* --------------------------------------------------------------------------
1663 External: Position the window
1664 -------------------------------------------------------------------------- */
1666 NSView *view = FRAME_NS_VIEW (f);
1667 NSArray *screens = [NSScreen screens];
1668 NSScreen *screen = [[view window] screen];
1670 NSTRACE ("x_set_offset");
1679 if (FRAME_PARENT_FRAME (f) == NULL && screen)
1681 f->left_pos = f->size_hint_flags & XNegative
1682 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1684 /* We use visibleFrame here to take menu bar into account.
1685 Ideally we should also adjust left/top with visibleFrame.origin. */
1687 f->top_pos = f->size_hint_flags & YNegative
1688 ? ([screen visibleFrame].size.height + f->top_pos
1689 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1690 - FRAME_TOOLBAR_HEIGHT (f))
1692 #ifdef NS_IMPL_GNUSTEP
1693 if (f->left_pos < 100)
1694 f->left_pos = 100; /* don't overlap menu */
1697 else if (FRAME_PARENT_FRAME (f) != NULL)
1699 struct frame *parent = FRAME_PARENT_FRAME (f);
1701 /* On X negative values for child frames always result in
1702 positioning relative to the bottom right corner of the
1704 if (f->left_pos < 0)
1705 f->left_pos = FRAME_PIXEL_WIDTH (parent) - FRAME_PIXEL_WIDTH (f) + f->left_pos;
1708 f->top_pos = FRAME_PIXEL_HEIGHT (parent) + FRAME_TOOLBAR_HEIGHT (parent)
1709 - FRAME_PIXEL_HEIGHT (f) + f->top_pos;
1712 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1714 NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
1715 + NS_PARENT_WINDOW_LEFT_POS (f)),
1716 SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
1718 NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1719 [[view window] setFrameTopLeftPoint: pt];
1720 f->size_hint_flags &= ~(XNegative|YNegative);
1728 x_set_window_size (struct frame *f,
1729 bool change_gravity,
1733 /* --------------------------------------------------------------------------
1734 Adjust window pixel size based on given character grid size
1735 Impl is a bit more complex than other terms, need to do some
1737 -------------------------------------------------------------------------- */
1739 EmacsView *view = FRAME_NS_VIEW (f);
1740 NSWindow *window = [view window];
1741 NSRect wr = [window frame];
1742 int pixelwidth, pixelheight;
1743 int orig_height = wr.size.height;
1745 NSTRACE ("x_set_window_size");
1750 NSTRACE_RECT ("current", wr);
1751 NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1752 NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1758 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1759 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1763 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1764 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1767 wr.size.width = pixelwidth + f->border_width;
1768 wr.size.height = pixelheight;
1769 if (! [view isFullscreen])
1770 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1771 + FRAME_TOOLBAR_HEIGHT (f);
1773 /* Do not try to constrain to this screen. We may have multiple
1774 screens, and want Emacs to span those. Constraining to screen
1775 prevents that, and that is not nice to the user. */
1776 if (f->output_data.ns->zooming)
1777 f->output_data.ns->zooming = 0;
1779 wr.origin.y += orig_height - wr.size.height;
1781 frame_size_history_add
1782 (f, Qx_set_window_size_1, width, height,
1783 list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1784 Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1785 make_number (f->border_width),
1786 make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1787 make_number (FRAME_TOOLBAR_HEIGHT (f))));
1789 [window setFrame: wr display: YES];
1791 [view updateFrameSize: NO];
1795 #ifdef NS_IMPL_COCOA
1797 x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1798 /* --------------------------------------------------------------------------
1799 Set frame F's `undecorated' parameter. If non-nil, F's window-system
1800 window is drawn without decorations, title, minimize/maximize boxes
1801 and external borders. This usually means that the window cannot be
1802 dragged, resized, iconified, maximized or deleted with the mouse. If
1803 nil, draw the frame with all the elements listed above unless these
1804 have been suspended via window manager settings.
1806 GNUStep cannot change an existing window's style.
1807 -------------------------------------------------------------------------- */
1809 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1810 NSWindow *window = [view window];
1812 NSTRACE ("x_set_undecorated");
1814 if (!EQ (new_value, old_value))
1818 if (NILP (new_value))
1820 FRAME_UNDECORATED (f) = false;
1821 [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
1822 ^ FRAME_UNDECORATED_FLAGS)];
1824 [view createToolbar: f];
1828 [window setToolbar: nil];
1829 /* Do I need to release the toolbar here? */
1831 FRAME_UNDECORATED (f) = true;
1832 [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS)
1833 ^ FRAME_DECORATED_FLAGS)];
1836 /* At this point it seems we don't have an active NSResponder,
1837 so some key presses (TAB) are swallowed by the system. */
1838 [window makeFirstResponder: view];
1840 [view updateFrameSize: NO];
1844 #endif /* NS_IMPL_COCOA */
1847 x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1848 /* --------------------------------------------------------------------------
1849 Set frame F's `parent-frame' parameter. If non-nil, make F a child
1850 frame of the frame specified by that parameter. Technically, this
1851 makes F's window-system window a child window of the parent frame's
1852 window-system window. If nil, make F's window-system window a
1853 top-level window--a child of its display's root window.
1855 A child frame's `left' and `top' parameters specify positions
1856 relative to the top-left corner of its parent frame's native
1857 rectangle. On macOS moving a parent frame moves all its child
1858 frames too, keeping their position relative to the parent
1859 unaltered. When a parent frame is iconified or made invisible, its
1860 child frames are made invisible. When a parent frame is deleted,
1861 its child frames are deleted too.
1863 Whether a child frame has a tool bar may be window-system or window
1864 manager dependent. It's advisable to disable it via the frame
1867 Some window managers may not honor this parameter.
1868 -------------------------------------------------------------------------- */
1870 struct frame *p = NULL;
1871 NSWindow *parent, *child;
1873 NSTRACE ("x_set_parent_frame");
1875 if (!NILP (new_value)
1876 && (!FRAMEP (new_value)
1877 || !FRAME_LIVE_P (p = XFRAME (new_value))
1878 || !FRAME_NS_P (p)))
1880 store_frame_param (f, Qparent_frame, old_value);
1881 error ("Invalid specification of `parent-frame'");
1884 if (p != FRAME_PARENT_FRAME (f))
1887 child = [FRAME_NS_VIEW (f) window];
1889 if ([child parentWindow] != nil)
1891 [[child parentWindow] removeChildWindow:child];
1892 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
1893 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
1894 if ([child respondsToSelector:@selector(setAccessibilitySubrole:)])
1896 [child setAccessibilitySubrole:NSAccessibilityStandardWindowSubrole];
1900 if (!NILP (new_value))
1902 parent = [FRAME_NS_VIEW (p) window];
1904 [parent addChildWindow: child
1905 ordered: NSWindowAbove];
1906 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
1907 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
1908 if ([child respondsToSelector:@selector(setAccessibilitySubrole:)])
1910 [child setAccessibilitySubrole:NSAccessibilityFloatingWindowSubrole];
1916 fset_parent_frame (f, new_value);
1921 x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1922 /* Set frame F's `no-focus-on-map' parameter which, if non-nil, means
1923 * that F's window-system window does not want to receive input focus
1924 * when it is mapped. (A frame's window is mapped when the frame is
1925 * displayed for the first time and when the frame changes its state
1926 * from `iconified' or `invisible' to `visible'.)
1928 * Some window managers may not honor this parameter. */
1930 NSTRACE ("x_set_no_focus_on_map");
1932 if (!EQ (new_value, old_value))
1934 FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
1939 x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1940 /* Set frame F's `no-accept-focus' parameter which, if non-nil, hints
1941 * that F's window-system window does not want to receive input focus
1942 * via mouse clicks or by moving the mouse into it.
1944 * If non-nil, this may have the unwanted side-effect that a user cannot
1945 * scroll a non-selected frame with the mouse.
1947 * Some window managers may not honor this parameter. */
1949 NSTRACE ("x_set_no_accept_focus");
1951 if (!EQ (new_value, old_value))
1952 FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
1956 x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1957 /* Set frame F's `z-group' parameter. If `above', F's window-system
1958 window is displayed above all windows that do not have the `above'
1959 property set. If nil, F's window is shown below all windows that
1960 have the `above' property set and above all windows that have the
1961 `below' property set. If `below', F's window is displayed below
1962 all windows that do.
1964 Some window managers may not honor this parameter. */
1966 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1967 NSWindow *window = [view window];
1969 NSTRACE ("x_set_z_group");
1971 if (NILP (new_value))
1973 window.level = NSNormalWindowLevel;
1974 FRAME_Z_GROUP (f) = z_group_none;
1976 else if (EQ (new_value, Qabove))
1978 window.level = NSNormalWindowLevel + 1;
1979 FRAME_Z_GROUP (f) = z_group_above;
1981 else if (EQ (new_value, Qabove_suspended))
1983 /* Not sure what level this should be. */
1984 window.level = NSNormalWindowLevel + 1;
1985 FRAME_Z_GROUP (f) = z_group_above_suspended;
1987 else if (EQ (new_value, Qbelow))
1989 window.level = NSNormalWindowLevel - 1;
1990 FRAME_Z_GROUP (f) = z_group_below;
1993 error ("Invalid z-group specification");
1996 #ifdef NS_IMPL_COCOA
1998 ns_set_appearance (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2000 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
2001 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2002 NSWindow *window = [view window];
2004 NSTRACE ("ns_set_appearance");
2006 #ifndef NSAppKitVersionNumber10_10
2007 #define NSAppKitVersionNumber10_10 1343
2010 if (NSAppKitVersionNumber < NSAppKitVersionNumber10_10)
2013 if (EQ (new_value, Qdark))
2015 window.appearance = [NSAppearance
2016 appearanceNamed: NSAppearanceNameVibrantDark];
2017 FRAME_NS_APPEARANCE (f) = ns_appearance_vibrant_dark;
2021 window.appearance = [NSAppearance
2022 appearanceNamed: NSAppearanceNameAqua];
2023 FRAME_NS_APPEARANCE (f) = ns_appearance_aqua;
2025 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
2029 ns_set_transparent_titlebar (struct frame *f, Lisp_Object new_value,
2030 Lisp_Object old_value)
2032 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
2033 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2034 NSWindow *window = [view window];
2036 NSTRACE ("ns_set_transparent_titlebar");
2038 if ([window respondsToSelector: @selector(titlebarAppearsTransparent)]
2039 && !EQ (new_value, old_value))
2041 window.titlebarAppearsTransparent = !NILP (new_value);
2042 FRAME_NS_TRANSPARENT_TITLEBAR (f) = !NILP (new_value);
2044 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
2046 #endif /* NS_IMPL_COCOA */
2049 ns_fullscreen_hook (struct frame *f)
2051 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2053 NSTRACE ("ns_fullscreen_hook");
2055 if (!FRAME_VISIBLE_P (f))
2058 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
2060 /* Old style fs don't initiate correctly if created from
2061 init/default-frame alist, so use a timer (not nice...).
2063 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
2064 selector: @selector (handleFS)
2065 userInfo: nil repeats: NO];
2074 /* ==========================================================================
2078 ========================================================================== */
2082 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
2084 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2085 if (idx < 1 || idx >= color_table->avail)
2087 return color_table->colors[idx];
2092 ns_index_color (NSColor *color, struct frame *f)
2094 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2098 if (!color_table->colors)
2100 color_table->size = NS_COLOR_CAPACITY;
2101 color_table->avail = 1; /* skip idx=0 as marker */
2102 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
2103 color_table->colors[0] = nil;
2104 color_table->empty_indices = [[NSMutableSet alloc] init];
2107 /* Do we already have this color? */
2108 for (i = 1; i < color_table->avail; i++)
2109 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
2112 if ([color_table->empty_indices count] > 0)
2114 NSNumber *index = [color_table->empty_indices anyObject];
2115 [color_table->empty_indices removeObject: index];
2116 idx = [index unsignedLongValue];
2120 if (color_table->avail == color_table->size)
2121 color_table->colors =
2122 xpalloc (color_table->colors, &color_table->size, 1,
2123 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
2124 idx = color_table->avail++;
2127 color_table->colors[idx] = color;
2129 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
2135 ns_get_color (const char *name, NSColor **col)
2136 /* --------------------------------------------------------------------------
2138 -------------------------------------------------------------------------- */
2139 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
2140 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
2141 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
2144 static char hex[20];
2146 float r = -1.0, g, b;
2147 NSString *nsname = [NSString stringWithUTF8String: name];
2149 NSTRACE ("ns_get_color(%s, **)", name);
2153 if ([nsname isEqualToString: @"ns_selection_bg_color"])
2155 #ifdef NS_IMPL_COCOA
2156 NSString *defname = [[NSUserDefaults standardUserDefaults]
2157 stringForKey: @"AppleHighlightColor"];
2162 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
2164 *col = [new colorUsingDefaultColorSpace];
2169 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
2171 name = [nsname UTF8String];
2173 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
2175 /* NOTE: macOS applications normally don't set foreground
2176 selection, but text may be unreadable if we don't.
2178 if ((new = [NSColor selectedTextColor]) != nil)
2180 *col = [new colorUsingDefaultColorSpace];
2185 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
2186 name = [nsname UTF8String];
2189 /* First, check for some sort of numeric specification. */
2192 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
2194 NSScanner *scanner = [NSScanner scannerWithString: nsname];
2195 [scanner scanFloat: &r];
2196 [scanner scanFloat: &g];
2197 [scanner scanFloat: &b];
2199 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
2200 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2201 else if (name[0] == '#') /* An old X11 format; convert to newer */
2203 int len = (strlen(name) - 1);
2204 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2206 scaling = strlen(name+start) / 3;
2207 for (i = 0; i < 3; i++)
2208 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2209 name + start + i * scaling);
2210 hex[3 * (scaling + 1) - 1] = '\0';
2215 unsigned int rr, gg, bb;
2216 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2217 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2227 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2232 /* Otherwise, color is expected to be from a list */
2234 NSEnumerator *lenum, *cenum;
2238 #ifdef NS_IMPL_GNUSTEP
2239 /* XXX: who is wrong, the requestor or the implementation? */
2240 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2242 nsname = @"highlightColor";
2245 lenum = [[NSColorList availableColorLists] objectEnumerator];
2246 while ( (clist = [lenum nextObject]) && new == nil)
2248 cenum = [[clist allKeys] objectEnumerator];
2249 while ( (name = [cenum nextObject]) && new == nil )
2251 if ([name compare: nsname
2252 options: NSCaseInsensitiveSearch] == NSOrderedSame )
2253 new = [clist colorWithKey: name];
2259 *col = [new colorUsingDefaultColorSpace];
2266 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2267 /* --------------------------------------------------------------------------
2268 Convert a Lisp string object to a NS color
2269 -------------------------------------------------------------------------- */
2271 NSTRACE ("ns_lisp_to_color");
2272 if (STRINGP (color))
2273 return ns_get_color (SSDATA (color), col);
2274 else if (SYMBOLP (color))
2275 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2281 ns_query_color(void *col, XColor *color_def, int setPixel)
2282 /* --------------------------------------------------------------------------
2283 Get ARGB values out of NSColor col and put them into color_def.
2284 If setPixel, set the pixel to a concatenated version.
2285 and set color_def pixel to the resulting index.
2286 -------------------------------------------------------------------------- */
2288 EmacsCGFloat r, g, b, a;
2290 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2291 color_def->red = r * 65535;
2292 color_def->green = g * 65535;
2293 color_def->blue = b * 65535;
2295 if (setPixel == YES)
2297 = ARGB_TO_ULONG((int)(a*255),
2298 (int)(r*255), (int)(g*255), (int)(b*255));
2303 ns_defined_color (struct frame *f,
2308 /* --------------------------------------------------------------------------
2309 Return true if named color found, and set color_def rgb accordingly.
2310 If makeIndex and alloc are nonzero put the color in the color_table,
2311 and set color_def pixel to the resulting index.
2312 If makeIndex is zero, set color_def pixel to ARGB.
2313 Return false if not found
2314 -------------------------------------------------------------------------- */
2317 NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2320 if (ns_get_color (name, &col) != 0) /* Color not found */
2325 if (makeIndex && alloc)
2326 color_def->pixel = ns_index_color (col, f);
2327 ns_query_color (col, color_def, !makeIndex);
2334 x_set_frame_alpha (struct frame *f)
2335 /* --------------------------------------------------------------------------
2336 change the entire-frame transparency
2337 -------------------------------------------------------------------------- */
2339 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2341 double alpha_min = 1.0;
2343 NSTRACE ("x_set_frame_alpha");
2345 if (dpyinfo->x_highlight_frame == f)
2346 alpha = f->alpha[0];
2348 alpha = f->alpha[1];
2350 if (FLOATP (Vframe_alpha_lower_limit))
2351 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2352 else if (INTEGERP (Vframe_alpha_lower_limit))
2353 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2357 else if (1.0 < alpha)
2359 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2362 #ifdef NS_IMPL_COCOA
2364 EmacsView *view = FRAME_NS_VIEW (f);
2365 [[view window] setAlphaValue: alpha];
2371 /* ==========================================================================
2375 ========================================================================== */
2379 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2380 /* --------------------------------------------------------------------------
2381 Programmatically reposition mouse pointer in pixel coordinates
2382 -------------------------------------------------------------------------- */
2384 NSTRACE ("frame_set_mouse_pixel_position");
2386 /* FIXME: what about GNUstep? */
2387 #ifdef NS_IMPL_COCOA
2389 CGPointMake(f->left_pos + pix_x,
2390 f->top_pos + pix_y +
2391 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
2392 CGWarpMouseCursorPosition (mouse_pos);
2397 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2398 /* ------------------------------------------------------------------------
2399 Called by EmacsView on mouseMovement events. Passes on
2400 to emacs mainstream code if we moved off of a rect of interest
2401 known as last_mouse_glyph.
2402 ------------------------------------------------------------------------ */
2404 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2407 // NSTRACE ("note_mouse_movement");
2409 dpyinfo->last_mouse_motion_frame = frame;
2410 r = &dpyinfo->last_mouse_glyph;
2412 /* Note, this doesn't get called for enter/leave, since we don't have a
2413 position. Those are taken care of in the corresponding NSView methods. */
2415 /* has movement gone beyond last rect we were tracking? */
2416 if (x < r->origin.x || x >= r->origin.x + r->size.width
2417 || y < r->origin.y || y >= r->origin.y + r->size.height)
2419 ns_update_begin (frame);
2420 frame->mouse_moved = 1;
2421 note_mouse_highlight (frame, x, y);
2422 remember_mouse_glyph (frame, x, y, r);
2423 ns_update_end (frame);
2432 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2433 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2435 /* --------------------------------------------------------------------------
2436 External (hook): inform emacs about mouse position and hit parts.
2437 If a scrollbar is being dragged, set bar_window, part, x, y, time.
2438 x & y should be position in the scrollbar (the whole bar, not the handle)
2439 and length of scrollbar respectively
2440 -------------------------------------------------------------------------- */
2444 Lisp_Object frame, tail;
2446 struct ns_display_info *dpyinfo;
2448 NSTRACE ("ns_mouse_position");
2452 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2456 dpyinfo = FRAME_DISPLAY_INFO (*fp);
2460 /* Clear the mouse-moved flag for every frame on this display. */
2461 FOR_EACH_FRAME (tail, frame)
2462 if (FRAME_NS_P (XFRAME (frame))
2463 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2464 XFRAME (frame)->mouse_moved = 0;
2466 dpyinfo->last_mouse_scroll_bar = nil;
2467 if (dpyinfo->last_mouse_frame
2468 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2469 f = dpyinfo->last_mouse_frame;
2471 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2473 if (f && FRAME_NS_P (f))
2475 view = FRAME_NS_VIEW (f);
2477 position = [[view window] mouseLocationOutsideOfEventStream];
2478 position = [view convertPoint: position fromView: nil];
2479 remember_mouse_glyph (f, position.x, position.y,
2480 &dpyinfo->last_mouse_glyph);
2481 NSTRACE_POINT ("position", position);
2483 if (bar_window) *bar_window = Qnil;
2484 if (part) *part = scroll_bar_above_handle;
2486 if (x) XSETINT (*x, lrint (position.x));
2487 if (y) XSETINT (*y, lrint (position.y));
2489 *time = dpyinfo->last_mouse_movement_time;
2498 ns_frame_up_to_date (struct frame *f)
2499 /* --------------------------------------------------------------------------
2500 External (hook): Fix up mouse highlighting right after a full update.
2501 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2502 -------------------------------------------------------------------------- */
2504 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2508 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2509 if (f == hlinfo->mouse_face_mouse_frame)
2513 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2514 hlinfo->mouse_face_mouse_x,
2515 hlinfo->mouse_face_mouse_y);
2524 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2525 /* --------------------------------------------------------------------------
2526 External (RIF): set frame mouse pointer type.
2527 -------------------------------------------------------------------------- */
2529 NSTRACE ("ns_define_frame_cursor");
2530 if (FRAME_POINTER_TYPE (f) != cursor)
2532 EmacsView *view = FRAME_NS_VIEW (f);
2533 FRAME_POINTER_TYPE (f) = cursor;
2534 [[view window] invalidateCursorRectsForView: view];
2535 /* Redisplay assumes this function also draws the changed frame
2536 cursor, but this function doesn't, so do it explicitly. */
2537 x_update_cursor (f, 1);
2543 /* ==========================================================================
2547 ========================================================================== */
2551 ns_convert_key (unsigned code)
2552 /* --------------------------------------------------------------------------
2553 Internal call used by NSView-keyDown.
2554 -------------------------------------------------------------------------- */
2556 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2558 /* An array would be faster, but less easy to read. */
2559 for (keysym = 0; keysym < last_keysym; keysym += 2)
2560 if (code == convert_ns_to_X_keysym[keysym])
2561 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2563 /* if decide to use keyCode and Carbon table, use this line:
2564 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2569 x_get_keysym_name (int keysym)
2570 /* --------------------------------------------------------------------------
2571 Called by keyboard.c. Not sure if the return val is important, except
2573 -------------------------------------------------------------------------- */
2575 static char value[16];
2576 NSTRACE ("x_get_keysym_name");
2577 sprintf (value, "%d", keysym);
2583 /* ==========================================================================
2585 Block drawing operations
2587 ========================================================================== */
2591 ns_redraw_scroll_bars (struct frame *f)
2595 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2596 NSTRACE ("ns_redraw_scroll_bars");
2597 for (i =[subviews count]-1; i >= 0; i--)
2599 view = [subviews objectAtIndex: i];
2600 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2607 ns_clear_frame (struct frame *f)
2608 /* --------------------------------------------------------------------------
2609 External (hook): Erase the entire frame
2610 -------------------------------------------------------------------------- */
2612 NSView *view = FRAME_NS_VIEW (f);
2615 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2617 /* comes on initial frame because we have
2618 after-make-frame-functions = select-frame */
2619 if (!FRAME_DEFAULT_FACE (f))
2622 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2627 if (ns_clip_to_rect (f, &r, 1))
2629 [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2630 (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
2632 ns_reset_clipping (f);
2634 /* as of 2006/11 or so this is now needed */
2635 ns_redraw_scroll_bars (f);
2642 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2643 /* --------------------------------------------------------------------------
2644 External (RIF): Clear section of frame
2645 -------------------------------------------------------------------------- */
2647 NSRect r = NSMakeRect (x, y, width, height);
2648 NSView *view = FRAME_NS_VIEW (f);
2649 struct face *face = FRAME_DEFAULT_FACE (f);
2654 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2656 r = NSIntersectionRect (r, [view frame]);
2657 if (ns_clip_to_rect (f, &r, 1))
2659 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2663 ns_reset_clipping (f);
2668 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2670 NSSize delta = NSMakeSize (dest.origin.x - src.origin.x,
2671 dest.origin.y - src.origin.y);
2672 NSTRACE ("ns_copy_bits");
2674 if (FRAME_NS_VIEW (f))
2676 hide_bell(); // Ensure the bell image isn't scrolled.
2678 /* FIXME: scrollRect:by: is deprecated in macOS 10.14. There is
2679 no obvious replacement so we may have to come up with our own. */
2680 [FRAME_NS_VIEW (f) scrollRect: src by: delta];
2682 #ifdef NS_IMPL_COCOA
2683 /* As far as I can tell from the documentation, scrollRect:by:,
2684 above, should copy the dirty rectangles from our source
2685 rectangle to our destination, however it appears it clips the
2686 operation to src. As a result we need to use
2687 translateRectsNeedingDisplayInRect:by: below, and we have to
2688 union src and dest so it can pick up the dirty rectangles,
2689 and place them, as it also clips to the rectangle.
2691 FIXME: We need a GNUstep equivalent. */
2692 [FRAME_NS_VIEW (f) translateRectsNeedingDisplayInRect:NSUnionRect (src, dest)
2699 ns_scroll_run (struct window *w, struct run *run)
2700 /* --------------------------------------------------------------------------
2701 External (RIF): Insert or delete n lines at line vpos
2702 -------------------------------------------------------------------------- */
2704 struct frame *f = XFRAME (w->frame);
2705 int x, y, width, height, from_y, to_y, bottom_y;
2707 NSTRACE ("ns_scroll_run");
2709 /* begin copy from other terms */
2710 /* Get frame-relative bounding box of the text display area of W,
2711 without mode lines. Include in this box the left and right
2713 window_box (w, ANY_AREA, &x, &y, &width, &height);
2715 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2716 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2717 bottom_y = y + height;
2721 /* Scrolling up. Make sure we don't copy part of the mode
2722 line at the bottom. */
2723 if (from_y + run->height > bottom_y)
2724 height = bottom_y - from_y;
2726 height = run->height;
2730 /* Scrolling down. Make sure we don't copy over the mode line.
2732 if (to_y + run->height > bottom_y)
2733 height = bottom_y - to_y;
2735 height = run->height;
2737 /* end copy from other terms */
2747 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2748 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2750 ns_copy_bits (f, srcRect , dstRect);
2758 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2759 /* --------------------------------------------------------------------------
2760 External (RIF): preparatory to fringe update after text was updated
2761 -------------------------------------------------------------------------- */
2766 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2768 /* begin copy from other terms */
2771 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2772 desired_row->redraw_fringe_bitmaps_p = 1;
2774 /* When a window has disappeared, make sure that no rest of
2775 full-width rows stays visible in the internal border. */
2776 if (windows_or_buffers_changed
2777 && desired_row->full_width_p
2778 && (f = XFRAME (w->frame),
2779 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2781 && (height = desired_row->visible_height,
2784 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2787 ns_clear_frame_area (f, 0, y, width, height);
2788 ns_clear_frame_area (f,
2789 FRAME_PIXEL_WIDTH (f) - width,
2797 ns_shift_glyphs_for_insert (struct frame *f,
2798 int x, int y, int width, int height,
2800 /* --------------------------------------------------------------------------
2801 External (RIF): copy an area horizontally, don't worry about clearing src
2802 -------------------------------------------------------------------------- */
2804 //NSRect srcRect = NSMakeRect (x, y, width, height);
2805 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2807 NSTRACE ("ns_shift_glyphs_for_insert");
2809 /* This doesn't work now as we copy the "bits" before we've had a
2810 chance to actually draw any changes to the screen. This means in
2811 certain circumstances we end up with copies of the cursor all
2812 over the place. Just mark the area dirty so it is redrawn later.
2814 FIXME: Work out how to do this properly. */
2815 // ns_copy_bits (f, srcRect, dstRect);
2817 [FRAME_NS_VIEW (f) setNeedsDisplayInRect:dstRect];
2822 /* ==========================================================================
2824 Character encoding and metrics
2826 ========================================================================== */
2830 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2831 /* --------------------------------------------------------------------------
2832 External (RIF); compute left/right overhang of whole string and set in s
2833 -------------------------------------------------------------------------- */
2835 struct font *font = s->font;
2839 struct font_metrics metrics;
2840 unsigned int codes[2];
2841 codes[0] = *(s->char2b);
2842 codes[1] = *(s->char2b + s->nchars - 1);
2844 font->driver->text_extents (font, codes, 2, &metrics);
2845 s->left_overhang = -metrics.lbearing;
2847 = metrics.rbearing > metrics.width
2848 ? metrics.rbearing - metrics.width : 0;
2852 s->left_overhang = 0;
2853 if (EQ (font->driver->type, Qns))
2854 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2855 FONT_HEIGHT (font) * 0.2 : 0;
2857 s->right_overhang = 0;
2863 /* ==========================================================================
2865 Fringe and cursor drawing
2867 ========================================================================== */
2870 extern int max_used_fringe_bitmap;
2872 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2873 struct draw_fringe_bitmap_params *p)
2874 /* --------------------------------------------------------------------------
2875 External (RIF); fringe-related
2876 -------------------------------------------------------------------------- */
2878 /* Fringe bitmaps comes in two variants, normal and periodic. A
2879 periodic bitmap is used to create a continuous pattern. Since a
2880 bitmap is rendered one text line at a time, the start offset (dh)
2881 of the bitmap varies. Concretely, this is used for the empty
2884 For a bitmap, "h + dh" is the full height and is always
2885 invariant. For a normal bitmap "dh" is zero.
2887 For example, when the period is three and the full height is 72
2888 the following combinations exists:
2894 struct frame *f = XFRAME (WINDOW_FRAME (w));
2895 struct face *face = p->face;
2896 static EmacsImage **bimgs = NULL;
2897 static int nBimgs = 0;
2898 NSRect clearRect = NSZeroRect;
2899 NSRect imageRect = NSZeroRect;
2900 NSRect rowRect = ns_row_rect (w, row, ANY_AREA);
2902 NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2903 NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2904 p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2906 /* grow bimgs if needed */
2907 if (nBimgs < max_used_fringe_bitmap)
2909 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2910 memset (bimgs + nBimgs, 0,
2911 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2912 nBimgs = max_used_fringe_bitmap;
2915 /* Work out the rectangle we will composite into. */
2917 imageRect = NSMakeRect (p->x, p->y, p->wd, p->h);
2919 /* Work out the rectangle we will need to clear. Because we're
2920 compositing rather than blitting, we need to clear the area under
2921 the image regardless of anything else. */
2922 if (p->bx >= 0 && !p->overlay_p)
2924 clearRect = NSMakeRect (p->bx, p->by, p->nx, p->ny);
2925 clearRect = NSUnionRect (clearRect, imageRect);
2929 clearRect = imageRect;
2932 /* Handle partially visible rows. */
2933 clearRect = NSIntersectionRect (clearRect, rowRect);
2935 /* The visible portion of imageRect will always be contained within
2937 if (ns_clip_to_rect (f, &clearRect, 1))
2939 if (! NSIsEmptyRect (clearRect))
2941 NSTRACE_RECT ("clearRect", clearRect);
2943 [ns_lookup_indexed_color(face->background, f) set];
2944 NSRectFill (clearRect);
2949 EmacsImage *img = bimgs[p->which - 1];
2953 // Note: For "periodic" images, allocate one EmacsImage for
2954 // the base image, and use it for all dh:s.
2955 unsigned short *bits = p->bits;
2956 int full_height = p->h + p->dh;
2958 unsigned char *cbits = xmalloc (full_height);
2960 for (i = 0; i < full_height; i++)
2962 img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2965 bimgs[p->which - 1] = img;
2973 bm_color = ns_lookup_indexed_color(face->foreground, f);
2974 else if (p->overlay_p)
2975 bm_color = ns_lookup_indexed_color(face->background, f);
2977 bm_color = f->output_data.ns->cursor_color;
2978 [img setXBMColor: bm_color];
2981 #ifdef NS_IMPL_COCOA
2982 // Note: For periodic images, the full image height is "h + hd".
2983 // By using the height h, a suitable part of the image is used.
2984 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2986 NSTRACE_RECT ("fromRect", fromRect);
2988 [img drawInRect: imageRect
2990 operation: NSCompositingOperationSourceOver
2996 NSPoint pt = imageRect.origin;
2998 [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
3002 ns_reset_clipping (f);
3008 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3009 int x, int y, enum text_cursor_kinds cursor_type,
3010 int cursor_width, bool on_p, bool active_p)
3011 /* --------------------------------------------------------------------------
3012 External call (RIF): draw cursor.
3013 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
3014 -------------------------------------------------------------------------- */
3017 int fx, fy, h, cursor_height;
3018 struct frame *f = WINDOW_XFRAME (w);
3019 struct glyph *phys_cursor_glyph;
3020 struct glyph *cursor_glyph;
3022 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
3024 /* If cursor is out of bounds, don't draw garbage. This can happen
3025 in mini-buffer windows when switching between echo area glyphs
3028 NSTRACE ("ns_draw_window_cursor");
3033 w->phys_cursor_type = cursor_type;
3034 w->phys_cursor_on_p = on_p;
3036 if (cursor_type == NO_CURSOR)
3038 w->phys_cursor_width = 0;
3042 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
3044 if (glyph_row->exact_window_width_line_p
3045 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
3047 glyph_row->cursor_in_fringe_p = 1;
3048 draw_fringe_bitmap (w, glyph_row, 0);
3053 /* We draw the cursor (with NSRectFill), then draw the glyph on top
3054 (other terminals do it the other way round). We must set
3055 w->phys_cursor_width to the cursor width. For bar cursors, that
3056 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
3057 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
3059 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
3060 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
3061 if (cursor_type == BAR_CURSOR)
3063 if (cursor_width < 1)
3064 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
3066 /* The bar cursor should never be wider than the glyph. */
3067 if (cursor_width < w->phys_cursor_width)
3068 w->phys_cursor_width = cursor_width;
3070 /* If we have an HBAR, "cursor_width" MAY specify height. */
3071 else if (cursor_type == HBAR_CURSOR)
3073 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
3074 if (cursor_height > glyph_row->height)
3075 cursor_height = glyph_row->height;
3076 if (h > cursor_height) // Cursor smaller than line height, move down
3077 fy += h - cursor_height;
3081 r.origin.x = fx, r.origin.y = fy;
3083 r.size.width = w->phys_cursor_width;
3085 /* Prevent the cursor from being drawn outside the text area. */
3086 r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA));
3088 if (ns_clip_to_rect (f, &r, 1))
3090 face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
3091 if (face && NS_FACE_BACKGROUND (face)
3092 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
3094 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
3095 hollow_color = FRAME_CURSOR_COLOR (f);
3098 [FRAME_CURSOR_COLOR (f) set];
3100 switch (cursor_type)
3102 case DEFAULT_CURSOR:
3105 case FILLED_BOX_CURSOR:
3108 case HOLLOW_BOX_CURSOR:
3111 NSRectFill (NSInsetRect (r, 1, 1));
3112 [FRAME_CURSOR_COLOR (f) set];
3119 /* If the character under cursor is R2L, draw the bar cursor
3120 on the right of its glyph, rather than on the left. */
3121 cursor_glyph = get_phys_cursor_glyph (w);
3122 if ((cursor_glyph->resolved_level & 1) != 0)
3123 s.origin.x += cursor_glyph->pixel_width - s.size.width;
3129 /* draw the character under the cursor */
3130 if (cursor_type != NO_CURSOR)
3131 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3133 ns_reset_clipping (f);
3135 else if (! redisplaying_p)
3137 /* If this function is called outside redisplay, it probably
3138 means we need an immediate update. */
3139 [FRAME_NS_VIEW (f) display];
3145 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
3146 /* --------------------------------------------------------------------------
3147 External (RIF): Draw a vertical line.
3148 -------------------------------------------------------------------------- */
3150 struct frame *f = XFRAME (WINDOW_FRAME (w));
3152 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
3154 NSTRACE ("ns_draw_vertical_window_border");
3156 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
3158 if (ns_clip_to_rect (f, &r, 1))
3161 [ns_lookup_indexed_color(face->foreground, f) set];
3164 ns_reset_clipping (f);
3170 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3171 /* --------------------------------------------------------------------------
3172 External (RIF): Draw a window divider.
3173 -------------------------------------------------------------------------- */
3175 struct frame *f = XFRAME (WINDOW_FRAME (w));
3176 struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
3177 struct face *face_first
3178 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID);
3179 struct face *face_last
3180 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID);
3181 unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f);
3182 unsigned long color_first = (face_first
3183 ? face_first->foreground
3184 : FRAME_FOREGROUND_PIXEL (f));
3185 unsigned long color_last = (face_last
3186 ? face_last->foreground
3187 : FRAME_FOREGROUND_PIXEL (f));
3188 NSRect divider = NSMakeRect (x0, y0, x1-x0, y1-y0);
3190 NSTRACE ("ns_draw_window_divider");
3192 if (ns_clip_to_rect (f, ÷r, 1))
3194 if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3))
3195 /* A vertical divider, at least three pixels wide: Draw first and
3196 last pixels differently. */
3198 [ns_lookup_indexed_color(color_first, f) set];
3199 NSRectFill(NSMakeRect (x0, y0, 1, y1 - y0));
3200 [ns_lookup_indexed_color(color, f) set];
3201 NSRectFill(NSMakeRect (x0 + 1, y0, x1 - x0 - 2, y1 - y0));
3202 [ns_lookup_indexed_color(color_last, f) set];
3203 NSRectFill(NSMakeRect (x1 - 1, y0, 1, y1 - y0));
3205 else if ((x1 - x0 > y1 - y0) && (y1 - y0 >= 3))
3206 /* A horizontal divider, at least three pixels high: Draw first and
3207 last pixels differently. */
3209 [ns_lookup_indexed_color(color_first, f) set];
3210 NSRectFill(NSMakeRect (x0, y0, x1 - x0, 1));
3211 [ns_lookup_indexed_color(color, f) set];
3212 NSRectFill(NSMakeRect (x0, y0 + 1, x1 - x0, y1 - y0 - 2));
3213 [ns_lookup_indexed_color(color_last, f) set];
3214 NSRectFill(NSMakeRect (x0, y1 - 1, x1 - x0, 1));
3218 /* In any other case do not draw the first and last pixels
3220 [ns_lookup_indexed_color(color, f) set];
3221 NSRectFill(divider);
3224 ns_reset_clipping (f);
3229 ns_show_hourglass (struct frame *f)
3231 /* TODO: add NSProgressIndicator to all frames. */
3235 ns_hide_hourglass (struct frame *f)
3237 /* TODO: remove NSProgressIndicator from all frames. */
3240 /* ==========================================================================
3242 Glyph drawing operations
3244 ========================================================================== */
3247 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3248 /* --------------------------------------------------------------------------
3249 Wrapper utility to account for internal border width on full-width lines,
3250 and allow top full-width rows to hit the frame top. nr should be pointer
3251 to two successive NSRects. Number of rects actually used is returned.
3252 -------------------------------------------------------------------------- */
3254 int n = get_glyph_string_clip_rects (s, nr, 2);
3258 /* --------------------------------------------------------------------
3259 Draw a wavy line under glyph string s. The wave fills wave_height
3266 wave_height = 3 | * * * *
3267 --------------------------------------------------------------------- */
3270 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3272 int wave_height = 3, wave_length = 2;
3273 int y, dx, dy, odd, xmax;
3278 dy = wave_height - 1;
3279 y = s->ybase - wave_height + 3;
3282 /* Find and set clipping rectangle */
3283 waveClip = NSMakeRect (x, y, width, wave_height);
3284 [[NSGraphicsContext currentContext] saveGraphicsState];
3285 NSRectClip (waveClip);
3287 /* Draw the waves */
3288 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3290 odd = (int)(a.x/dx) % 2;
3291 a.y = b.y = y + 0.5;
3300 [NSBezierPath strokeLineFromPoint:a toPoint:b];
3301 a.x = b.x, a.y = b.y;
3302 b.x += dx, b.y = y + 0.5 + odd*dy;
3306 /* Restore previous clipping rectangle(s) */
3307 [[NSGraphicsContext currentContext] restoreGraphicsState];
3313 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3314 NSColor *defaultCol, CGFloat width, CGFloat x)
3315 /* --------------------------------------------------------------------------
3316 Draw underline, overline, and strike-through on glyph string s.
3317 -------------------------------------------------------------------------- */
3319 if (s->for_overlaps)
3323 if (face->underline_p)
3325 if (s->face->underline_type == FACE_UNDER_WAVE)
3327 if (face->underline_defaulted_p)
3330 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3332 ns_draw_underwave (s, width, x);
3334 else if (s->face->underline_type == FACE_UNDER_LINE)
3338 unsigned long thickness, position;
3340 /* If the prev was underlined, match its appearance. */
3341 if (s->prev && s->prev->face->underline_p
3342 && s->prev->face->underline_type == FACE_UNDER_LINE
3343 && s->prev->underline_thickness > 0)
3345 thickness = s->prev->underline_thickness;
3346 position = s->prev->underline_position;
3350 struct font *font = font_for_underline_metrics (s);
3351 unsigned long descent = s->y + s->height - s->ybase;
3353 /* Use underline thickness of font, defaulting to 1. */
3354 thickness = (font && font->underline_thickness > 0)
3355 ? font->underline_thickness : 1;
3357 /* Determine the offset of underlining from the baseline. */
3358 if (x_underline_at_descent_line)
3359 position = descent - thickness;
3360 else if (x_use_underline_position_properties
3361 && font && font->underline_position >= 0)
3362 position = font->underline_position;
3364 position = lround (font->descent / 2);
3366 position = underline_minimum_offset;
3368 position = max (position, underline_minimum_offset);
3370 /* Ensure underlining is not cropped. */
3371 if (descent <= position)
3373 position = descent - 1;
3376 else if (descent < position + thickness)
3380 s->underline_thickness = thickness;
3381 s->underline_position = position;
3383 r = NSMakeRect (x, s->ybase + position, width, thickness);
3385 if (face->underline_defaulted_p)
3388 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3392 /* Do overline. We follow other terms in using a thickness of 1
3393 and ignoring overline_margin. */
3394 if (face->overline_p)
3397 r = NSMakeRect (x, s->y, width, 1);
3399 if (face->overline_color_defaulted_p)
3402 [ns_lookup_indexed_color (face->overline_color, s->f) set];
3406 /* Do strike-through. We follow other terms for thickness and
3407 vertical position.*/
3408 if (face->strike_through_p)
3411 /* Y-coordinate and height of the glyph string's first glyph.
3412 We cannot use s->y and s->height because those could be
3413 larger if there are taller display elements (e.g., characters
3414 displayed with a larger font) in the same glyph row. */
3415 int glyph_y = s->ybase - s->first_glyph->ascent;
3416 int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
3417 /* Strike-through width and offset from the glyph string's
3419 unsigned long h = 1;
3422 dy = lrint ((glyph_height - h) / 2);
3423 r = NSMakeRect (x, glyph_y + dy, width, 1);
3425 if (face->strike_through_color_defaulted_p)
3428 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3434 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3435 char left_p, char right_p)
3436 /* --------------------------------------------------------------------------
3437 Draw an unfilled rect inside r, optionally leaving left and/or right open.
3438 Note we can't just use an NSDrawRect command, because of the possibility
3439 of some sides not being drawn, and because the rect will be filled.
3440 -------------------------------------------------------------------------- */
3446 s.size.height = thickness;
3448 s.origin.y += r.size.height - thickness;
3451 s.size.height = r.size.height;
3452 s.origin.y = r.origin.y;
3454 /* left, right (optional) */
3455 s.size.width = thickness;
3460 s.origin.x += r.size.width - thickness;
3467 ns_draw_relief (NSRect r, int thickness, char raised_p,
3468 char top_p, char bottom_p, char left_p, char right_p,
3469 struct glyph_string *s)
3470 /* --------------------------------------------------------------------------
3471 Draw a relief rect inside r, optionally leaving some sides open.
3472 Note we can't just use an NSDrawBezel command, because of the possibility
3473 of some sides not being drawn, and because the rect will be filled.
3474 -------------------------------------------------------------------------- */
3476 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3477 NSColor *newBaseCol = nil;
3480 NSTRACE ("ns_draw_relief");
3484 if (s->face->use_box_color_for_shadows_p)
3486 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3488 /* else if (s->first_glyph->type == IMAGE_GLYPH
3490 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3492 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
3496 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3499 if (newBaseCol == nil)
3500 newBaseCol = [NSColor grayColor];
3502 if (newBaseCol != baseCol) /* TODO: better check */
3505 baseCol = [newBaseCol retain];
3507 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3509 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3512 [(raised_p ? lightCol : darkCol) set];
3514 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3517 sr.size.height = thickness;
3518 if (top_p) NSRectFill (sr);
3521 sr.size.height = r.size.height;
3522 sr.size.width = thickness;
3523 if (left_p) NSRectFill (sr);
3525 [(raised_p ? darkCol : lightCol) set];
3528 sr.size.width = r.size.width;
3529 sr.size.height = thickness;
3530 sr.origin.y += r.size.height - thickness;
3531 if (bottom_p) NSRectFill (sr);
3534 sr.size.height = r.size.height;
3535 sr.origin.y = r.origin.y;
3536 sr.size.width = thickness;
3537 sr.origin.x += r.size.width - thickness;
3538 if (right_p) NSRectFill (sr);
3543 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3544 /* --------------------------------------------------------------------------
3545 Function modeled after x_draw_glyph_string_box ().
3546 Sets up parameters for drawing.
3547 -------------------------------------------------------------------------- */
3549 int right_x, last_x;
3550 char left_p, right_p;
3551 struct glyph *last_glyph;
3556 if (s->hl == DRAW_MOUSE_FACE)
3558 face = FACE_FROM_ID_OR_NULL (s->f,
3559 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3561 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3566 thickness = face->box_line_width;
3568 NSTRACE ("ns_dumpglyphs_box_or_relief");
3570 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3571 ? WINDOW_RIGHT_EDGE_X (s->w)
3572 : window_box_right (s->w, s->area));
3573 last_glyph = (s->cmp || s->img
3574 ? s->first_glyph : s->first_glyph + s->nchars-1);
3576 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3577 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3579 left_p = (s->first_glyph->left_box_line_p
3580 || (s->hl == DRAW_MOUSE_FACE
3581 && (s->prev == NULL || s->prev->hl != s->hl)));
3582 right_p = (last_glyph->right_box_line_p
3583 || (s->hl == DRAW_MOUSE_FACE
3584 && (s->next == NULL || s->next->hl != s->hl)));
3586 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3588 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3589 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3591 ns_draw_box (r, abs (thickness),
3592 ns_lookup_indexed_color (face->box_color, s->f),
3597 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3598 1, 1, left_p, right_p, s);
3604 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3605 /* --------------------------------------------------------------------------
3606 Modeled after x_draw_glyph_string_background, which draws BG in
3607 certain cases. Others are left to the text rendering routine.
3608 -------------------------------------------------------------------------- */
3610 NSTRACE ("ns_maybe_dumpglyphs_background");
3612 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3614 int box_line_width = max (s->face->box_line_width, 0);
3615 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3616 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3617 dimensions, since the actual glyphs might be much
3618 smaller. So in that case we always clear the rectangle
3619 with background color. */
3620 || FONT_TOO_HIGH (s->font)
3621 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3624 if (s->hl == DRAW_MOUSE_FACE)
3627 = FACE_FROM_ID_OR_NULL (s->f,
3628 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3630 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3633 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3635 [(NS_FACE_BACKGROUND (face) != 0
3636 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3637 : FRAME_BACKGROUND_COLOR (s->f)) set];
3640 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3641 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3644 if (s->hl != DRAW_CURSOR)
3646 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3647 s->background_width,
3648 s->height-2*box_line_width);
3652 s->background_filled_p = 1;
3659 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3660 /* --------------------------------------------------------------------------
3661 Renders an image and associated borders.
3662 -------------------------------------------------------------------------- */
3664 EmacsImage *img = s->img->pixmap;
3665 int box_line_vwidth = max (s->face->box_line_width, 0);
3666 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3667 int bg_x, bg_y, bg_height;
3674 NSTRACE ("ns_dumpglyphs_image");
3676 if (s->face->box != FACE_NO_BOX
3677 && s->first_glyph->left_box_line_p && s->slice.x == 0)
3678 x += abs (s->face->box_line_width);
3681 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3682 bg_height = s->height;
3683 /* other terms have this, but was causing problems w/tabbar mode */
3684 /* - 2 * box_line_vwidth; */
3686 if (s->slice.x == 0) x += s->img->hmargin;
3687 if (s->slice.y == 0) y += s->img->vmargin;
3689 /* Draw BG: if we need larger area than image itself cleared, do that,
3690 otherwise, since we composite the image under NS (instead of mucking
3691 with its background color), we must clear just the image area. */
3692 if (s->hl == DRAW_MOUSE_FACE)
3694 face = FACE_FROM_ID_OR_NULL (s->f,
3695 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3697 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3700 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3702 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3704 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3705 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3707 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3708 s->background_filled_p = 1;
3712 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3717 /* Draw the image.. do we need to draw placeholder if img ==nil? */
3720 #ifdef NS_IMPL_COCOA
3721 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3722 NSRect ir = NSMakeRect (s->slice.x,
3723 s->img->height - s->slice.y - s->slice.height,
3724 s->slice.width, s->slice.height);
3727 operation: NSCompositingOperationSourceOver
3732 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3733 operation: NSCompositingOperationSourceOver];
3737 if (s->hl == DRAW_CURSOR)
3739 [FRAME_CURSOR_COLOR (s->f) set];
3740 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3741 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3743 /* Currently on NS img->mask is always 0. Since
3744 get_window_cursor_type specifies a hollow box cursor when on
3745 a non-masked image we never reach this clause. But we put it
3746 in, in anticipation of better support for image masks on
3748 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3752 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3755 /* Draw underline, overline, strike-through. */
3756 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3758 /* Draw relief, if requested */
3759 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3761 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3763 th = tool_bar_button_relief >= 0 ?
3764 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3765 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3769 th = abs (s->img->relief);
3770 raised_p = (s->img->relief > 0);
3773 r.origin.x = x - th;
3774 r.origin.y = y - th;
3775 r.size.width = s->slice.width + 2*th-1;
3776 r.size.height = s->slice.height + 2*th-1;
3777 ns_draw_relief (r, th, raised_p,
3779 s->slice.y + s->slice.height == s->img->height,
3781 s->slice.x + s->slice.width == s->img->width, s);
3784 /* If there is no mask, the background won't be seen,
3785 so draw a rectangle on the image for the cursor.
3786 Do this for all images, getting transparency right is not reliable. */
3787 if (s->hl == DRAW_CURSOR)
3789 int thickness = abs (s->img->relief);
3790 if (thickness == 0) thickness = 1;
3791 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3797 ns_dumpglyphs_stretch (struct glyph_string *s)
3802 NSColor *fgCol, *bgCol;
3804 if (!s->background_filled_p)
3806 n = ns_get_glyph_string_clip_rect (s, r);
3807 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3809 if (ns_clip_to_rect (s->f, r, n))
3811 if (s->hl == DRAW_MOUSE_FACE)
3813 face = FACE_FROM_ID_OR_NULL (s->f,
3814 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3816 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3819 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3821 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3822 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3824 for (i = 0; i < n; ++i)
3826 if (!s->row->full_width_p)
3828 int overrun, leftoverrun;
3830 /* truncate to avoid overwriting fringe and/or scrollbar */
3831 overrun = max (0, (s->x + s->background_width)
3832 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3833 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3834 r[i].size.width -= overrun;
3836 /* truncate to avoid overwriting to left of the window box */
3837 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3838 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3840 if (leftoverrun > 0)
3842 r[i].origin.x += leftoverrun;
3843 r[i].size.width -= leftoverrun;
3846 /* XXX: Try to work between problem where a stretch glyph on
3847 a partially-visible bottom row will clear part of the
3848 modeline, and another where list-buffers headers and similar
3849 rows erroneously have visible_height set to 0. Not sure
3850 where this is coming from as other terms seem not to show. */
3851 r[i].size.height = min (s->height, s->row->visible_height);
3856 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3857 overwriting cursor (usually when cursor on a tab). */
3858 if (s->hl == DRAW_CURSOR)
3863 width = s->w->phys_cursor_width;
3864 r[i].size.width -= width;
3865 r[i].origin.x += width;
3869 /* Draw overlining, etc. on the cursor. */
3870 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3871 ns_draw_text_decoration (s, face, bgCol, width, x);
3873 ns_draw_text_decoration (s, face, fgCol, width, x);
3880 /* Draw overlining, etc. on the stretch glyph (or the part
3881 of the stretch glyph after the cursor). */
3882 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3885 ns_reset_clipping (s->f);
3887 s->background_filled_p = 1;
3893 ns_draw_glyph_string_foreground (struct glyph_string *s)
3896 struct font *font = s->font;
3898 /* If first glyph of S has a left box line, start drawing the text
3899 of S to the right of that box line. */
3900 if (s->face && s->face->box != FACE_NO_BOX
3901 && s->first_glyph->left_box_line_p)
3902 x = s->x + eabs (s->face->box_line_width);
3906 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3907 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3908 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3909 NS_DUMPGLYPH_NORMAL));
3912 (s, s->cmp_from, s->nchars, x, s->ybase,
3913 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3914 || flags == NS_DUMPGLYPH_MOUSEFACE);
3919 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3922 struct font *font = s->font;
3924 /* If first glyph of S has a left box line, start drawing the text
3925 of S to the right of that box line. */
3926 if (s->face && s->face->box != FACE_NO_BOX
3927 && s->first_glyph->left_box_line_p)
3928 x = s->x + eabs (s->face->box_line_width);
3932 /* S is a glyph string for a composition. S->cmp_from is the index
3933 of the first character drawn for glyphs of this composition.
3934 S->cmp_from == 0 means we are drawing the very first character of
3935 this composition. */
3937 /* Draw a rectangle for the composition if the font for the very
3938 first character of the composition could not be loaded. */
3939 if (s->font_not_found_p)
3941 if (s->cmp_from == 0)
3943 NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3944 ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3947 else if (! s->first_glyph->u.cmp.automatic)
3951 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3952 /* TAB in a composition means display glyphs with padding
3953 space on the left or right. */
3954 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3956 int xx = x + s->cmp->offsets[j * 2];
3957 int yy = y - s->cmp->offsets[j * 2 + 1];
3959 font->driver->draw (s, j, j + 1, xx, yy, false);
3960 if (s->face->overstrike)
3961 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3966 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3971 for (i = j = s->cmp_from; i < s->cmp_to; i++)
3973 glyph = LGSTRING_GLYPH (gstring, i);
3974 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3975 width += LGLYPH_WIDTH (glyph);
3978 int xoff, yoff, wadjust;
3982 font->driver->draw (s, j, i, x, y, false);
3983 if (s->face->overstrike)
3984 font->driver->draw (s, j, i, x + 1, y, false);
3987 xoff = LGLYPH_XOFF (glyph);
3988 yoff = LGLYPH_YOFF (glyph);
3989 wadjust = LGLYPH_WADJUST (glyph);
3990 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3991 if (s->face->overstrike)
3992 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
4001 font->driver->draw (s, j, i, x, y, false);
4002 if (s->face->overstrike)
4003 font->driver->draw (s, j, i, x + 1, y, false);
4009 ns_draw_glyph_string (struct glyph_string *s)
4010 /* --------------------------------------------------------------------------
4011 External (RIF): Main draw-text call.
4012 -------------------------------------------------------------------------- */
4014 /* TODO (optimize): focus for box and contents draw */
4017 char box_drawn_p = 0;
4018 struct font *font = s->face->font;
4019 if (! font) font = FRAME_FONT (s->f);
4021 NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
4023 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
4026 struct glyph_string *next;
4028 for (width = 0, next = s->next;
4029 next && width < s->right_overhang;
4030 width += next->width, next = next->next)
4031 if (next->first_glyph->type != IMAGE_GLYPH)
4033 if (next->first_glyph->type != STRETCH_GLYPH)
4035 n = ns_get_glyph_string_clip_rect (s->next, r);
4036 if (ns_clip_to_rect (s->f, r, n))
4038 ns_maybe_dumpglyphs_background (s->next, 1);
4039 ns_reset_clipping (s->f);
4044 ns_dumpglyphs_stretch (s->next);
4046 next->num_clips = 0;
4050 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
4051 && (s->first_glyph->type == CHAR_GLYPH
4052 || s->first_glyph->type == COMPOSITE_GLYPH))
4054 n = ns_get_glyph_string_clip_rect (s, r);
4055 if (ns_clip_to_rect (s->f, r, n))
4057 ns_maybe_dumpglyphs_background (s, 1);
4058 ns_dumpglyphs_box_or_relief (s);
4059 ns_reset_clipping (s->f);
4064 switch (s->first_glyph->type)
4068 n = ns_get_glyph_string_clip_rect (s, r);
4069 if (ns_clip_to_rect (s->f, r, n))
4071 ns_dumpglyphs_image (s, r[0]);
4072 ns_reset_clipping (s->f);
4077 ns_dumpglyphs_stretch (s);
4081 case COMPOSITE_GLYPH:
4082 n = ns_get_glyph_string_clip_rect (s, r);
4083 if (ns_clip_to_rect (s->f, r, n))
4085 if (s->for_overlaps || (s->cmp_from > 0
4086 && ! s->first_glyph->u.cmp.automatic))
4087 s->background_filled_p = 1;
4089 ns_maybe_dumpglyphs_background
4090 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4092 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4094 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4095 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4096 NS_FACE_FOREGROUND (s->face) = tmp;
4100 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
4103 ns_draw_composite_glyph_string_foreground (s);
4105 ns_draw_glyph_string_foreground (s);
4109 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
4110 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
4112 : FRAME_FOREGROUND_COLOR (s->f));
4115 /* Draw underline, overline, strike-through. */
4116 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
4119 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4121 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4122 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4123 NS_FACE_FOREGROUND (s->face) = tmp;
4126 ns_reset_clipping (s->f);
4130 case GLYPHLESS_GLYPH:
4131 n = ns_get_glyph_string_clip_rect (s, r);
4132 if (ns_clip_to_rect (s->f, r, n))
4134 if (s->for_overlaps || (s->cmp_from > 0
4135 && ! s->first_glyph->u.cmp.automatic))
4136 s->background_filled_p = 1;
4138 ns_maybe_dumpglyphs_background
4139 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4141 /* Not yet implemented. */
4143 ns_reset_clipping (s->f);
4151 /* Draw box if not done already. */
4152 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
4154 n = ns_get_glyph_string_clip_rect (s, r);
4155 if (ns_clip_to_rect (s->f, r, n))
4157 ns_dumpglyphs_box_or_relief (s);
4158 ns_reset_clipping (s->f);
4167 /* ==========================================================================
4171 ========================================================================== */
4175 ns_send_appdefined (int value)
4176 /* --------------------------------------------------------------------------
4177 Internal: post an appdefined event which EmacsApp-sendEvent will
4178 recognize and take as a command to halt the event loop.
4179 -------------------------------------------------------------------------- */
4181 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
4183 // GNUstep needs postEvent to happen on the main thread.
4184 // Cocoa needs nextEventMatchingMask to happen on the main thread too.
4185 if (! [[NSThread currentThread] isMainThread])
4187 EmacsApp *app = (EmacsApp *)NSApp;
4188 app->nextappdefined = value;
4189 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
4195 /* Only post this event if we haven't already posted one. This will end
4196 the [NXApp run] main loop after having processed all events queued at
4199 #ifdef NS_IMPL_COCOA
4200 if (! send_appdefined)
4202 /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves
4203 in certain situations (rapid incoming events).
4204 So check if we have one, if not add one. */
4205 NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
4206 untilDate:[NSDate distantPast]
4207 inMode:NSDefaultRunLoopMode
4209 if (! appev) send_appdefined = YES;
4213 if (send_appdefined)
4217 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
4218 send_appdefined = NO;
4220 /* Don't need wakeup timer any more */
4223 [timed_entry invalidate];
4224 [timed_entry release];
4228 nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
4229 location: NSMakePoint (0, 0)
4232 windowNumber: [[NSApp mainWindow] windowNumber]
4233 context: [NSApp context]
4238 /* Post an application defined event on the event queue. When this is
4239 received the [NXApp run] will return, thus having processed all
4240 events which are currently queued. */
4241 [NSApp postEvent: nxev atStart: NO];
4245 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4249 Lisp_Object frame, tail;
4251 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
4254 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
4256 FOR_EACH_FRAME (tail, frame)
4258 struct frame *f = XFRAME (frame);
4261 EmacsView *view = FRAME_NS_VIEW (f);
4262 [view updateCollectionBehavior];
4268 /* GNUstep does not have cancelTracking. */
4269 #ifdef NS_IMPL_COCOA
4270 /* Check if menu open should be canceled or continued as normal. */
4272 ns_check_menu_open (NSMenu *menu)
4274 /* Click in menu bar? */
4275 NSArray *a = [[NSApp mainMenu] itemArray];
4279 if (menu == nil) // Menu tracking ended.
4281 if (menu_will_open_state == MENU_OPENING)
4282 menu_will_open_state = MENU_NONE;
4286 for (i = 0; ! found && i < [a count]; i++)
4287 found = menu == [[a objectAtIndex:i] submenu];
4290 if (menu_will_open_state == MENU_NONE && emacs_event)
4292 NSEvent *theEvent = [NSApp currentEvent];
4293 struct frame *emacsframe = SELECTED_FRAME ();
4295 [menu cancelTracking];
4296 menu_will_open_state = MENU_PENDING;
4297 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4298 EV_TRAILER (theEvent);
4300 CGEventRef ourEvent = CGEventCreate (NULL);
4301 menu_mouse_point = CGEventGetLocation (ourEvent);
4302 CFRelease (ourEvent);
4304 else if (menu_will_open_state == MENU_OPENING)
4306 menu_will_open_state = MENU_NONE;
4311 /* Redo saved menu click if state is MENU_PENDING. */
4313 ns_check_pending_open_menu ()
4315 if (menu_will_open_state == MENU_PENDING)
4317 CGEventSourceRef source
4318 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4320 CGEventRef event = CGEventCreateMouseEvent (source,
4321 kCGEventLeftMouseDown,
4323 kCGMouseButtonLeft);
4324 CGEventSetType (event, kCGEventLeftMouseDown);
4325 CGEventPost (kCGHIDEventTap, event);
4329 menu_will_open_state = MENU_OPENING;
4332 #endif /* NS_IMPL_COCOA */
4335 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4336 /* --------------------------------------------------------------------------
4337 External (hook): Post an event to ourself and keep reading events until
4338 we read it back again. In effect process all events which were waiting.
4339 From 21+ we have to manage the event buffer ourselves.
4340 -------------------------------------------------------------------------- */
4342 struct input_event ev;
4345 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4347 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4351 if ([NSApp modalWindow] != nil)
4354 if (hold_event_q.nr > 0)
4357 for (i = 0; i < hold_event_q.nr; ++i)
4358 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4359 hold_event_q.nr = 0;
4363 if ([NSThread isMainThread])
4366 n_emacs_events_pending = 0;
4367 ns_init_events (&ev);
4368 q_event_ptr = hold_quit;
4370 /* we manage autorelease pools by allocate/reallocate each time around
4371 the loop; strict nesting is occasionally violated but seems not to
4372 matter.. earlier methods using full nesting caused major memory leaks */
4373 [outerpool release];
4374 outerpool = [[NSAutoreleasePool alloc] init];
4376 /* If have pending open-file requests, attend to the next one of those. */
4377 if (ns_pending_files && [ns_pending_files count] != 0
4378 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4380 [ns_pending_files removeObjectAtIndex: 0];
4382 /* Deal with pending service requests. */
4383 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4385 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4386 withArg: [ns_pending_service_args objectAtIndex: 0]])
4388 [ns_pending_service_names removeObjectAtIndex: 0];
4389 [ns_pending_service_args removeObjectAtIndex: 0];
4393 /* Run and wait for events. We must always send one NX_APPDEFINED event
4394 to ourself, otherwise [NXApp run] will never exit. */
4395 send_appdefined = YES;
4396 ns_send_appdefined (-1);
4401 nevents = n_emacs_events_pending;
4402 n_emacs_events_pending = 0;
4403 ns_finish_events ();
4415 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4416 fd_set *exceptfds, struct timespec *timeout,
4418 /* --------------------------------------------------------------------------
4419 Replacement for select, checking for events
4420 -------------------------------------------------------------------------- */
4424 struct input_event event;
4427 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4429 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4433 if (hold_event_q.nr > 0)
4435 /* We already have events pending. */
4441 for (k = 0; k < nfds+1; k++)
4443 if (readfds && FD_ISSET(k, readfds)) ++nr;
4444 if (writefds && FD_ISSET(k, writefds)) ++nr;
4448 || ![NSThread isMainThread]
4449 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4450 return thread_select(pselect, nfds, readfds, writefds,
4451 exceptfds, timeout, sigmask);
4454 struct timespec t = {0, 0};
4455 thread_select(pselect, 0, NULL, NULL, NULL, &t, sigmask);
4458 [outerpool release];
4459 outerpool = [[NSAutoreleasePool alloc] init];
4462 send_appdefined = YES;
4465 pthread_mutex_lock (&select_mutex);
4470 select_readfds = *readfds;
4471 select_valid += SELECT_HAVE_READ;
4475 select_writefds = *writefds;
4476 select_valid += SELECT_HAVE_WRITE;
4481 select_timeout = *timeout;
4482 select_valid += SELECT_HAVE_TMO;
4485 pthread_mutex_unlock (&select_mutex);
4487 /* Inform fd_handler that select should be called */
4489 emacs_write_sig (selfds[1], &c, 1);
4491 else if (nr == 0 && timeout)
4493 /* No file descriptor, just a timeout, no need to wake fd_handler */
4494 double time = timespectod (*timeout);
4495 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4498 @selector (timeout_handler:)
4503 else /* No timeout and no file descriptors, can this happen? */
4505 /* Send appdefined so we exit from the loop */
4506 ns_send_appdefined (-1);
4510 ns_init_events (&event);
4514 ns_finish_events ();
4515 if (nr > 0 && readfds)
4518 emacs_write_sig (selfds[1], &c, 1);
4522 t = last_appdefined_event_data;
4524 if (t != NO_APPDEFINED_DATA)
4526 last_appdefined_event_data = NO_APPDEFINED_DATA;
4530 /* The NX_APPDEFINED event we received was a timeout. */
4535 /* The NX_APPDEFINED event we received was the result of
4536 at least one real input event arriving. */
4542 /* Received back from select () in fd_handler; copy the results */
4543 pthread_mutex_lock (&select_mutex);
4544 if (readfds) *readfds = select_readfds;
4545 if (writefds) *writefds = select_writefds;
4546 pthread_mutex_unlock (&select_mutex);
4561 ns_run_loop_break ()
4562 /* Break out of the NS run loop in ns_select or ns_read_socket. */
4564 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_run_loop_break");
4566 /* If we don't have a GUI, don't send the event. */
4568 ns_send_appdefined(-1);
4573 /* ==========================================================================
4577 ========================================================================== */
4581 ns_set_vertical_scroll_bar (struct window *window,
4582 int portion, int whole, int position)
4583 /* --------------------------------------------------------------------------
4584 External (hook): Update or add scrollbar
4585 -------------------------------------------------------------------------- */
4589 struct frame *f = XFRAME (WINDOW_FRAME (window));
4590 EmacsView *view = FRAME_NS_VIEW (f);
4592 int window_y, window_height;
4593 int top, left, height, width;
4594 BOOL update_p = YES;
4596 /* optimization; display engine sends WAY too many of these.. */
4597 if (!NILP (window->vertical_scroll_bar))
4599 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4600 if ([bar checkSamePosition: position portion: portion whole: whole])
4602 if (view->scrollbarsNeedingUpdate == 0)
4604 if (!windows_or_buffers_changed)
4608 view->scrollbarsNeedingUpdate--;
4613 NSTRACE ("ns_set_vertical_scroll_bar");
4615 /* Get dimensions. */
4616 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4618 height = window_height;
4619 width = NS_SCROLL_BAR_WIDTH (f);
4620 left = WINDOW_SCROLL_BAR_AREA_X (window);
4622 r = NSMakeRect (left, top, width, height);
4623 /* the parent view is flipped, so we need to flip y value */
4625 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4627 XSETWINDOW (win, window);
4630 /* we want at least 5 lines to display a scrollbar */
4631 if (WINDOW_TOTAL_LINES (window) < 5)
4633 if (!NILP (window->vertical_scroll_bar))
4635 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4636 [bar removeFromSuperview];
4637 wset_vertical_scroll_bar (window, Qnil);
4640 ns_clear_frame_area (f, left, top, width, height);
4645 if (NILP (window->vertical_scroll_bar))
4647 if (width > 0 && height > 0)
4648 ns_clear_frame_area (f, left, top, width, height);
4650 bar = [[EmacsScroller alloc] initFrame: r window: win];
4651 wset_vertical_scroll_bar (window, make_save_ptr (bar));
4657 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4658 oldRect = [bar frame];
4659 r.size.width = oldRect.size.width;
4660 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4662 if (oldRect.origin.x != r.origin.x)
4663 ns_clear_frame_area (f, left, top, width, height);
4669 [bar setPosition: position portion: portion whole: whole];
4675 ns_set_horizontal_scroll_bar (struct window *window,
4676 int portion, int whole, int position)
4677 /* --------------------------------------------------------------------------
4678 External (hook): Update or add scrollbar
4679 -------------------------------------------------------------------------- */
4683 struct frame *f = XFRAME (WINDOW_FRAME (window));
4684 EmacsView *view = FRAME_NS_VIEW (f);
4686 int top, height, left, width;
4687 int window_x, window_width;
4688 BOOL update_p = YES;
4690 /* optimization; display engine sends WAY too many of these.. */
4691 if (!NILP (window->horizontal_scroll_bar))
4693 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4694 if ([bar checkSamePosition: position portion: portion whole: whole])
4696 if (view->scrollbarsNeedingUpdate == 0)
4698 if (!windows_or_buffers_changed)
4702 view->scrollbarsNeedingUpdate--;
4707 NSTRACE ("ns_set_horizontal_scroll_bar");
4709 /* Get dimensions. */
4710 window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4712 width = window_width;
4713 height = NS_SCROLL_BAR_HEIGHT (f);
4714 top = WINDOW_SCROLL_BAR_AREA_Y (window);
4716 r = NSMakeRect (left, top, width, height);
4717 /* the parent view is flipped, so we need to flip y value */
4719 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4721 XSETWINDOW (win, window);
4724 if (NILP (window->horizontal_scroll_bar))
4726 if (width > 0 && height > 0)
4727 ns_clear_frame_area (f, left, top, width, height);
4729 bar = [[EmacsScroller alloc] initFrame: r window: win];
4730 wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4736 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4737 oldRect = [bar frame];
4738 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4740 if (oldRect.origin.y != r.origin.y)
4741 ns_clear_frame_area (f, left, top, width, height);
4747 /* If there are both horizontal and vertical scroll-bars they leave
4748 a square that belongs to neither. We need to clear it otherwise
4749 it fills with junk. */
4750 if (!NILP (window->vertical_scroll_bar))
4751 ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4752 NS_SCROLL_BAR_HEIGHT (f), height);
4755 [bar setPosition: position portion: portion whole: whole];
4761 ns_condemn_scroll_bars (struct frame *f)
4762 /* --------------------------------------------------------------------------
4763 External (hook): arrange for all frame's scrollbars to be removed
4764 at next call to judge_scroll_bars, except for those redeemed.
4765 -------------------------------------------------------------------------- */
4769 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4771 NSTRACE ("ns_condemn_scroll_bars");
4773 for (i =[subviews count]-1; i >= 0; i--)
4775 view = [subviews objectAtIndex: i];
4776 if ([view isKindOfClass: [EmacsScroller class]])
4783 ns_redeem_scroll_bar (struct window *window)
4784 /* --------------------------------------------------------------------------
4785 External (hook): arrange to spare this window's scrollbar
4786 at next call to judge_scroll_bars.
4787 -------------------------------------------------------------------------- */
4790 NSTRACE ("ns_redeem_scroll_bar");
4791 if (!NILP (window->vertical_scroll_bar)
4792 && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4794 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4798 if (!NILP (window->horizontal_scroll_bar)
4799 && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4801 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4808 ns_judge_scroll_bars (struct frame *f)
4809 /* --------------------------------------------------------------------------
4810 External (hook): destroy all scrollbars on frame that weren't
4811 redeemed after call to condemn_scroll_bars.
4812 -------------------------------------------------------------------------- */
4816 EmacsView *eview = FRAME_NS_VIEW (f);
4817 NSArray *subviews = [[eview superview] subviews];
4820 NSTRACE ("ns_judge_scroll_bars");
4821 for (i = [subviews count]-1; i >= 0; --i)
4823 view = [subviews objectAtIndex: i];
4824 if (![view isKindOfClass: [EmacsScroller class]]) continue;
4830 [eview updateFrameSize: NO];
4833 /* ==========================================================================
4837 ========================================================================== */
4840 x_display_pixel_height (struct ns_display_info *dpyinfo)
4842 NSArray *screens = [NSScreen screens];
4843 NSEnumerator *enumerator = [screens objectEnumerator];
4848 while ((screen = [enumerator nextObject]) != nil)
4849 frame = NSUnionRect (frame, [screen frame]);
4851 return NSHeight (frame);
4855 x_display_pixel_width (struct ns_display_info *dpyinfo)
4857 NSArray *screens = [NSScreen screens];
4858 NSEnumerator *enumerator = [screens objectEnumerator];
4863 while ((screen = [enumerator nextObject]) != nil)
4864 frame = NSUnionRect (frame, [screen frame]);
4866 return NSWidth (frame);
4870 static Lisp_Object ns_string_to_lispmod (const char *s)
4871 /* --------------------------------------------------------------------------
4872 Convert modifier name to lisp symbol
4873 -------------------------------------------------------------------------- */
4875 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4877 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4879 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4881 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4883 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4885 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4893 ns_default (const char *parameter, Lisp_Object *result,
4894 Lisp_Object yesval, Lisp_Object noval,
4895 BOOL is_float, BOOL is_modstring)
4896 /* --------------------------------------------------------------------------
4897 Check a parameter value in user's preferences
4898 -------------------------------------------------------------------------- */
4900 const char *value = ns_get_defaults_value (parameter);
4906 if (c_strcasecmp (value, "YES") == 0)
4908 else if (c_strcasecmp (value, "NO") == 0)
4910 else if (is_float && (f = strtod (value, &pos), pos != value))
4911 *result = make_float (f);
4912 else if (is_modstring && value)
4913 *result = ns_string_to_lispmod (value);
4914 else fprintf (stderr,
4915 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4921 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4922 /* --------------------------------------------------------------------------
4923 Initialize global info and storage for display.
4924 -------------------------------------------------------------------------- */
4926 NSScreen *screen = [NSScreen mainScreen];
4927 NSWindowDepth depth = [screen depth];
4929 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4930 dpyinfo->resy = 72.27;
4931 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4932 NSColorSpaceFromDepth (depth)]
4933 && ![NSCalibratedWhiteColorSpace isEqualToString:
4934 NSColorSpaceFromDepth (depth)];
4935 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4936 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4937 dpyinfo->color_table->colors = NULL;
4938 dpyinfo->root_window = 42; /* a placeholder.. */
4939 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4940 dpyinfo->n_fonts = 0;
4941 dpyinfo->smallest_font_height = 1;
4942 dpyinfo->smallest_char_width = 1;
4944 reset_mouse_highlight (&dpyinfo->mouse_highlight);
4948 /* This and next define (many of the) public functions in this file. */
4949 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4950 with using despite presence in the "system dependent" redisplay
4951 interface. In addition, many of the ns_ methods have code that is
4952 shared with all terms, indicating need for further refactoring. */
4953 extern frame_parm_handler ns_frame_parm_handlers[];
4954 static struct redisplay_interface ns_redisplay_interface =
4956 ns_frame_parm_handlers,
4960 x_clear_end_of_line,
4962 ns_after_update_window_line,
4963 ns_update_window_begin,
4964 ns_update_window_end,
4965 0, /* flush_display */
4966 x_clear_window_mouse_face,
4967 x_get_glyph_overhangs,
4968 x_fix_overlapping_area,
4969 ns_draw_fringe_bitmap,
4970 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4971 0, /* destroy_fringe_bitmap */
4972 ns_compute_glyph_string_overhangs,
4973 ns_draw_glyph_string,
4974 ns_define_frame_cursor,
4975 ns_clear_frame_area,
4976 ns_draw_window_cursor,
4977 ns_draw_vertical_window_border,
4978 ns_draw_window_divider,
4979 ns_shift_glyphs_for_insert,
4986 ns_delete_display (struct ns_display_info *dpyinfo)
4992 /* This function is called when the last frame on a display is deleted. */
4994 ns_delete_terminal (struct terminal *terminal)
4996 struct ns_display_info *dpyinfo = terminal->display_info.ns;
4998 NSTRACE ("ns_delete_terminal");
5000 /* Protect against recursive calls. delete_frame in
5001 delete_terminal calls us back when it deletes our last frame. */
5002 if (!terminal->name)
5007 x_destroy_all_bitmaps (dpyinfo);
5008 ns_delete_display (dpyinfo);
5013 static struct terminal *
5014 ns_create_terminal (struct ns_display_info *dpyinfo)
5015 /* --------------------------------------------------------------------------
5016 Set up use of NS before we make the first connection.
5017 -------------------------------------------------------------------------- */
5019 struct terminal *terminal;
5021 NSTRACE ("ns_create_terminal");
5023 terminal = create_terminal (output_ns, &ns_redisplay_interface);
5025 terminal->display_info.ns = dpyinfo;
5026 dpyinfo->terminal = terminal;
5028 terminal->clear_frame_hook = ns_clear_frame;
5029 terminal->ring_bell_hook = ns_ring_bell;
5030 terminal->update_begin_hook = ns_update_begin;
5031 terminal->update_end_hook = ns_update_end;
5032 terminal->read_socket_hook = ns_read_socket;
5033 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
5034 terminal->mouse_position_hook = ns_mouse_position;
5035 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
5036 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
5037 terminal->fullscreen_hook = ns_fullscreen_hook;
5038 terminal->menu_show_hook = ns_menu_show;
5039 terminal->popup_dialog_hook = ns_popup_dialog;
5040 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
5041 terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
5042 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
5043 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
5044 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
5045 terminal->delete_frame_hook = x_destroy_window;
5046 terminal->delete_terminal_hook = ns_delete_terminal;
5047 /* Other hooks are NULL by default. */
5053 struct ns_display_info *
5054 ns_term_init (Lisp_Object display_name)
5055 /* --------------------------------------------------------------------------
5056 Start the Application and get things rolling.
5057 -------------------------------------------------------------------------- */
5059 struct terminal *terminal;
5060 struct ns_display_info *dpyinfo;
5061 static int ns_initialized = 0;
5064 if (ns_initialized) return x_display_list;
5069 NSTRACE ("ns_term_init");
5071 [outerpool release];
5072 outerpool = [[NSAutoreleasePool alloc] init];
5074 /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */
5075 /*GSDebugAllocationActive (YES); */
5079 Fset_input_interrupt_mode (Qnil);
5081 if (selfds[0] == -1)
5083 if (emacs_pipe (selfds) != 0)
5085 fprintf (stderr, "Failed to create pipe: %s\n",
5086 emacs_strerror (errno));
5090 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
5091 FD_ZERO (&select_readfds);
5092 FD_ZERO (&select_writefds);
5093 pthread_mutex_init (&select_mutex, NULL);
5096 ns_pending_files = [[NSMutableArray alloc] init];
5097 ns_pending_service_names = [[NSMutableArray alloc] init];
5098 ns_pending_service_args = [[NSMutableArray alloc] init];
5100 /* Start app and create the main menu, window, view.
5101 Needs to be here because ns_initialize_display_info () uses AppKit classes.
5102 The view will then ask the NSApp to stop and return to Emacs. */
5103 [EmacsApp sharedApplication];
5106 [NSApp setDelegate: NSApp];
5108 /* Start the select thread. */
5109 [NSThread detachNewThreadSelector:@selector (fd_handler:)
5113 /* debugging: log all notifications */
5114 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
5115 selector: @selector (logNotification:)
5116 name: nil object: nil]; */
5118 dpyinfo = xzalloc (sizeof *dpyinfo);
5120 ns_initialize_display_info (dpyinfo);
5121 terminal = ns_create_terminal (dpyinfo);
5123 terminal->kboard = allocate_kboard (Qns);
5124 /* Don't let the initial kboard remain current longer than necessary.
5125 That would cause problems if a file loaded on startup tries to
5126 prompt in the mini-buffer. */
5127 if (current_kboard == initial_kboard)
5128 current_kboard = terminal->kboard;
5129 terminal->kboard->reference_count++;
5131 dpyinfo->next = x_display_list;
5132 x_display_list = dpyinfo;
5134 dpyinfo->name_list_element = Fcons (display_name, Qnil);
5136 terminal->name = xlispstrdup (display_name);
5140 if (!inhibit_x_resources)
5142 ns_default ("GSFontAntiAlias", &ns_antialias_text,
5145 /* this is a standard variable */
5146 ns_default ("AppleAntiAliasingThreshold", &tmp,
5147 make_float (10.0), make_float (6.0), YES, NO);
5148 ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp);
5151 NSTRACE_MSG ("Colors");
5154 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
5158 Lisp_Object color_file, color_map, color;
5162 color_file = Fexpand_file_name (build_string ("rgb.txt"),
5163 Fsymbol_value (intern ("data-directory")));
5165 color_map = Fx_load_color_file (color_file);
5166 if (NILP (color_map))
5167 fatal ("Could not read %s.\n", SDATA (color_file));
5169 cl = [[NSColorList alloc] initWithName: @"Emacs"];
5170 for ( ; CONSP (color_map); color_map = XCDR (color_map))
5172 color = XCAR (color_map);
5173 name = SSDATA (XCAR (color));
5174 c = XINT (XCDR (color));
5176 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
5177 green: GREEN_FROM_ULONG (c) / 255.0
5178 blue: BLUE_FROM_ULONG (c) / 255.0
5180 forKey: [NSString stringWithUTF8String: name]];
5183 /* FIXME: Report any errors writing the color file below. */
5184 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101100
5185 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101100
5186 if ([cl respondsToSelector:@selector(writeToURL:error:)])
5188 [cl writeToURL:nil error:nil];
5189 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101100
5192 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101100 */
5193 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101100 \
5194 || defined (NS_IMPL_GNUSTEP)
5195 [cl writeToFile: nil];
5200 NSTRACE_MSG ("Versions");
5203 #ifdef NS_IMPL_GNUSTEP
5204 Vwindow_system_version = build_string (gnustep_base_version);
5206 /*PSnextrelease (128, c); */
5207 char c[DBL_BUFSIZE_BOUND];
5208 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
5209 Vwindow_system_version = make_unibyte_string (c, len);
5213 delete_keyboard_wait_descriptor (0);
5215 ns_app_name = [[NSProcessInfo processInfo] processName];
5217 /* Set up macOS app menu */
5219 NSTRACE_MSG ("Menu init");
5221 #ifdef NS_IMPL_COCOA
5225 /* set up the application menu */
5226 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
5227 [svcsMenu setAutoenablesItems: NO];
5228 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
5229 [appMenu setAutoenablesItems: NO];
5230 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
5231 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
5233 [appMenu insertItemWithTitle: @"About Emacs"
5234 action: @selector (orderFrontStandardAboutPanel:)
5237 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
5238 [appMenu insertItemWithTitle: @"Preferences..."
5239 action: @selector (showPreferencesWindow:)
5242 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
5243 item = [appMenu insertItemWithTitle: @"Services"
5244 action: @selector (menuDown:)
5247 [appMenu setSubmenu: svcsMenu forItem: item];
5248 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
5249 [appMenu insertItemWithTitle: @"Hide Emacs"
5250 action: @selector (hide:)
5253 item = [appMenu insertItemWithTitle: @"Hide Others"
5254 action: @selector (hideOtherApplications:)
5257 [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption];
5258 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
5259 [appMenu insertItemWithTitle: @"Quit Emacs"
5260 action: @selector (terminate:)
5264 item = [mainMenu insertItemWithTitle: ns_app_name
5265 action: @selector (menuDown:)
5268 [mainMenu setSubmenu: appMenu forItem: item];
5269 [dockMenu insertItemWithTitle: @"New Frame"
5270 action: @selector (newFrame:)
5274 [NSApp setMainMenu: mainMenu];
5275 [NSApp setAppleMenu: appMenu];
5276 [NSApp setServicesMenu: svcsMenu];
5277 /* Needed at least on Cocoa, to get dock menu to show windows */
5278 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5280 [[NSNotificationCenter defaultCenter]
5281 addObserver: mainMenu
5282 selector: @selector (trackingNotification:)
5283 name: NSMenuDidBeginTrackingNotification object: mainMenu];
5284 [[NSNotificationCenter defaultCenter]
5285 addObserver: mainMenu
5286 selector: @selector (trackingNotification:)
5287 name: NSMenuDidEndTrackingNotification object: mainMenu];
5289 #endif /* macOS menu setup */
5291 /* Register our external input/output types, used for determining
5292 applicable services and also drag/drop eligibility. */
5294 NSTRACE_MSG ("Input/output types");
5296 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5297 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5299 ns_drag_types = [[NSArray arrayWithObjects:
5301 NSTabularTextPboardType,
5302 NSFilenamesPboardType,
5303 NSURLPboardType, nil] retain];
5305 /* If fullscreen is in init/default-frame-alist, focus isn't set
5306 right for fullscreen windows, so set this. */
5307 [NSApp activateIgnoringOtherApps:YES];
5309 NSTRACE_MSG ("Call NSApp run");
5312 ns_do_open_file = YES;
5314 #ifdef NS_IMPL_GNUSTEP
5315 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5316 We must re-catch it so subprocess works. */
5317 catch_child_signal ();
5320 NSTRACE_MSG ("ns_term_init done");
5329 ns_term_shutdown (int sig)
5331 [[NSUserDefaults standardUserDefaults] synchronize];
5333 /* code not reached in emacs.c after this is called by shut_down_emacs: */
5334 if (STRINGP (Vauto_save_list_file_name))
5335 unlink (SSDATA (Vauto_save_list_file_name));
5337 if (sig == 0 || sig == SIGTERM)
5339 [NSApp terminate: NSApp];
5341 else // force a stack trace to happen
5348 /* ==========================================================================
5350 EmacsApp implementation
5352 ========================================================================== */
5355 @implementation EmacsApp
5359 NSTRACE ("[EmacsApp init]");
5361 if ((self = [super init]))
5363 #ifdef NS_IMPL_COCOA
5364 self->isFirst = YES;
5366 #ifdef NS_IMPL_GNUSTEP
5367 self->applicationDidFinishLaunchingCalled = NO;
5374 #ifdef NS_IMPL_COCOA
5377 NSTRACE ("[EmacsApp run]");
5379 #ifndef NSAppKitVersionNumber10_9
5380 #define NSAppKitVersionNumber10_9 1265
5383 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5389 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5391 if (isFirst) [self finishLaunching];
5394 shouldKeepRunning = YES;
5398 pool = [[NSAutoreleasePool alloc] init];
5401 [self nextEventMatchingMask:NSEventMaskAny
5402 untilDate:[NSDate distantFuture]
5403 inMode:NSDefaultRunLoopMode
5406 [self sendEvent:event];
5407 [self updateWindows];
5408 } while (shouldKeepRunning);
5413 - (void)stop: (id)sender
5415 NSTRACE ("[EmacsApp stop:]");
5417 shouldKeepRunning = NO;
5418 // Stop possible dialog also. Noop if no dialog present.
5419 // The file dialog still leaks 7k - 10k on 10.9 though.
5420 [super stop:sender];
5422 #endif /* NS_IMPL_COCOA */
5424 - (void)logNotification: (NSNotification *)notification
5426 NSTRACE ("[EmacsApp logNotification:]");
5428 const char *name = [[notification name] UTF8String];
5429 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5430 && !strstr (name, "WindowNumber"))
5431 NSLog (@"notification: '%@'", [notification name]);
5435 - (void)sendEvent: (NSEvent *)theEvent
5436 /* --------------------------------------------------------------------------
5437 Called when NSApp is running for each event received. Used to stop
5438 the loop when we choose, since there's no way to just run one iteration.
5439 -------------------------------------------------------------------------- */
5441 int type = [theEvent type];
5442 NSWindow *window = [theEvent window];
5444 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5445 NSTRACE_MSG ("Type: %d", type);
5447 #ifdef NS_IMPL_GNUSTEP
5448 // Keyboard events aren't propagated to file dialogs for some reason.
5449 if ([NSApp modalWindow] != nil &&
5450 (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged))
5452 [[NSApp modalWindow] sendEvent: theEvent];
5457 if (represented_filename != nil && represented_frame)
5459 NSString *fstr = represented_filename;
5460 NSView *view = FRAME_NS_VIEW (represented_frame);
5461 #ifdef NS_IMPL_COCOA
5462 /* work around a bug observed on 10.3 and later where
5463 setTitleWithRepresentedFilename does not clear out previous state
5464 if given filename does not exist */
5465 if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5466 [[view window] setRepresentedFilename: @""];
5468 [[view window] setRepresentedFilename: fstr];
5469 [represented_filename release];
5470 represented_filename = nil;
5471 represented_frame = NULL;
5474 if (type == NSEventTypeApplicationDefined)
5476 switch ([theEvent data2])
5478 #ifdef NS_IMPL_COCOA
5479 case NSAPP_DATA2_RUNASSCRIPT:
5484 case NSAPP_DATA2_RUNFILEDIALOG:
5485 ns_run_file_dialog ();
5491 if (type == NSEventTypeCursorUpdate && window == nil)
5493 fprintf (stderr, "Dropping external cursor update event.\n");
5497 if (type == NSEventTypeApplicationDefined)
5499 /* Events posted by ns_send_appdefined interrupt the run loop here.
5500 But, if a modal window is up, an appdefined can still come through,
5501 (e.g., from a makeKeyWindow event) but stopping self also stops the
5502 modal loop. Just defer it until later. */
5503 if ([NSApp modalWindow] == nil)
5505 last_appdefined_event_data = [theEvent data1];
5510 send_appdefined = YES;
5515 #ifdef NS_IMPL_COCOA
5516 /* If no dialog and none of our frames have focus and it is a move, skip it.
5517 It is a mouse move in an auxiliary menu, i.e. on the top right on macOS,
5518 such as Wifi, sound, date or similar.
5519 This prevents "spooky" highlighting in the frame under the menu. */
5520 if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil)
5522 struct ns_display_info *di;
5523 BOOL has_focus = NO;
5524 for (di = x_display_list; ! has_focus && di; di = di->next)
5525 has_focus = di->x_focus_frame != 0;
5531 NSTRACE_UNSILENCE();
5533 [super sendEvent: theEvent];
5537 - (void)showPreferencesWindow: (id)sender
5539 struct frame *emacsframe = SELECTED_FRAME ();
5540 NSEvent *theEvent = [NSApp currentEvent];
5544 emacs_event->kind = NS_NONKEY_EVENT;
5545 emacs_event->code = KEY_NS_SHOW_PREFS;
5546 emacs_event->modifiers = 0;
5547 EV_TRAILER (theEvent);
5551 - (void)newFrame: (id)sender
5553 NSTRACE ("[EmacsApp newFrame:]");
5555 struct frame *emacsframe = SELECTED_FRAME ();
5556 NSEvent *theEvent = [NSApp currentEvent];
5560 emacs_event->kind = NS_NONKEY_EVENT;
5561 emacs_event->code = KEY_NS_NEW_FRAME;
5562 emacs_event->modifiers = 0;
5563 EV_TRAILER (theEvent);
5567 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5568 - (BOOL) openFile: (NSString *)fileName
5570 NSTRACE ("[EmacsApp openFile:]");
5572 struct frame *emacsframe = SELECTED_FRAME ();
5573 NSEvent *theEvent = [NSApp currentEvent];
5578 emacs_event->kind = NS_NONKEY_EVENT;
5579 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5580 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5581 ns_input_line = Qnil; /* can be start or cons start,end */
5582 emacs_event->modifiers =0;
5583 EV_TRAILER (theEvent);
5589 /* **************************************************************************
5591 EmacsApp delegate implementation
5593 ************************************************************************** */
5595 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5596 /* --------------------------------------------------------------------------
5597 When application is loaded, terminate event loop in ns_term_init
5598 -------------------------------------------------------------------------- */
5600 NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5602 #ifdef NS_IMPL_GNUSTEP
5603 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5605 [NSApp setServicesProvider: NSApp];
5607 [self antialiasThresholdDidChange:nil];
5608 #ifdef NS_IMPL_COCOA
5609 [[NSNotificationCenter defaultCenter]
5611 selector:@selector(antialiasThresholdDidChange:)
5612 name:NSAntialiasThresholdChangedNotification
5616 #ifdef NS_IMPL_COCOA
5617 if ([NSApp activationPolicy] == NSApplicationActivationPolicyProhibited) {
5618 /* Set the app's activation policy to regular when we run outside
5619 of a bundle. This is already done for us by Info.plist when we
5620 run inside a bundle. */
5621 [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
5622 [NSApp setApplicationIconImage:
5625 build_string("icons/hicolor/128x128/apps/emacs.png")]];
5629 ns_send_appdefined (-2);
5632 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5634 #ifdef NS_IMPL_COCOA
5635 macfont_update_antialias_threshold ();
5640 /* Termination sequences:
5643 MenuBar | File | Exit:
5644 Select Quit from App menubar:
5646 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5649 Select Quit from Dock menu:
5652 Cancel -> Nothing else
5656 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5661 - (void) terminate: (id)sender
5663 NSTRACE ("[EmacsApp terminate:]");
5665 struct frame *emacsframe = SELECTED_FRAME ();
5670 emacs_event->kind = NS_NONKEY_EVENT;
5671 emacs_event->code = KEY_NS_POWER_OFF;
5672 emacs_event->arg = Qt; /* mark as non-key event */
5673 EV_TRAILER ((id)nil);
5677 runAlertPanel(NSString *title,
5678 NSString *msgFormat,
5679 NSString *defaultButton,
5680 NSString *alternateButton)
5682 #ifdef NS_IMPL_GNUSTEP
5683 return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5684 == NSAlertDefaultReturn;
5686 NSAlert *alert = [[NSAlert alloc] init];
5687 [alert setAlertStyle: NSAlertStyleCritical];
5688 [alert setMessageText: msgFormat];
5689 [alert addButtonWithTitle: defaultButton];
5690 [alert addButtonWithTitle: alternateButton];
5691 NSInteger ret = [alert runModal];
5693 return ret == NSAlertFirstButtonReturn;
5698 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5700 NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5704 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
5705 return NSTerminateNow;
5707 ret = runAlertPanel(ns_app_name,
5708 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
5709 @"Save Buffers and Exit", @"Cancel");
5711 return ret ? NSTerminateNow : NSTerminateCancel;
5715 not_in_argv (NSString *arg)
5718 const char *a = [arg UTF8String];
5719 for (k = 1; k < initial_argc; ++k)
5720 if (strcmp (a, initial_argv[k]) == 0) return 0;
5724 /* Notification from the Workspace to open a file */
5725 - (BOOL)application: sender openFile: (NSString *)file
5727 if (ns_do_open_file || not_in_argv (file))
5728 [ns_pending_files addObject: file];
5733 /* Open a file as a temporary file */
5734 - (BOOL)application: sender openTempFile: (NSString *)file
5736 if (ns_do_open_file || not_in_argv (file))
5737 [ns_pending_files addObject: file];
5742 /* Notification from the Workspace to open a file noninteractively (?) */
5743 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5745 if (ns_do_open_file || not_in_argv (file))
5746 [ns_pending_files addObject: file];
5750 /* Notification from the Workspace to open multiple files */
5751 - (void)application: sender openFiles: (NSArray *)fileList
5753 NSEnumerator *files = [fileList objectEnumerator];
5755 /* Don't open files from the command line unconditionally,
5756 Cocoa parses the command line wrong, --option value tries to open value
5757 if --option is the last option. */
5758 while ((file = [files nextObject]) != nil)
5759 if (ns_do_open_file || not_in_argv (file))
5760 [ns_pending_files addObject: file];
5762 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5767 /* Handle dock menu requests. */
5768 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5774 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5775 - (void)applicationWillBecomeActive: (NSNotification *)notification
5777 NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5778 //ns_app_active=YES;
5781 - (void)applicationDidBecomeActive: (NSNotification *)notification
5783 NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5785 #ifdef NS_IMPL_GNUSTEP
5786 if (! applicationDidFinishLaunchingCalled)
5787 [self applicationDidFinishLaunching:notification];
5789 //ns_app_active=YES;
5791 ns_update_auto_hide_menu_bar ();
5792 // No constraining takes place when the application is not active.
5793 ns_constrain_all_frames ();
5795 - (void)applicationDidResignActive: (NSNotification *)notification
5797 NSTRACE ("[EmacsApp applicationDidResignActive:]");
5800 ns_send_appdefined (-1);
5805 /* ==========================================================================
5807 EmacsApp aux handlers for managing event loop
5809 ========================================================================== */
5812 - (void)timeout_handler: (NSTimer *)timedEntry
5813 /* --------------------------------------------------------------------------
5814 The timeout specified to ns_select has passed.
5815 -------------------------------------------------------------------------- */
5817 /*NSTRACE ("timeout_handler"); */
5818 ns_send_appdefined (-2);
5821 - (void)sendFromMainThread:(id)unused
5823 ns_send_appdefined (nextappdefined);
5826 - (void)fd_handler:(id)unused
5827 /* --------------------------------------------------------------------------
5828 Check data waiting on file descriptors and terminate if so
5829 -------------------------------------------------------------------------- */
5832 int waiting = 1, nfds;
5835 fd_set readfds, writefds, *wfds;
5836 struct timespec timeout, *tmo;
5837 NSAutoreleasePool *pool = nil;
5839 /* NSTRACE ("fd_handler"); */
5844 pool = [[NSAutoreleasePool alloc] init];
5850 FD_SET (selfds[0], &fds);
5851 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5852 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5857 pthread_mutex_lock (&select_mutex);
5860 if (select_valid & SELECT_HAVE_READ)
5861 readfds = select_readfds;
5865 if (select_valid & SELECT_HAVE_WRITE)
5867 writefds = select_writefds;
5872 if (select_valid & SELECT_HAVE_TMO)
5874 timeout = select_timeout;
5880 pthread_mutex_unlock (&select_mutex);
5882 FD_SET (selfds[0], &readfds);
5883 if (selfds[0] >= nfds) nfds = selfds[0]+1;
5885 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5888 ns_send_appdefined (-2);
5889 else if (result > 0)
5891 if (FD_ISSET (selfds[0], &readfds))
5893 if (read (selfds[0], &c, 1) == 1 && c == 's')
5898 pthread_mutex_lock (&select_mutex);
5899 if (select_valid & SELECT_HAVE_READ)
5900 select_readfds = readfds;
5901 if (select_valid & SELECT_HAVE_WRITE)
5902 select_writefds = writefds;
5903 if (select_valid & SELECT_HAVE_TMO)
5904 select_timeout = timeout;
5905 pthread_mutex_unlock (&select_mutex);
5907 ns_send_appdefined (result);
5917 /* ==========================================================================
5921 ========================================================================== */
5923 /* called from system: queue for next pass through event loop */
5924 - (void)requestService: (NSPasteboard *)pboard
5925 userData: (NSString *)userData
5926 error: (NSString **)error
5928 [ns_pending_service_names addObject: userData];
5929 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5930 SSDATA (ns_string_from_pasteboard (pboard))]];
5934 /* called from ns_read_socket to clear queue */
5935 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5937 struct frame *emacsframe = SELECTED_FRAME ();
5938 NSEvent *theEvent = [NSApp currentEvent];
5940 NSTRACE ("[EmacsApp fulfillService:withArg:]");
5945 emacs_event->kind = NS_NONKEY_EVENT;
5946 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5947 ns_input_spi_name = build_string ([name UTF8String]);
5948 ns_input_spi_arg = build_string ([arg UTF8String]);
5949 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5950 EV_TRAILER (theEvent);
5960 /* ==========================================================================
5962 EmacsView implementation
5964 ========================================================================== */
5967 @implementation EmacsView
5969 /* needed to inform when window closed from LISP */
5970 - (void) setWindowClosing: (BOOL)closing
5972 NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5974 windowClosing = closing;
5980 NSTRACE ("[EmacsView dealloc]");
5982 if (fs_state == FULLSCREEN_BOTH)
5983 [nonfs_window release];
5988 /* called on font panel selection */
5989 - (void)changeFont: (id)sender
5991 NSEvent *e = [[self window] currentEvent];
5992 struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID);
5993 struct font *font = face->font;
5998 NSTRACE ("[EmacsView changeFont:]");
6003 #ifdef NS_IMPL_GNUSTEP
6004 nsfont = ((struct nsfont_info *)font)->nsfont;
6006 #ifdef NS_IMPL_COCOA
6007 nsfont = (NSFont *) macfont_get_nsctfont (font);
6010 if ((newFont = [sender convertFont: nsfont]))
6012 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
6014 emacs_event->kind = NS_NONKEY_EVENT;
6015 emacs_event->modifiers = 0;
6016 emacs_event->code = KEY_NS_CHANGE_FONT;
6018 size = [newFont pointSize];
6019 ns_input_fontsize = make_number (lrint (size));
6020 ns_input_font = build_string ([[newFont familyName] UTF8String]);
6026 - (BOOL)acceptsFirstResponder
6028 NSTRACE ("[EmacsView acceptsFirstResponder]");
6033 - (void)resetCursorRects
6035 NSRect visible = [self visibleRect];
6036 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
6037 NSTRACE ("[EmacsView resetCursorRects]");
6039 if (currentCursor == nil)
6040 currentCursor = [NSCursor arrowCursor];
6042 if (!NSIsEmptyRect (visible))
6043 [self addCursorRect: visible cursor: currentCursor];
6044 [currentCursor setOnMouseEntered: YES];
6049 /*****************************************************************************/
6050 /* Keyboard handling. */
6053 - (void)keyDown: (NSEvent *)theEvent
6055 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6057 unsigned fnKeysym = 0;
6058 static NSMutableArray *nsEvArray;
6060 unsigned int flags = [theEvent modifierFlags];
6062 NSTRACE ("[EmacsView keyDown:]");
6064 /* Rhapsody and macOS give up and down events for the arrow keys */
6065 if (ns_fake_keydown == YES)
6066 ns_fake_keydown = NO;
6067 else if ([theEvent type] != NSEventTypeKeyDown)
6073 if (![[self window] isKeyWindow]
6074 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
6075 /* we must avoid an infinite loop here. */
6076 && (EmacsView *)[[theEvent window] delegate] != self)
6078 /* XXX: There is an occasional condition in which, when Emacs display
6079 updates a different frame from the current one, and temporarily
6080 selects it, then processes some interrupt-driven input
6081 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
6082 for some reason that window has its first responder set to the NSView
6083 most recently updated (I guess), which is not the correct one. */
6084 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
6088 if (nsEvArray == nil)
6089 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
6091 [NSCursor setHiddenUntilMouseMoves: YES];
6093 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
6095 clear_mouse_face (hlinfo);
6096 hlinfo->mouse_face_hidden = 1;
6099 if (!processingCompose)
6101 /* When using screen sharing, no left or right information is sent,
6102 so use Left key in those cases. */
6103 int is_left_key, is_right_key;
6105 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
6106 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
6108 /* (Carbon way: [theEvent keyCode]) */
6110 /* is it a "function key"? */
6111 /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad
6112 flag set (this is probably a bug in the OS).
6114 if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad))
6116 fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad);
6120 fnKeysym = ns_convert_key (code);
6125 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
6126 because Emacs treats Delete and KP-Delete same (in simple.el). */
6127 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
6128 #ifdef NS_IMPL_GNUSTEP
6129 /* GNUstep uses incompatible keycodes, even for those that are
6130 supposed to be hardware independent. Just check for delete.
6131 Keypad delete does not have keysym 0xFFFF.
6132 See https://savannah.gnu.org/bugs/?25395
6134 || (fnKeysym == 0xFFFF && code == 127)
6137 code = 0xFF08; /* backspace */
6142 /* are there modifiers? */
6143 emacs_event->modifiers = 0;
6145 if (flags & NSEventModifierFlagHelp)
6146 emacs_event->modifiers |= hyper_modifier;
6148 if (flags & NSEventModifierFlagShift)
6149 emacs_event->modifiers |= shift_modifier;
6151 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
6152 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
6153 || (! is_right_key && (flags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand);
6156 emacs_event->modifiers |= parse_solitary_modifier
6157 (EQ (ns_right_command_modifier, Qleft)
6158 ? ns_command_modifier
6159 : ns_right_command_modifier);
6163 emacs_event->modifiers |= parse_solitary_modifier
6164 (ns_command_modifier);
6166 /* if super (default), take input manager's word so things like
6167 dvorak / qwerty layout work */
6168 if (EQ (ns_command_modifier, Qsuper)
6170 && [[theEvent characters] length] != 0)
6172 /* XXX: the code we get will be unshifted, so if we have
6173 a shift modifier, must convert ourselves */
6174 if (!(flags & NSEventModifierFlagShift))
6175 code = [[theEvent characters] characterAtIndex: 0];
6177 /* this is ugly and also requires linking w/Carbon framework
6178 (for LMGetKbdType) so for now leave this rare (?) case
6179 undealt with.. in future look into CGEvent methods */
6182 long smv = GetScriptManagerVariable (smKeyScript);
6183 Handle uchrHandle = GetResource
6184 ('uchr', GetScriptVariable (smv, smScriptKeys));
6186 UCKeyTranslate ((UCKeyboardLayout *) *uchrHandle,
6187 [[theEvent characters] characterAtIndex: 0],
6188 kUCKeyActionDisplay,
6189 (flags & ~NSEventModifierFlagCommand) >> 8,
6190 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
6191 &dummy, 1, &dummy, &code);
6198 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
6199 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
6200 || (! is_right_key && (flags & NSEventModifierFlagControl) == NSEventModifierFlagControl);
6203 emacs_event->modifiers |= parse_solitary_modifier
6204 (EQ (ns_right_control_modifier, Qleft)
6205 ? ns_control_modifier
6206 : ns_right_control_modifier);
6209 emacs_event->modifiers |= parse_solitary_modifier
6210 (ns_control_modifier);
6212 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
6213 emacs_event->modifiers |=
6214 parse_solitary_modifier (ns_function_modifier);
6216 left_is_none = NILP (ns_alternate_modifier)
6217 || EQ (ns_alternate_modifier, Qnone);
6219 is_right_key = (flags & NSRightAlternateKeyMask)
6220 == NSRightAlternateKeyMask;
6221 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
6223 && (flags & NSEventModifierFlagOption) == NSEventModifierFlagOption);
6227 if ((NILP (ns_right_alternate_modifier)
6228 || EQ (ns_right_alternate_modifier, Qnone)
6229 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
6231 { /* accept pre-interp alt comb */
6232 if ([[theEvent characters] length] > 0)
6233 code = [[theEvent characters] characterAtIndex: 0];
6234 /*HACK: clear lone shift modifier to stop next if from firing */
6235 if (emacs_event->modifiers == shift_modifier)
6236 emacs_event->modifiers = 0;
6239 emacs_event->modifiers |= parse_solitary_modifier
6240 (EQ (ns_right_alternate_modifier, Qleft)
6241 ? ns_alternate_modifier
6242 : ns_right_alternate_modifier);
6245 if (is_left_key) /* default = meta */
6247 if (left_is_none && !fnKeysym)
6248 { /* accept pre-interp alt comb */
6249 if ([[theEvent characters] length] > 0)
6250 code = [[theEvent characters] characterAtIndex: 0];
6251 /*HACK: clear lone shift modifier to stop next if from firing */
6252 if (emacs_event->modifiers == shift_modifier)
6253 emacs_event->modifiers = 0;
6256 emacs_event->modifiers |=
6257 parse_solitary_modifier (ns_alternate_modifier);
6261 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6262 (unsigned) code, fnKeysym, flags, emacs_event->modifiers);
6264 /* if it was a function key or had modifiers, pass it directly to emacs */
6265 if (fnKeysym || (emacs_event->modifiers
6266 && (emacs_event->modifiers != shift_modifier)
6267 && [[theEvent charactersIgnoringModifiers] length] > 0))
6268 /*[[theEvent characters] length] */
6270 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6272 code |= (1<<28)|(3<<16);
6273 else if (code == 0x7f)
6274 code |= (1<<28)|(3<<16);
6276 emacs_event->kind = code > 0xFF
6277 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6279 emacs_event->code = code;
6280 EV_TRAILER (theEvent);
6281 processingCompose = NO;
6287 if (NS_KEYLOG && !processingCompose)
6288 fprintf (stderr, "keyDown: Begin compose sequence.\n");
6290 processingCompose = YES;
6291 [nsEvArray addObject: theEvent];
6292 [self interpretKeyEvents: nsEvArray];
6293 [nsEvArray removeObject: theEvent];
6297 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6300 /* <NSTextInput>: called when done composing;
6301 NOTE: also called when we delete over working text, followed immed.
6302 by doCommandBySelector: deleteBackward: */
6303 - (void)insertText: (id)aString
6308 NSTRACE ("[EmacsView insertText:]");
6310 if ([aString isKindOfClass:[NSAttributedString class]])
6311 s = [aString string];
6318 NSLog (@"insertText '%@'\tlen = %lu", aString, (unsigned long) len);
6319 processingCompose = NO;
6324 /* first, clear any working text */
6325 if (workingText != nil)
6326 [self deleteWorkingText];
6328 /* It might be preferable to use getCharacters:range: below,
6329 cf. https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CocoaPerformance/Articles/StringDrawing.html#//apple_ref/doc/uid/TP40001445-112378.
6330 However, we probably can't use SAFE_NALLOCA here because it might
6333 /* now insert the string as keystrokes */
6334 for (NSUInteger i = 0; i < len; i++)
6336 NSUInteger code = [s characterAtIndex:i];
6337 if (UTF_16_HIGH_SURROGATE_P (code) && i < len - 1)
6339 unichar low = [s characterAtIndex:i + 1];
6340 if (UTF_16_LOW_SURROGATE_P (low))
6342 code = surrogates_to_codepoint (low, code);
6346 /* TODO: still need this? */
6348 code = '~'; /* 0x7E */
6349 if (code != 32) /* Space */
6350 emacs_event->modifiers = 0;
6352 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6353 emacs_event->code = code;
6354 EV_TRAILER ((id)nil);
6359 /* <NSTextInput>: inserts display of composing characters */
6360 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6362 NSString *str = [aString respondsToSelector: @selector (string)] ?
6363 [aString string] : aString;
6365 NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6368 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6369 str, (unsigned long)[str length],
6370 (unsigned long)selRange.length,
6371 (unsigned long)selRange.location);
6373 if (workingText != nil)
6374 [self deleteWorkingText];
6375 if ([str length] == 0)
6381 processingCompose = YES;
6382 workingText = [str copy];
6383 ns_working_text = build_string ([workingText UTF8String]);
6385 emacs_event->kind = NS_TEXT_EVENT;
6386 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6387 EV_TRAILER ((id)nil);
6391 /* delete display of composing characters [not in <NSTextInput>] */
6392 - (void)deleteWorkingText
6394 NSTRACE ("[EmacsView deleteWorkingText]");
6396 if (workingText == nil)
6399 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6400 [workingText release];
6402 processingCompose = NO;
6407 emacs_event->kind = NS_TEXT_EVENT;
6408 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6409 EV_TRAILER ((id)nil);
6413 - (BOOL)hasMarkedText
6415 NSTRACE ("[EmacsView hasMarkedText]");
6417 return workingText != nil;
6421 - (NSRange)markedRange
6423 NSTRACE ("[EmacsView markedRange]");
6425 NSRange rng = workingText != nil
6426 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6428 NSLog (@"markedRange request");
6435 NSTRACE ("[EmacsView unmarkText]");
6438 NSLog (@"unmark (accept) text");
6439 [self deleteWorkingText];
6440 processingCompose = NO;
6444 /* used to position char selection windows, etc. */
6445 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6449 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6451 NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6454 NSLog (@"firstRectForCharRange request");
6456 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6457 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6458 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6459 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6460 +FRAME_LINE_HEIGHT (emacsframe));
6462 pt = [self convertPoint: pt toView: nil];
6464 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6465 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6466 if ([[self window] respondsToSelector: @selector(convertRectToScreen:)])
6470 rect = [(EmacsWindow *) [self window] convertRectToScreen: rect];
6471 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6475 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6476 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
6477 || defined (NS_IMPL_GNUSTEP)
6479 pt = [[self window] convertBaseToScreen: pt];
6488 - (NSInteger)conversationIdentifier
6490 return (NSInteger)self;
6494 - (void)doCommandBySelector: (SEL)aSelector
6496 NSTRACE ("[EmacsView doCommandBySelector:]");
6499 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6501 processingCompose = NO;
6502 if (aSelector == @selector (deleteBackward:))
6504 /* happens when user backspaces over an ongoing composition:
6505 throw a 'delete' into the event queue */
6508 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6509 emacs_event->code = 0xFF08;
6510 EV_TRAILER ((id)nil);
6514 - (NSArray *)validAttributesForMarkedText
6516 static NSArray *arr = nil;
6517 if (arr == nil) arr = [NSArray new];
6518 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6522 - (NSRange)selectedRange
6525 NSLog (@"selectedRange request");
6526 return NSMakeRange (NSNotFound, 0);
6529 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6530 GNUSTEP_GUI_MINOR_VERSION > 22
6531 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6533 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6537 NSLog (@"characterIndexForPoint request");
6541 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6543 static NSAttributedString *str = nil;
6544 if (str == nil) str = [NSAttributedString new];
6546 NSLog (@"attributedSubstringFromRange request");
6550 /* End <NSTextInput> impl. */
6551 /*****************************************************************************/
6554 /* This is what happens when the user presses a mouse button. */
6555 - (void)mouseDown: (NSEvent *)theEvent
6557 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6558 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6560 NSTRACE ("[EmacsView mouseDown:]");
6562 [self deleteWorkingText];
6567 dpyinfo->last_mouse_frame = emacsframe;
6568 /* appears to be needed to prevent spurious movement events generated on
6570 emacsframe->mouse_moved = 0;
6572 if ([theEvent type] == NSEventTypeScrollWheel)
6574 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6575 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6576 if ([theEvent respondsToSelector:@selector(hasPreciseScrollingDeltas)])
6579 /* If the input device is a touchpad or similar, use precise
6580 * scrolling deltas. These are measured in pixels, so we
6581 * have to add them up until they exceed one line height,
6582 * then we can send a scroll wheel event.
6584 * If the device only has coarse scrolling deltas, like a
6585 * real mousewheel, the deltas represent a ratio of whole
6586 * lines, so round up the number of lines. This means we
6587 * always send one scroll event per click, but can still
6588 * scroll more than one line if the OS tells us to.
6594 /* FIXME: At the top or bottom of the buffer we should
6595 * ignore momentum-phase events. */
6596 if (! ns_use_mwheel_momentum
6597 && [theEvent momentumPhase] != NSEventPhaseNone)
6600 if ([theEvent hasPreciseScrollingDeltas])
6602 static int totalDeltaX, totalDeltaY;
6605 if (NUMBERP (ns_mwheel_line_height))
6606 lineHeight = XINT (ns_mwheel_line_height);
6609 /* FIXME: Use actual line height instead of the default. */
6610 lineHeight = default_line_pixel_height
6611 (XWINDOW (FRAME_SELECTED_WINDOW (emacsframe)));
6614 if ([theEvent phase] == NSEventPhaseBegan)
6620 totalDeltaX += [theEvent scrollingDeltaX];
6621 totalDeltaY += [theEvent scrollingDeltaY];
6623 /* Calculate the number of lines, if any, to scroll, and
6624 * reset the total delta for the direction we're NOT
6625 * scrolling so that small movements don't add up. */
6626 if (abs (totalDeltaX) > abs (totalDeltaY)
6627 && abs (totalDeltaX) > lineHeight)
6630 scrollUp = totalDeltaX > 0;
6632 lines = abs (totalDeltaX / lineHeight);
6633 totalDeltaX = totalDeltaX % lineHeight;
6636 else if (abs (totalDeltaY) >= abs (totalDeltaX)
6637 && abs (totalDeltaY) > lineHeight)
6640 scrollUp = totalDeltaY > 0;
6642 lines = abs (totalDeltaY / lineHeight);
6643 totalDeltaY = totalDeltaY % lineHeight;
6647 if (lines > 1 && ! ns_use_mwheel_acceleration)
6654 if ([theEvent scrollingDeltaY] == 0)
6657 delta = [theEvent scrollingDeltaX];
6662 delta = [theEvent scrollingDeltaY];
6665 lines = (ns_use_mwheel_acceleration)
6666 ? ceil (fabs (delta)) : 1;
6668 scrollUp = delta > 0;
6674 emacs_event->kind = horizontal ? HORIZ_WHEEL_EVENT : WHEEL_EVENT;
6675 emacs_event->arg = (make_number (lines));
6677 emacs_event->code = 0;
6678 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6679 (scrollUp ? up_modifier : down_modifier);
6680 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6684 #endif /* defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6685 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6687 CGFloat delta = [theEvent deltaY];
6688 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6691 delta = [theEvent deltaX];
6694 NSTRACE_MSG ("deltaIsZero");
6697 emacs_event->kind = HORIZ_WHEEL_EVENT;
6700 emacs_event->kind = WHEEL_EVENT;
6702 emacs_event->code = 0;
6703 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6704 ((delta > 0) ? up_modifier : down_modifier);
6710 emacs_event->kind = MOUSE_CLICK_EVENT;
6711 emacs_event->code = EV_BUTTON (theEvent);
6712 emacs_event->modifiers = EV_MODIFIERS (theEvent)
6713 | EV_UDMODIFIERS (theEvent);
6716 XSETINT (emacs_event->x, lrint (p.x));
6717 XSETINT (emacs_event->y, lrint (p.y));
6718 EV_TRAILER (theEvent);
6723 - (void)rightMouseDown: (NSEvent *)theEvent
6725 NSTRACE ("[EmacsView rightMouseDown:]");
6726 [self mouseDown: theEvent];
6730 - (void)otherMouseDown: (NSEvent *)theEvent
6732 NSTRACE ("[EmacsView otherMouseDown:]");
6733 [self mouseDown: theEvent];
6737 - (void)mouseUp: (NSEvent *)theEvent
6739 NSTRACE ("[EmacsView mouseUp:]");
6740 [self mouseDown: theEvent];
6744 - (void)rightMouseUp: (NSEvent *)theEvent
6746 NSTRACE ("[EmacsView rightMouseUp:]");
6747 [self mouseDown: theEvent];
6751 - (void)otherMouseUp: (NSEvent *)theEvent
6753 NSTRACE ("[EmacsView otherMouseUp:]");
6754 [self mouseDown: theEvent];
6758 - (void) scrollWheel: (NSEvent *)theEvent
6760 NSTRACE ("[EmacsView scrollWheel:]");
6761 [self mouseDown: theEvent];
6765 /* Tell emacs the mouse has moved. */
6766 - (void)mouseMoved: (NSEvent *)e
6768 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6769 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6773 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6775 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6776 pt = [self convertPoint: [e locationInWindow] fromView: nil];
6777 dpyinfo->last_mouse_motion_x = pt.x;
6778 dpyinfo->last_mouse_motion_y = pt.y;
6780 /* update any mouse face */
6781 if (hlinfo->mouse_face_hidden)
6783 hlinfo->mouse_face_hidden = 0;
6784 clear_mouse_face (hlinfo);
6787 /* tooltip handling */
6788 previous_help_echo_string = help_echo_string;
6789 help_echo_string = Qnil;
6791 if (!NILP (Vmouse_autoselect_window))
6793 NSTRACE_MSG ("mouse_autoselect_window");
6794 static Lisp_Object last_mouse_window;
6796 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6798 if (WINDOWP (window)
6799 && !EQ (window, last_mouse_window)
6800 && !EQ (window, selected_window)
6801 && (!NILP (focus_follows_mouse)
6802 || (EQ (XWINDOW (window)->frame,
6803 XWINDOW (selected_window)->frame))))
6805 NSTRACE_MSG ("in_window");
6806 emacs_event->kind = SELECT_WINDOW_EVENT;
6807 emacs_event->frame_or_window = window;
6810 /* Remember the last window where we saw the mouse. */
6811 last_mouse_window = window;
6814 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6815 help_echo_string = previous_help_echo_string;
6817 XSETFRAME (frame, emacsframe);
6818 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6820 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6821 (note_mouse_highlight), which is called through the
6822 note_mouse_movement () call above */
6823 any_help_event_p = YES;
6824 gen_help_event (help_echo_string, frame, help_echo_window,
6825 help_echo_object, help_echo_pos);
6828 if (emacsframe->mouse_moved && send_appdefined)
6829 ns_send_appdefined (-1);
6833 - (void)mouseDragged: (NSEvent *)e
6835 NSTRACE ("[EmacsView mouseDragged:]");
6836 [self mouseMoved: e];
6840 - (void)rightMouseDragged: (NSEvent *)e
6842 NSTRACE ("[EmacsView rightMouseDragged:]");
6843 [self mouseMoved: e];
6847 - (void)otherMouseDragged: (NSEvent *)e
6849 NSTRACE ("[EmacsView otherMouseDragged:]");
6850 [self mouseMoved: e];
6854 - (BOOL)windowShouldClose: (id)sender
6856 NSEvent *e =[[self window] currentEvent];
6858 NSTRACE ("[EmacsView windowShouldClose:]");
6859 windowClosing = YES;
6862 emacs_event->kind = DELETE_WINDOW_EVENT;
6863 emacs_event->modifiers = 0;
6864 emacs_event->code = 0;
6866 /* Don't close this window, let this be done from lisp code. */
6870 - (void) updateFrameSize: (BOOL) delay
6872 NSWindow *window = [self window];
6873 NSRect wr = [window frame];
6875 int oldc = cols, oldr = rows;
6876 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6877 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6880 NSTRACE ("[EmacsView updateFrameSize:]");
6881 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6882 NSTRACE_RECT ("Original frame", wr);
6883 NSTRACE_MSG ("Original columns: %d", cols);
6884 NSTRACE_MSG ("Original rows: %d", rows);
6886 if (! [self isFullscreen])
6889 #ifdef NS_IMPL_GNUSTEP
6890 // GNUstep does not always update the tool bar height. Force it.
6891 if (toolbar && [toolbar isVisible])
6892 update_frame_tool_bar (emacsframe);
6895 toolbar_height = FRAME_TOOLBAR_HEIGHT (emacsframe);
6896 if (toolbar_height < 0)
6897 toolbar_height = 35;
6899 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6903 if (wait_for_tool_bar)
6905 /* The toolbar height is always 0 in fullscreen and undecorated
6906 frames, so don't wait for it to become available. */
6907 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0
6908 && FRAME_UNDECORATED (emacsframe) == false
6909 && ! [self isFullscreen])
6911 NSTRACE_MSG ("Waiting for toolbar");
6914 wait_for_tool_bar = NO;
6917 neww = (int)wr.size.width - emacsframe->border_width;
6918 newh = (int)wr.size.height - extra;
6920 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6921 NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
6922 NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
6924 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6925 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6927 if (cols < MINWIDTH)
6930 if (rows < MINHEIGHT)
6933 NSTRACE_MSG ("New columns: %d", cols);
6934 NSTRACE_MSG ("New rows: %d", rows);
6936 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6938 NSView *view = FRAME_NS_VIEW (emacsframe);
6940 change_frame_size (emacsframe,
6941 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6942 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6944 SET_FRAME_GARBAGED (emacsframe);
6945 cancel_mouse_face (emacsframe);
6947 /* The next two lines set the frame to the same size as we've
6948 already set above. We need to do this when we switch back
6949 from non-native fullscreen, in other circumstances it appears
6950 to be a noop. (bug#28872) */
6951 wr = NSMakeRect (0, 0, neww, newh);
6952 [view setFrame: wr];
6954 // to do: consider using [NSNotificationCenter postNotificationName:].
6955 [self windowDidMove: // Update top/left.
6956 [NSNotification notificationWithName:NSWindowDidMoveNotification
6957 object:[view window]]];
6961 NSTRACE_MSG ("No change");
6965 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6966 /* normalize frame to gridded text size */
6970 NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6971 NSTRACE_ARG_SIZE (frameSize));
6972 NSTRACE_RECT ("[sender frame]", [sender frame]);
6973 NSTRACE_FSTYPE ("fs_state", fs_state);
6975 if (!FRAME_LIVE_P (emacsframe))
6978 if (fs_state == FULLSCREEN_MAXIMIZED
6979 && (maximized_width != (int)frameSize.width
6980 || maximized_height != (int)frameSize.height))
6981 [self setFSValue: FULLSCREEN_NONE];
6982 else if (fs_state == FULLSCREEN_WIDTH
6983 && maximized_width != (int)frameSize.width)
6984 [self setFSValue: FULLSCREEN_NONE];
6985 else if (fs_state == FULLSCREEN_HEIGHT
6986 && maximized_height != (int)frameSize.height)
6987 [self setFSValue: FULLSCREEN_NONE];
6989 if (fs_state == FULLSCREEN_NONE)
6990 maximized_width = maximized_height = -1;
6992 if (! [self isFullscreen])
6994 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6995 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6998 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6999 if (cols < MINWIDTH)
7002 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
7003 frameSize.height - extra);
7004 if (rows < MINHEIGHT)
7006 #ifdef NS_IMPL_COCOA
7008 /* this sets window title to have size in it; the wm does this under GS */
7009 NSRect r = [[self window] frame];
7010 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
7018 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
7019 && [[self window] title] != NULL)
7022 NSWindow *window = [self window];
7025 char *t = strdup ([[[self window] title] UTF8String]);
7026 char *pos = strstr (t, " — ");
7031 size_title = xmalloc (strlen (old_title) + 40);
7032 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
7033 [window setTitle: [NSString stringWithUTF8String: size_title]];
7037 #endif /* NS_IMPL_COCOA */
7039 NSTRACE_MSG ("cols: %d rows: %d", cols, rows);
7041 /* Restrict the new size to the text gird.
7043 Don't restrict the width if the user only adjusted the height, and
7044 vice versa. (Without this, the frame would shrink, and move
7045 slightly, if the window was resized by dragging one of its
7047 if (!frame_resize_pixelwise)
7049 NSRect r = [[self window] frame];
7051 if (r.size.width != frameSize.width)
7054 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
7057 if (r.size.height != frameSize.height)
7060 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
7064 NSTRACE_RETURN_SIZE (frameSize);
7070 - (void)windowDidResize: (NSNotification *)notification
7072 NSTRACE ("[EmacsView windowDidResize:]");
7073 if (!FRAME_LIVE_P (emacsframe))
7075 NSTRACE_MSG ("Ignored (frame dead)");
7078 if (emacsframe->output_data.ns->in_animation)
7080 NSTRACE_MSG ("Ignored (in animation)");
7084 if (! [self fsIsNative])
7086 NSWindow *theWindow = [notification object];
7087 /* We can get notification on the non-FS window when in
7089 if ([self window] != theWindow) return;
7092 NSTRACE_RECT ("frame", [[notification object] frame]);
7094 #ifdef NS_IMPL_GNUSTEP
7095 NSWindow *theWindow = [notification object];
7097 /* In GNUstep, at least currently, it's possible to get a didResize
7098 without getting a willResize.. therefore we need to act as if we got
7099 the willResize now */
7100 NSSize sz = [theWindow frame].size;
7101 sz = [self windowWillResize: theWindow toSize: sz];
7102 #endif /* NS_IMPL_GNUSTEP */
7104 if (cols > 0 && rows > 0)
7106 [self updateFrameSize: YES];
7109 ns_send_appdefined (-1);
7112 #ifdef NS_IMPL_COCOA
7113 - (void)viewDidEndLiveResize
7115 NSTRACE ("[EmacsView viewDidEndLiveResize]");
7117 [super viewDidEndLiveResize];
7120 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
7124 maximizing_resize = NO;
7126 #endif /* NS_IMPL_COCOA */
7129 - (void)windowDidBecomeKey: (NSNotification *)notification
7130 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
7132 [self windowDidBecomeKey];
7136 - (void)windowDidBecomeKey /* for direct calls */
7138 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7139 struct frame *old_focus = dpyinfo->x_focus_frame;
7141 NSTRACE ("[EmacsView windowDidBecomeKey]");
7143 if (emacsframe != old_focus)
7144 dpyinfo->x_focus_frame = emacsframe;
7146 ns_frame_rehighlight (emacsframe);
7150 emacs_event->kind = FOCUS_IN_EVENT;
7151 EV_TRAILER ((id)nil);
7156 - (void)windowDidResignKey: (NSNotification *)notification
7157 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
7159 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7160 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
7161 NSTRACE ("[EmacsView windowDidResignKey:]");
7164 dpyinfo->x_focus_frame = 0;
7166 emacsframe->mouse_moved = 0;
7167 ns_frame_rehighlight (emacsframe);
7169 /* FIXME: for some reason needed on second and subsequent clicks away
7170 from sole-frame Emacs to get hollow box to show */
7171 if (!windowClosing && [[self window] isVisible] == YES)
7173 x_update_cursor (emacsframe, 1);
7174 x_set_frame_alpha (emacsframe);
7177 if (any_help_event_p)
7180 XSETFRAME (frame, emacsframe);
7181 help_echo_string = Qnil;
7182 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
7185 if (emacs_event && is_focus_frame)
7187 [self deleteWorkingText];
7188 emacs_event->kind = FOCUS_OUT_EVENT;
7189 EV_TRAILER ((id)nil);
7194 - (void)windowWillMiniaturize: sender
7196 NSTRACE ("[EmacsView windowWillMiniaturize:]");
7200 - (void)setFrame:(NSRect)frameRect
7202 NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
7203 NSTRACE_ARG_RECT (frameRect));
7205 [super setFrame:(NSRect)frameRect];
7221 - (void)createToolbar: (struct frame *)f
7223 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
7224 NSWindow *window = [view window];
7226 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
7227 [NSString stringWithFormat: @"Emacs Frame %d",
7229 [toolbar setVisible: NO];
7230 [window setToolbar: toolbar];
7232 /* Don't set frame garbaged until tool bar is up to date?
7233 This avoids an extra clear and redraw (flicker) at frame creation. */
7234 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
7235 else wait_for_tool_bar = NO;
7238 #ifdef NS_IMPL_COCOA
7240 NSButton *toggleButton;
7241 toggleButton = [window standardWindowButton: NSWindowToolbarButton];
7242 [toggleButton setTarget: self];
7243 [toggleButton setAction: @selector (toggleToolbar: )];
7249 - (instancetype) initFrameFromEmacs: (struct frame *)f
7257 NSTRACE ("[EmacsView initFrameFromEmacs:]");
7258 NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
7261 processingCompose = NO;
7262 scrollbarsNeedingUpdate = 0;
7263 fs_state = FULLSCREEN_NONE;
7264 fs_before_fs = next_maximized = -1;
7267 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7268 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7269 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7271 fs_is_native = ns_use_native_fullscreen;
7274 maximized_width = maximized_height = -1;
7277 ns_userRect = NSMakeRect (0, 0, 0, 0);
7278 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
7279 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
7280 [self initWithFrame: r];
7281 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
7283 FRAME_NS_VIEW (f) = self;
7285 #ifdef NS_IMPL_COCOA
7287 maximizing_resize = NO;
7290 win = [[EmacsWindow alloc]
7291 initWithContentRect: r
7292 styleMask: (FRAME_UNDECORATED (f)
7293 ? FRAME_UNDECORATED_FLAGS
7294 : FRAME_DECORATED_FLAGS)
7295 backing: NSBackingStoreBuffered
7298 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7299 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7300 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7302 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
7306 bwidth = f->border_width = wr.size.width - r.size.width;
7308 [win setAcceptsMouseMovedEvents: YES];
7309 [win setDelegate: self];
7310 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7311 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7312 if ([win respondsToSelector: @selector(useOptimizedDrawing:)])
7314 [win useOptimizedDrawing: YES];
7317 [[win contentView] addSubview: self];
7320 [self registerForDraggedTypes: ns_drag_types];
7323 name = [NSString stringWithUTF8String:
7324 NILP (tem) ? "Emacs" : SSDATA (tem)];
7325 [win setTitle: name];
7327 /* toolbar support */
7328 if (! FRAME_UNDECORATED (f))
7329 [self createToolbar: f];
7331 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7332 #ifndef NSAppKitVersionNumber10_10
7333 #define NSAppKitVersionNumber10_10 1343
7336 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_10
7337 && FRAME_NS_APPEARANCE (f) != ns_appearance_aqua)
7338 win.appearance = [NSAppearance
7339 appearanceNamed: NSAppearanceNameVibrantDark];
7342 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7343 if ([win respondsToSelector: @selector(titlebarAppearsTransparent)])
7344 win.titlebarAppearsTransparent = FRAME_NS_TRANSPARENT_TITLEBAR (f);
7349 [win setMiniwindowTitle:
7350 [NSString stringWithUTF8String: SSDATA (tem)]];
7352 if (FRAME_PARENT_FRAME (f) != NULL)
7354 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
7355 [parent addChildWindow: win
7356 ordered: NSWindowAbove];
7359 if (FRAME_Z_GROUP (f) != z_group_none)
7360 win.level = NSNormalWindowLevel
7361 + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
7364 NSScreen *screen = [win screen];
7368 NSPoint pt = NSMakePoint
7369 (IN_BOUND (-SCREENMAX, f->left_pos
7370 + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7371 IN_BOUND (-SCREENMAX,
7372 NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7375 [win setFrameTopLeftPoint: pt];
7377 NSTRACE_RECT ("new frame", [win frame]);
7381 [win makeFirstResponder: self];
7383 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7384 (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7386 [win setBackgroundColor: col];
7387 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7388 [win setOpaque: NO];
7390 #if !defined (NS_IMPL_COCOA) \
7391 || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7392 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7393 if ([self respondsToSelector: @selector(allocateGState)])
7395 [self allocateGState];
7397 [NSApp registerServicesMenuSendTypes: ns_send_types
7398 returnTypes: [NSArray array]];
7400 /* macOS Sierra automatically enables tabbed windows. We can't
7401 allow this to be enabled until it's available on a Free system.
7402 Currently it only happens by accident and is buggy anyway. */
7403 #if defined (NS_IMPL_COCOA) \
7404 && MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
7405 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
7406 if ([win respondsToSelector: @selector(setTabbingMode:)])
7408 [win setTabbingMode: NSWindowTabbingModeDisallowed];
7416 - (void)windowDidMove: sender
7418 NSWindow *win = [self window];
7419 NSRect r = [win frame];
7420 NSArray *screens = [NSScreen screens];
7421 NSScreen *screen = [screens objectAtIndex: 0];
7423 NSTRACE ("[EmacsView windowDidMove:]");
7425 if (!emacsframe->output_data.ns)
7429 emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7430 emacsframe->top_pos =
7431 NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7435 emacs_event->kind = MOVE_FRAME_EVENT;
7436 EV_TRAILER ((id)nil);
7442 /* Called AFTER method below, but before our windowWillResize call there leads
7443 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
7444 location so set_window_size moves the frame. */
7445 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7447 NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7448 NSTRACE_FMT_RETURN "YES"),
7449 NSTRACE_ARG_RECT (newFrame));
7451 emacsframe->output_data.ns->zooming = 1;
7456 /* Override to do something slightly nonstandard, but nice. First click on
7457 zoom button will zoom vertically. Second will zoom completely. Third
7458 returns to original. */
7459 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7460 defaultFrame:(NSRect)defaultFrame
7462 // TODO: Rename to "currentFrame" and assign "result" properly in
7464 NSRect result = [sender frame];
7466 NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7467 NSTRACE_FMT_RECT "]"),
7468 NSTRACE_ARG_RECT (defaultFrame));
7469 NSTRACE_FSTYPE ("fs_state", fs_state);
7470 NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7471 NSTRACE_FSTYPE ("next_maximized", next_maximized);
7472 NSTRACE_RECT ("ns_userRect", ns_userRect);
7473 NSTRACE_RECT ("[sender frame]", [sender frame]);
7475 if (fs_before_fs != -1) /* Entering fullscreen */
7477 NSTRACE_MSG ("Entering fullscreen");
7478 result = defaultFrame;
7482 // Save the window size and position (frame) before the resize.
7483 if (fs_state != FULLSCREEN_MAXIMIZED
7484 && fs_state != FULLSCREEN_WIDTH)
7486 ns_userRect.size.width = result.size.width;
7487 ns_userRect.origin.x = result.origin.x;
7490 if (fs_state != FULLSCREEN_MAXIMIZED
7491 && fs_state != FULLSCREEN_HEIGHT)
7493 ns_userRect.size.height = result.size.height;
7494 ns_userRect.origin.y = result.origin.y;
7497 NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7499 if (next_maximized == FULLSCREEN_HEIGHT
7500 || (next_maximized == -1
7501 && abs ((int)(defaultFrame.size.height - result.size.height))
7502 > FRAME_LINE_HEIGHT (emacsframe)))
7505 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7506 maximized_height = result.size.height = defaultFrame.size.height;
7507 maximized_width = -1;
7508 result.origin.y = defaultFrame.origin.y;
7509 if (ns_userRect.size.height != 0)
7511 result.origin.x = ns_userRect.origin.x;
7512 result.size.width = ns_userRect.size.width;
7514 [self setFSValue: FULLSCREEN_HEIGHT];
7515 #ifdef NS_IMPL_COCOA
7516 maximizing_resize = YES;
7519 else if (next_maximized == FULLSCREEN_WIDTH)
7521 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7522 maximized_width = result.size.width = defaultFrame.size.width;
7523 maximized_height = -1;
7524 result.origin.x = defaultFrame.origin.x;
7525 if (ns_userRect.size.width != 0)
7527 result.origin.y = ns_userRect.origin.y;
7528 result.size.height = ns_userRect.size.height;
7530 [self setFSValue: FULLSCREEN_WIDTH];
7532 else if (next_maximized == FULLSCREEN_MAXIMIZED
7533 || (next_maximized == -1
7534 && abs ((int)(defaultFrame.size.width - result.size.width))
7535 > FRAME_COLUMN_WIDTH (emacsframe)))
7537 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7539 result = defaultFrame; /* second click */
7540 maximized_width = result.size.width;
7541 maximized_height = result.size.height;
7542 [self setFSValue: FULLSCREEN_MAXIMIZED];
7543 #ifdef NS_IMPL_COCOA
7544 maximizing_resize = YES;
7550 NSTRACE_MSG ("Restore");
7551 result = ns_userRect.size.height ? ns_userRect : result;
7552 NSTRACE_RECT ("restore (2)", result);
7553 ns_userRect = NSMakeRect (0, 0, 0, 0);
7554 #ifdef NS_IMPL_COCOA
7555 maximizing_resize = fs_state != FULLSCREEN_NONE;
7557 [self setFSValue: FULLSCREEN_NONE];
7558 maximized_width = maximized_height = -1;
7562 if (fs_before_fs == -1) next_maximized = -1;
7564 NSTRACE_RECT ("Final ns_userRect", ns_userRect);
7565 NSTRACE_MSG ("Final maximized_width: %d", maximized_width);
7566 NSTRACE_MSG ("Final maximized_height: %d", maximized_height);
7567 NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7569 [self windowWillResize: sender toSize: result.size];
7571 NSTRACE_RETURN_RECT (result);
7577 - (void)windowDidDeminiaturize: sender
7579 NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7580 if (!emacsframe->output_data.ns)
7583 SET_FRAME_ICONIFIED (emacsframe, 0);
7584 SET_FRAME_VISIBLE (emacsframe, 1);
7585 windows_or_buffers_changed = 63;
7589 emacs_event->kind = DEICONIFY_EVENT;
7590 EV_TRAILER ((id)nil);
7595 - (void)windowDidExpose: sender
7597 NSTRACE ("[EmacsView windowDidExpose:]");
7598 if (!emacsframe->output_data.ns)
7601 SET_FRAME_VISIBLE (emacsframe, 1);
7602 SET_FRAME_GARBAGED (emacsframe);
7604 if (send_appdefined)
7605 ns_send_appdefined (-1);
7609 - (void)windowDidMiniaturize: sender
7611 NSTRACE ("[EmacsView windowDidMiniaturize:]");
7612 if (!emacsframe->output_data.ns)
7615 SET_FRAME_ICONIFIED (emacsframe, 1);
7616 SET_FRAME_VISIBLE (emacsframe, 0);
7620 emacs_event->kind = ICONIFY_EVENT;
7621 EV_TRAILER ((id)nil);
7625 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7626 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7627 willUseFullScreenPresentationOptions:
7628 (NSApplicationPresentationOptions)proposedOptions
7630 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7634 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7636 NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7637 [self windowWillEnterFullScreen];
7639 - (void)windowWillEnterFullScreen /* provided for direct calls */
7641 NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7642 fs_before_fs = fs_state;
7645 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7647 NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7648 [self windowDidEnterFullScreen];
7651 - (void)windowDidEnterFullScreen /* provided for direct calls */
7653 NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7654 [self setFSValue: FULLSCREEN_BOTH];
7655 if (! [self fsIsNative])
7657 [self windowDidBecomeKey];
7658 [nonfs_window orderOut:self];
7662 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7663 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \
7664 && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
7665 unsigned val = (unsigned)[NSApp presentationOptions];
7667 // Mac OS X 10.7 bug fix, the menu won't appear without this.
7668 // val is non-zero on other macOS versions.
7671 NSApplicationPresentationOptions options
7672 = NSApplicationPresentationAutoHideDock
7673 | NSApplicationPresentationAutoHideMenuBar
7674 | NSApplicationPresentationFullScreen
7675 | NSApplicationPresentationAutoHideToolbar;
7677 [NSApp setPresentationOptions: options];
7680 [toolbar setVisible:tbar_visible];
7684 - (void)windowWillExitFullScreen:(NSNotification *)notification
7686 NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7687 [self windowWillExitFullScreen];
7690 - (void)windowWillExitFullScreen /* provided for direct calls */
7692 NSTRACE ("[EmacsView windowWillExitFullScreen]");
7693 if (!FRAME_LIVE_P (emacsframe))
7695 NSTRACE_MSG ("Ignored (frame dead)");
7698 if (next_maximized != -1)
7699 fs_before_fs = next_maximized;
7702 - (void)windowDidExitFullScreen:(NSNotification *)notification
7704 NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7705 [self windowDidExitFullScreen];
7708 - (void)windowDidExitFullScreen /* provided for direct calls */
7710 NSTRACE ("[EmacsView windowDidExitFullScreen]");
7711 if (!FRAME_LIVE_P (emacsframe))
7713 NSTRACE_MSG ("Ignored (frame dead)");
7716 [self setFSValue: fs_before_fs];
7718 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7719 [self updateCollectionBehavior];
7721 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7723 [toolbar setVisible:YES];
7724 update_frame_tool_bar (emacsframe);
7725 [self updateFrameSize:YES];
7726 [[self window] display];
7729 [toolbar setVisible:NO];
7731 if (next_maximized != -1)
7732 [[self window] performZoom:self];
7737 return fs_is_native;
7740 - (BOOL)isFullscreen
7746 res = (nonfs_window != nil);
7750 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7751 res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7757 NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7763 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7764 - (void)updateCollectionBehavior
7766 NSTRACE ("[EmacsView updateCollectionBehavior]");
7768 if (! [self isFullscreen])
7770 NSWindow *win = [self window];
7771 NSWindowCollectionBehavior b = [win collectionBehavior];
7772 if (ns_use_native_fullscreen)
7773 b |= NSWindowCollectionBehaviorFullScreenPrimary;
7775 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7777 [win setCollectionBehavior: b];
7778 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7779 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7781 fs_is_native = ns_use_native_fullscreen;
7786 - (void)toggleFullScreen: (id)sender
7794 NSTRACE ("[EmacsView toggleFullScreen:]");
7798 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7799 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7800 if ([[self window] respondsToSelector: @selector(toggleFullScreen:)])
7802 [[self window] toggleFullScreen:sender];
7808 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7811 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7812 (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7815 if (fs_state != FULLSCREEN_BOTH)
7817 NSScreen *screen = [w screen];
7819 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
7820 /* Hide ghost menu bar on secondary monitor? */
7822 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
7823 && [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)]
7826 onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7828 /* Hide dock and menubar if we are on the primary screen. */
7831 #ifdef NS_IMPL_COCOA
7832 NSApplicationPresentationOptions options
7833 = NSApplicationPresentationAutoHideDock
7834 | NSApplicationPresentationAutoHideMenuBar;
7836 [NSApp setPresentationOptions: options];
7838 [NSMenu setMenuBarVisible:NO];
7842 fw = [[EmacsFSWindow alloc]
7843 initWithContentRect:[w contentRectForFrameRect:wr]
7844 styleMask:NSWindowStyleMaskBorderless
7845 backing:NSBackingStoreBuffered
7849 [fw setContentView:[w contentView]];
7850 [fw setTitle:[w title]];
7851 [fw setDelegate:self];
7852 [fw setAcceptsMouseMovedEvents: YES];
7853 #if !defined (NS_IMPL_COCOA) \
7854 || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7855 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7856 if ([fw respondsToSelector: @selector(useOptimizedDrawing:)])
7858 [fw useOptimizedDrawing: YES];
7860 [fw setBackgroundColor: col];
7861 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7864 f->border_width = 0;
7868 [self windowWillEnterFullScreen];
7869 [fw makeKeyAndOrderFront:NSApp];
7870 [fw makeFirstResponder:self];
7872 r = [fw frameRectForContentRect:[screen frame]];
7873 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7874 [self windowDidEnterFullScreen];
7885 #ifdef NS_IMPL_COCOA
7886 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7888 [NSMenu setMenuBarVisible:YES];
7892 [w setContentView:[fw contentView]];
7893 [w setBackgroundColor: col];
7894 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7897 f->border_width = bwidth;
7899 // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7901 [self windowWillExitFullScreen];
7902 [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7904 [w makeKeyAndOrderFront:NSApp];
7905 [self windowDidExitFullScreen];
7906 [self updateFrameSize:YES];
7912 NSTRACE ("[EmacsView handleFS]");
7914 if (fs_state != emacsframe->want_fullscreen)
7916 if (fs_state == FULLSCREEN_BOTH)
7918 NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7919 [self toggleFullScreen:self];
7922 switch (emacsframe->want_fullscreen)
7924 case FULLSCREEN_BOTH:
7925 NSTRACE_MSG ("FULLSCREEN_BOTH");
7926 [self toggleFullScreen:self];
7928 case FULLSCREEN_WIDTH:
7929 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7930 next_maximized = FULLSCREEN_WIDTH;
7931 if (fs_state != FULLSCREEN_BOTH)
7932 [[self window] performZoom:self];
7934 case FULLSCREEN_HEIGHT:
7935 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7936 next_maximized = FULLSCREEN_HEIGHT;
7937 if (fs_state != FULLSCREEN_BOTH)
7938 [[self window] performZoom:self];
7940 case FULLSCREEN_MAXIMIZED:
7941 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7942 next_maximized = FULLSCREEN_MAXIMIZED;
7943 if (fs_state != FULLSCREEN_BOTH)
7944 [[self window] performZoom:self];
7946 case FULLSCREEN_NONE:
7947 NSTRACE_MSG ("FULLSCREEN_NONE");
7948 if (fs_state != FULLSCREEN_BOTH)
7950 next_maximized = FULLSCREEN_NONE;
7951 [[self window] performZoom:self];
7956 emacsframe->want_fullscreen = FULLSCREEN_NONE;
7961 - (void) setFSValue: (int)value
7963 NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7964 NSTRACE_ARG_FSTYPE(value));
7966 Lisp_Object lval = Qnil;
7969 case FULLSCREEN_BOTH:
7972 case FULLSCREEN_WIDTH:
7975 case FULLSCREEN_HEIGHT:
7978 case FULLSCREEN_MAXIMIZED:
7982 store_frame_param (emacsframe, Qfullscreen, lval);
7986 - (void)mouseEntered: (NSEvent *)theEvent
7988 NSTRACE ("[EmacsView mouseEntered:]");
7990 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7991 = EV_TIMESTAMP (theEvent);
7995 - (void)mouseExited: (NSEvent *)theEvent
7997 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7999 NSTRACE ("[EmacsView mouseExited:]");
8004 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
8005 = EV_TIMESTAMP (theEvent);
8007 if (emacsframe == hlinfo->mouse_face_mouse_frame)
8009 clear_mouse_face (hlinfo);
8010 hlinfo->mouse_face_mouse_frame = 0;
8015 - (instancetype)menuDown: sender
8017 NSTRACE ("[EmacsView menuDown:]");
8018 if (context_menu_value == -1)
8019 context_menu_value = [sender tag];
8022 NSInteger tag = [sender tag];
8023 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
8024 emacsframe->menu_bar_vector,
8028 ns_send_appdefined (-1);
8033 - (EmacsToolbar *)toolbar
8039 /* this gets called on toolbar button click */
8040 - (instancetype)toolbarClicked: (id)item
8043 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
8045 NSTRACE ("[EmacsView toolbarClicked:]");
8050 /* send first event (for some reason two needed) */
8051 theEvent = [[self window] currentEvent];
8052 emacs_event->kind = TOOL_BAR_EVENT;
8053 XSETFRAME (emacs_event->arg, emacsframe);
8054 EV_TRAILER (theEvent);
8056 emacs_event->kind = TOOL_BAR_EVENT;
8057 /* XSETINT (emacs_event->code, 0); */
8058 emacs_event->arg = AREF (emacsframe->tool_bar_items,
8059 idx + TOOL_BAR_ITEM_KEY);
8060 emacs_event->modifiers = EV_MODIFIERS (theEvent);
8061 EV_TRAILER (theEvent);
8066 - (instancetype)toggleToolbar: (id)sender
8068 NSTRACE ("[EmacsView toggleToolbar:]");
8073 emacs_event->kind = NS_NONKEY_EVENT;
8074 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
8075 EV_TRAILER ((id)nil);
8080 - (void)viewWillDraw
8082 /* If the frame has been garbaged there's no point in redrawing
8084 if (FRAME_GARBAGED_P (emacsframe))
8085 [self setNeedsDisplay:NO];
8088 - (void)drawRect: (NSRect)rect
8090 const NSRect *rectList;
8093 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
8094 NSTRACE_ARG_RECT(rect));
8096 if (!emacsframe || !emacsframe->output_data.ns)
8101 /* Get only the precise dirty rectangles to avoid redrawing
8102 potentially large areas of the frame that haven't changed.
8104 I'm not sure this actually provides much of a performance benefit
8105 as it's hard to benchmark, but it certainly doesn't seem to
8107 [self getRectsBeingDrawn:&rectList count:&numRects];
8108 for (int i = 0 ; i < numRects ; i++)
8110 NSRect r = rectList[i];
8112 NSTRACE_RECT ("r", r);
8114 expose_frame (emacsframe,
8115 NSMinX (r), NSMinY (r),
8116 NSWidth (r), NSHeight (r));
8122 drawRect: may be called (at least in Mac OS X 10.5) for invisible
8123 views as well for some reason. Thus, do not infer visibility
8126 emacsframe->async_visible = 1;
8127 emacsframe->async_iconified = 0;
8132 /* NSDraggingDestination protocol methods. Actually this is not really a
8133 protocol, but a category of Object. O well... */
8135 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
8137 NSTRACE ("[EmacsView draggingEntered:]");
8138 return NSDragOperationGeneric;
8142 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
8148 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
8153 NSEvent *theEvent = [[self window] currentEvent];
8155 NSDragOperation op = [sender draggingSourceOperationMask];
8158 NSTRACE ("[EmacsView performDragOperation:]");
8163 position = [self convertPoint: [sender draggingLocation] fromView: nil];
8164 x = lrint (position.x); y = lrint (position.y);
8166 pb = [sender draggingPasteboard];
8167 type = [pb availableTypeFromArray: ns_drag_types];
8169 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
8170 // URL drags contain all operations (0xf), don't allow all to be set.
8173 if (op & NSDragOperationLink)
8174 modifiers |= NSEventModifierFlagControl;
8175 if (op & NSDragOperationCopy)
8176 modifiers |= NSEventModifierFlagOption;
8177 if (op & NSDragOperationGeneric)
8178 modifiers |= NSEventModifierFlagCommand;
8181 modifiers = EV_MODIFIERS2 (modifiers);
8186 else if ([type isEqualToString: NSFilenamesPboardType])
8189 NSEnumerator *fenum;
8192 if (!(files = [pb propertyListForType: type]))
8195 fenum = [files objectEnumerator];
8196 while ( (file = [fenum nextObject]) )
8198 emacs_event->kind = DRAG_N_DROP_EVENT;
8199 XSETINT (emacs_event->x, x);
8200 XSETINT (emacs_event->y, y);
8201 emacs_event->modifiers = modifiers;
8202 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
8203 EV_TRAILER (theEvent);
8207 else if ([type isEqualToString: NSURLPboardType])
8209 NSURL *url = [NSURL URLFromPasteboard: pb];
8210 if (url == nil) return NO;
8212 emacs_event->kind = DRAG_N_DROP_EVENT;
8213 XSETINT (emacs_event->x, x);
8214 XSETINT (emacs_event->y, y);
8215 emacs_event->modifiers = modifiers;
8216 emacs_event->arg = list2 (Qurl,
8217 build_string ([[url absoluteString]
8219 EV_TRAILER (theEvent);
8221 if ([url isFileURL] != NO)
8223 NSString *file = [url path];
8224 ns_input_file = append2 (ns_input_file,
8225 build_string ([file UTF8String]));
8229 else if ([type isEqualToString: NSStringPboardType]
8230 || [type isEqualToString: NSTabularTextPboardType])
8234 if (! (data = [pb stringForType: type]))
8237 emacs_event->kind = DRAG_N_DROP_EVENT;
8238 XSETINT (emacs_event->x, x);
8239 XSETINT (emacs_event->y, y);
8240 emacs_event->modifiers = modifiers;
8241 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
8242 EV_TRAILER (theEvent);
8247 fprintf (stderr, "Invalid data type in dragging pasteboard");
8253 - (id) validRequestorForSendType: (NSString *)typeSent
8254 returnType: (NSString *)typeReturned
8256 NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
8257 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
8258 && typeReturned == nil)
8260 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
8264 return [super validRequestorForSendType: typeSent
8265 returnType: typeReturned];
8269 /* The next two methods are part of NSServicesRequests informal protocol,
8270 supposedly called when a services menu item is chosen from this app.
8271 But this should not happen because we override the services menu with our
8272 own entries which call ns-perform-service.
8273 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
8274 So let's at least stub them out until further investigation can be done. */
8276 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
8278 /* we could call ns_string_from_pasteboard(pboard) here but then it should
8279 be written into the buffer in place of the existing selection..
8280 ordinary service calls go through functions defined in ns-win.el */
8284 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
8286 NSArray *typesDeclared;
8289 NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
8291 /* We only support NSStringPboardType */
8292 if ([types containsObject:NSStringPboardType] == NO) {
8296 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8297 if (CONSP (val) && SYMBOLP (XCAR (val)))
8300 if (CONSP (val) && NILP (XCDR (val)))
8303 if (! STRINGP (val))
8306 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
8307 [pb declareTypes:typesDeclared owner:nil];
8308 ns_string_to_pasteboard (pb, val);
8313 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
8314 (gives a miniaturized version of the window); currently we use the latter for
8315 frames whose active buffer doesn't correspond to any file
8316 (e.g., '*scratch*') */
8317 - (instancetype)setMiniwindowImage: (BOOL) setMini
8319 id image = [[self window] miniwindowImage];
8320 NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
8322 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
8323 about "AppleDockIconEnabled" notwithstanding, however the set message
8324 below has its effect nonetheless. */
8325 if (image != emacsframe->output_data.ns->miniimage)
8327 if (image && [image isKindOfClass: [EmacsImage class]])
8329 [[self window] setMiniwindowImage:
8330 setMini ? emacsframe->output_data.ns->miniimage : nil];
8337 - (void) setRows: (int) r andColumns: (int) c
8339 NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
8344 - (int) fullscreenState
8349 @end /* EmacsView */
8353 /* ==========================================================================
8355 EmacsWindow implementation
8357 ========================================================================== */
8359 @implementation EmacsWindow
8361 #ifdef NS_IMPL_COCOA
8362 - (id)accessibilityAttributeValue:(NSString *)attribute
8364 Lisp_Object str = Qnil;
8365 struct frame *f = SELECTED_FRAME ();
8366 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
8368 NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
8370 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
8371 return NSAccessibilityTextFieldRole;
8373 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
8374 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
8376 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8378 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
8380 if (! NILP (BVAR (curbuf, mark_active)))
8381 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8385 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
8386 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
8387 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
8389 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
8390 str = make_uninit_multibyte_string (range, byte_range);
8392 str = make_uninit_string (range);
8393 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
8394 Is this a problem? */
8395 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
8402 if (CONSP (str) && SYMBOLP (XCAR (str)))
8405 if (CONSP (str) && NILP (XCDR (str)))
8410 const char *utfStr = SSDATA (str);
8411 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8416 return [super accessibilityAttributeValue:attribute];
8418 #endif /* NS_IMPL_COCOA */
8420 /* Constrain size and placement of a frame.
8422 By returning the original "frameRect", the frame is not
8423 constrained. This can lead to unwanted situations where, for
8424 example, the menu bar covers the frame.
8426 The default implementation (accessed using "super") constrains the
8427 frame to the visible area of SCREEN, minus the menu bar (if
8428 present) and the Dock. Note that default implementation also calls
8429 windowWillResize, with the frame it thinks should have. (This can
8430 make the frame exit maximized mode.)
8432 Note that this should work in situations where multiple monitors
8433 are present. Common configurations are side-by-side monitors and a
8434 monitor on top of another (e.g. when a laptop is placed under a
8436 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8438 NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8439 NSTRACE_ARG_RECT (frameRect));
8441 #ifdef NS_IMPL_COCOA
8442 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
8443 // If separate spaces is on, it is like each screen is independent. There is
8444 // no spanning of frames across screens.
8446 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
8447 [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)] &&
8449 [NSScreen screensHaveSeparateSpaces])
8451 NSTRACE_MSG ("Screens have separate spaces");
8452 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8453 NSTRACE_RETURN_RECT (frameRect);
8457 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */
8459 // Check that the proposed frameRect is visible in at least one
8460 // screen. If it is not, ask the system to reposition it (only
8461 // for non-child windows).
8463 if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe))
8465 NSArray *screens = [NSScreen screens];
8466 NSUInteger nr_screens = [screens count];
8469 BOOL frame_on_screen = NO;
8471 for (i = 0; i < nr_screens; ++i)
8473 NSScreen *s = [screens objectAtIndex: i];
8474 NSRect scrRect = [s frame];
8476 if (NSIntersectsRect(frameRect, scrRect))
8478 frame_on_screen = YES;
8483 if (!frame_on_screen)
8485 NSTRACE_MSG ("Frame outside screens; constraining");
8486 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8487 NSTRACE_RETURN_RECT (frameRect);
8493 return constrain_frame_rect(frameRect,
8494 [(EmacsView *)[self delegate] isFullscreen]);
8498 - (void)performZoom:(id)sender
8500 NSTRACE ("[EmacsWindow performZoom:]");
8502 return [super performZoom:sender];
8505 - (void)zoom:(id)sender
8507 NSTRACE ("[EmacsWindow zoom:]");
8509 ns_update_auto_hide_menu_bar();
8511 // Below are three zoom implementations. In the final commit, the
8512 // idea is that the last should be included.
8515 // Native zoom done using the standard zoom animation. Size of the
8516 // resulting frame reduced to accommodate the Dock and, if present,
8518 [super zoom:sender];
8521 // Native zoom done using the standard zoom animation, plus an
8522 // explicit resize to cover the full screen, except the menu-bar and
8523 // dock, if present.
8524 [super zoom:sender];
8526 // After the native zoom, resize the resulting frame to fill the
8527 // entire screen, except the menu-bar.
8529 // This works for all practical purposes. (The only minor oddity is
8530 // when transiting from full-height frame to a maximized, the
8531 // animation reduces the height of the frame slightly (to the 4
8532 // pixels needed to accommodate the Doc) before it snaps back into
8533 // full height. The user would need a very trained eye to spot
8535 NSScreen * screen = [self screen];
8538 int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8540 NSTRACE_FSTYPE ("fullscreenState", fs_state);
8542 NSRect sr = [screen frame];
8543 struct EmacsMargins margins
8544 = ns_screen_margins_ignoring_hidden_dock(screen);
8546 NSRect wr = [self frame];
8547 NSTRACE_RECT ("Rect after zoom", wr);
8551 if (fs_state == FULLSCREEN_MAXIMIZED
8552 || fs_state == FULLSCREEN_HEIGHT)
8554 newWr.origin.y = sr.origin.y + margins.bottom;
8555 newWr.size.height = sr.size.height - margins.top - margins.bottom;
8558 if (fs_state == FULLSCREEN_MAXIMIZED
8559 || fs_state == FULLSCREEN_WIDTH)
8561 newWr.origin.x = sr.origin.x + margins.left;
8562 newWr.size.width = sr.size.width - margins.right - margins.left;
8565 if (newWr.size.width != wr.size.width
8566 || newWr.size.height != wr.size.height
8567 || newWr.origin.x != wr.origin.x
8568 || newWr.origin.y != wr.origin.y)
8570 NSTRACE_MSG ("New frame different");
8571 [self setFrame: newWr display: NO];
8575 // Non-native zoom which is done instantaneously. The resulting
8576 // frame covers the entire screen, except the menu-bar and dock, if
8578 NSScreen * screen = [self screen];
8581 NSRect sr = [screen frame];
8582 struct EmacsMargins margins
8583 = ns_screen_margins_ignoring_hidden_dock(screen);
8585 sr.size.height -= (margins.top + margins.bottom);
8586 sr.size.width -= (margins.left + margins.right);
8587 sr.origin.x += margins.left;
8588 sr.origin.y += margins.bottom;
8590 sr = [[self delegate] windowWillUseStandardFrame:self
8592 [self setFrame: sr display: NO];
8597 - (void)setFrame:(NSRect)windowFrame
8598 display:(BOOL)displayViews
8600 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8601 NSTRACE_ARG_RECT (windowFrame), displayViews);
8603 [super setFrame:windowFrame display:displayViews];
8606 - (void)setFrame:(NSRect)windowFrame
8607 display:(BOOL)displayViews
8608 animate:(BOOL)performAnimation
8610 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8611 " display:%d performAnimation:%d]",
8612 NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8614 [super setFrame:windowFrame display:displayViews animate:performAnimation];
8617 - (void)setFrameTopLeftPoint:(NSPoint)point
8619 NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8620 NSTRACE_ARG_POINT (point));
8622 [super setFrameTopLeftPoint:point];
8625 - (BOOL)canBecomeKeyWindow
8627 return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8629 @end /* EmacsWindow */
8632 @implementation EmacsFSWindow
8634 - (BOOL)canBecomeKeyWindow
8639 - (BOOL)canBecomeMainWindow
8646 /* ==========================================================================
8648 EmacsScroller implementation
8650 ========================================================================== */
8653 @implementation EmacsScroller
8655 /* for repeat button push */
8656 #define SCROLL_BAR_FIRST_DELAY 0.5
8657 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8659 + (CGFloat) scrollerWidth
8661 /* TODO: if we want to allow variable widths, this is the place to do it,
8662 however neither GNUstep nor Cocoa support it very well */
8664 #if defined (NS_IMPL_COCOA) \
8665 && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
8666 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8667 if ([NSScroller respondsToSelector:
8668 @selector(scrollerWidthForControlSize:scrollerStyle:)])
8670 r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8671 scrollerStyle: NSScrollerStyleLegacy];
8672 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8675 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
8676 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
8677 || defined (NS_IMPL_GNUSTEP)
8678 r = [NSScroller scrollerWidth];
8683 - (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin
8685 NSTRACE ("[EmacsScroller initFrame: window:]");
8687 if (r.size.width > r.size.height)
8692 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8693 [self setContinuous: YES];
8694 [self setEnabled: YES];
8696 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8697 locked against the top and bottom edges, and right edge on macOS, where
8698 scrollers are on right. */
8699 #ifdef NS_IMPL_GNUSTEP
8700 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8702 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8705 window = XWINDOW (nwin);
8708 pixel_length = NSWidth (r);
8710 pixel_length = NSHeight (r);
8711 if (pixel_length == 0) pixel_length = 1;
8712 min_portion = 20 / pixel_length;
8714 frame = XFRAME (window->frame);
8715 if (FRAME_LIVE_P (frame))
8718 EmacsView *view = FRAME_NS_VIEW (frame);
8719 NSView *sview = [[view window] contentView];
8720 NSArray *subs = [sview subviews];
8722 /* disable optimization stopping redraw of other scrollbars */
8723 view->scrollbarsNeedingUpdate = 0;
8724 for (i =[subs count]-1; i >= 0; i--)
8725 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8726 view->scrollbarsNeedingUpdate++;
8727 [sview addSubview: self];
8730 /* [self setFrame: r]; */
8736 - (void)setFrame: (NSRect)newRect
8738 NSTRACE ("[EmacsScroller setFrame:]");
8740 /* block_input (); */
8742 pixel_length = NSWidth (newRect);
8744 pixel_length = NSHeight (newRect);
8745 if (pixel_length == 0) pixel_length = 1;
8746 min_portion = 20 / pixel_length;
8747 [super setFrame: newRect];
8748 /* unblock_input (); */
8754 NSTRACE ("[EmacsScroller dealloc]");
8758 wset_horizontal_scroll_bar (window, Qnil);
8760 wset_vertical_scroll_bar (window, Qnil);
8767 - (instancetype)condemn
8769 NSTRACE ("[EmacsScroller condemn]");
8775 - (instancetype)reprieve
8777 NSTRACE ("[EmacsScroller reprieve]");
8785 NSTRACE ("[EmacsScroller judge]");
8786 bool ret = condemned;
8791 /* ensure other scrollbar updates after deletion */
8792 view = (EmacsView *)FRAME_NS_VIEW (frame);
8794 view->scrollbarsNeedingUpdate++;
8798 wset_horizontal_scroll_bar (window, Qnil);
8800 wset_vertical_scroll_bar (window, Qnil);
8803 [self removeFromSuperview];
8811 - (void)resetCursorRects
8813 NSRect visible = [self visibleRect];
8814 NSTRACE ("[EmacsScroller resetCursorRects]");
8816 if (!NSIsEmptyRect (visible))
8817 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8818 [[NSCursor arrowCursor] setOnMouseEntered: YES];
8822 - (int) checkSamePosition: (int) position portion: (int) portion
8825 return em_position ==position && em_portion ==portion && em_whole ==whole
8826 && portion != whole; /* needed for resize empty buf */
8830 - (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole
8832 NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8834 em_position = position;
8835 em_portion = portion;
8838 if (portion >= whole)
8840 #ifdef NS_IMPL_COCOA
8841 [self setKnobProportion: 1.0];
8842 [self setDoubleValue: 1.0];
8844 [self setFloatValue: 0.0 knobProportion: 1.0];
8851 portion = max ((float)whole*min_portion/pixel_length, portion);
8852 pos = (float)position / (whole - portion);
8853 por = (CGFloat)portion/whole;
8854 #ifdef NS_IMPL_COCOA
8855 [self setKnobProportion: por];
8856 [self setDoubleValue: pos];
8858 [self setFloatValue: pos knobProportion: por];
8865 /* set up emacs_event */
8866 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8870 NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8875 emacs_event->part = last_hit_part;
8876 emacs_event->code = 0;
8877 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8878 XSETWINDOW (win, window);
8879 emacs_event->frame_or_window = win;
8880 emacs_event->timestamp = EV_TIMESTAMP (e);
8881 emacs_event->arg = Qnil;
8885 emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8886 XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8887 XSETINT (emacs_event->y, em_whole);
8891 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8892 XSETINT (emacs_event->x, loc);
8893 XSETINT (emacs_event->y, pixel_length-20);
8898 n_emacs_events_pending++;
8899 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8902 hold_event (emacs_event);
8903 EVENT_INIT (*emacs_event);
8904 ns_send_appdefined (-1);
8908 /* called manually thru timer to implement repeated button action w/hold-down */
8909 - (instancetype)repeatScroll: (NSTimer *)scrollEntry
8911 NSEvent *e = [[self window] currentEvent];
8912 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
8913 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8915 NSTRACE ("[EmacsScroller repeatScroll:]");
8917 /* clear timer if need be */
8918 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8920 [scroll_repeat_entry invalidate];
8921 [scroll_repeat_entry release];
8922 scroll_repeat_entry = nil;
8928 = [[NSTimer scheduledTimerWithTimeInterval:
8929 SCROLL_BAR_CONTINUOUS_DELAY
8931 selector: @selector (repeatScroll:)
8937 [self sendScrollEventAtLoc: 0 fromEvent: e];
8942 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
8943 mouseDragged events without going into a modal loop. */
8944 - (void)mouseDown: (NSEvent *)e
8947 /* hitPart is only updated AFTER event is passed on */
8948 NSScrollerPart part = [self testPart: [e locationInWindow]];
8949 CGFloat loc, kloc, pos UNINIT;
8952 NSTRACE ("[EmacsScroller mouseDown:]");
8956 case NSScrollerDecrementPage:
8957 last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
8958 case NSScrollerIncrementPage:
8959 last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
8960 case NSScrollerDecrementLine:
8961 last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
8962 case NSScrollerIncrementLine:
8963 last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
8964 case NSScrollerKnob:
8965 last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
8966 case NSScrollerKnobSlot: /* GNUstep-only */
8967 last_hit_part = scroll_bar_move_ratio; break;
8968 default: /* NSScrollerNoPart? */
8969 fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
8974 if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
8976 /* handle, or on GNUstep possibly slot */
8977 NSEvent *fake_event;
8980 /* compute float loc in slot and mouse offset on knob */
8981 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8985 length = NSWidth (sr);
8986 loc = ([e locationInWindow].x - NSMinX (sr));
8990 length = NSHeight (sr);
8991 loc = length - ([e locationInWindow].y - NSMinY (sr));
8999 else if (loc >= length)
9009 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
9012 kloc = ([e locationInWindow].x - NSMinX (kr));
9014 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
9016 last_mouse_offset = kloc;
9018 /* if knob, tell emacs a location offset by knob pos
9019 (to indicate top of handle) */
9020 if (part == NSScrollerKnob)
9021 pos = (loc - last_mouse_offset);
9023 /* else this is a slot click on GNUstep: go straight there */
9026 /* If there are buttons in the scroller area, we need to
9027 recalculate pos as emacs expects the scroller slot to take up
9028 the entire available length. */
9029 if (length != pixel_length)
9030 pos = pos * pixel_length / length;
9032 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
9033 fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
9034 location: [e locationInWindow]
9035 modifierFlags: [e modifierFlags]
9036 timestamp: [e timestamp]
9037 windowNumber: [e windowNumber]
9039 eventNumber: [e eventNumber]
9040 clickCount: [e clickCount]
9041 pressure: [e pressure]];
9042 [super mouseUp: fake_event];
9046 pos = 0; /* ignored */
9048 /* set a timer to repeat, as we can't let superclass do this modally */
9050 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
9052 selector: @selector (repeatScroll:)
9058 if (part != NSScrollerKnob)
9059 [self sendScrollEventAtLoc: pos fromEvent: e];
9063 /* Called as we manually track scroller drags, rather than superclass. */
9064 - (void)mouseDragged: (NSEvent *)e
9070 NSTRACE ("[EmacsScroller mouseDragged:]");
9072 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
9077 length = NSWidth (sr);
9078 loc = ([e locationInWindow].x - NSMinX (sr));
9082 length = NSHeight (sr);
9083 loc = length - ([e locationInWindow].y - NSMinY (sr));
9090 else if (loc >= length + last_mouse_offset)
9092 loc = length + last_mouse_offset;
9095 pos = (loc - last_mouse_offset);
9097 /* If there are buttons in the scroller area, we need to
9098 recalculate pos as emacs expects the scroller slot to take up
9099 the entire available length. */
9100 if (length != pixel_length)
9101 pos = pos * pixel_length / length;
9103 [self sendScrollEventAtLoc: pos fromEvent: e];
9107 - (void)mouseUp: (NSEvent *)e
9109 NSTRACE ("[EmacsScroller mouseUp:]");
9111 if (scroll_repeat_entry)
9113 [scroll_repeat_entry invalidate];
9114 [scroll_repeat_entry release];
9115 scroll_repeat_entry = nil;
9117 last_hit_part = scroll_bar_above_handle;
9121 /* treat scrollwheel events in the bar as though they were in the main window */
9122 - (void) scrollWheel: (NSEvent *)theEvent
9124 NSTRACE ("[EmacsScroller scrollWheel:]");
9126 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
9127 [view mouseDown: theEvent];
9130 @end /* EmacsScroller */
9133 #ifdef NS_IMPL_GNUSTEP
9134 /* Dummy class to get rid of startup warnings. */
9135 @implementation EmacsDocument
9141 /* ==========================================================================
9143 Font-related functions; these used to be in nsfaces.m
9145 ========================================================================== */
9149 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
9151 struct font *font = XFONT_OBJECT (font_object);
9152 EmacsView *view = FRAME_NS_VIEW (f);
9153 int font_ascent, font_descent;
9156 fontset = fontset_from_font (font_object);
9157 FRAME_FONTSET (f) = fontset;
9159 if (FRAME_FONT (f) == font)
9160 /* This font is already set in frame F. There's nothing more to
9164 FRAME_FONT (f) = font;
9166 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
9167 FRAME_COLUMN_WIDTH (f) = font->average_width;
9168 get_font_ascent_descent (font, &font_ascent, &font_descent);
9169 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
9171 /* Compute the scroll bar width in character columns. */
9172 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
9174 int wid = FRAME_COLUMN_WIDTH (f);
9175 FRAME_CONFIG_SCROLL_BAR_COLS (f)
9176 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
9180 int wid = FRAME_COLUMN_WIDTH (f);
9181 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
9184 /* Compute the scroll bar height in character lines. */
9185 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
9187 int height = FRAME_LINE_HEIGHT (f);
9188 FRAME_CONFIG_SCROLL_BAR_LINES (f)
9189 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
9193 int height = FRAME_LINE_HEIGHT (f);
9194 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
9197 /* Now make the frame display the given font. */
9198 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
9199 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
9200 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
9207 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
9208 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
9212 ns_xlfd_to_fontname (const char *xlfd)
9213 /* --------------------------------------------------------------------------
9214 Convert an X font name (XLFD) to an NS font name.
9215 Only family is used.
9216 The string returned is temporarily allocated.
9217 -------------------------------------------------------------------------- */
9219 char *name = xmalloc (180);
9223 if (!strncmp (xlfd, "--", 2))
9224 sscanf (xlfd, "--%*[^-]-%179[^-]-", name);
9226 sscanf (xlfd, "-%*[^-]-%179[^-]-", name);
9228 /* stopgap for malformed XLFD input */
9229 if (strlen (name) == 0)
9230 strcpy (name, "Monaco");
9232 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
9233 also uppercase after '-' or ' ' */
9234 name[0] = c_toupper (name[0]);
9235 for (len =strlen (name), i =0; i<len; i++)
9241 name[i+1] = c_toupper (name[i+1]);
9243 else if (name[i] == '_')
9247 name[i+1] = c_toupper (name[i+1]);
9250 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
9251 ret = [[NSString stringWithUTF8String: name] UTF8String];
9258 syms_of_nsterm (void)
9260 NSTRACE ("syms_of_nsterm");
9262 ns_antialias_threshold = 10.0;
9264 /* from 23+ we need to tell emacs what modifiers there are.. */
9265 DEFSYM (Qmodifier_value, "modifier-value");
9266 DEFSYM (Qalt, "alt");
9267 DEFSYM (Qhyper, "hyper");
9268 DEFSYM (Qmeta, "meta");
9269 DEFSYM (Qsuper, "super");
9270 DEFSYM (Qcontrol, "control");
9271 DEFSYM (QUTF8_STRING, "UTF8_STRING");
9273 DEFSYM (Qfile, "file");
9274 DEFSYM (Qurl, "url");
9276 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
9277 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
9278 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
9279 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
9280 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
9282 DEFVAR_LISP ("ns-input-file", ns_input_file,
9283 "The file specified in the last NS event.");
9284 ns_input_file =Qnil;
9286 DEFVAR_LISP ("ns-working-text", ns_working_text,
9287 "String for visualizing working composition sequence.");
9288 ns_working_text =Qnil;
9290 DEFVAR_LISP ("ns-input-font", ns_input_font,
9291 "The font specified in the last NS event.");
9292 ns_input_font =Qnil;
9294 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
9295 "The fontsize specified in the last NS event.");
9296 ns_input_fontsize =Qnil;
9298 DEFVAR_LISP ("ns-input-line", ns_input_line,
9299 "The line specified in the last NS event.");
9300 ns_input_line =Qnil;
9302 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
9303 "The service name specified in the last NS event.");
9304 ns_input_spi_name =Qnil;
9306 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
9307 "The service argument specified in the last NS event.");
9308 ns_input_spi_arg =Qnil;
9310 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
9311 "This variable describes the behavior of the alternate or option key.\n\
9312 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9314 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9315 at all, allowing it to be used at a lower level for accented character entry.");
9316 ns_alternate_modifier = Qmeta;
9318 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
9319 "This variable describes the behavior of the right alternate or option key.\n\
9320 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9322 Set to left means be the same key as `ns-alternate-modifier'.\n\
9323 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9324 at all, allowing it to be used at a lower level for accented character entry.");
9325 ns_right_alternate_modifier = Qleft;
9327 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
9328 "This variable describes the behavior of the command key.\n\
9329 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9331 ns_command_modifier = Qsuper;
9333 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
9334 "This variable describes the behavior of the right command key.\n\
9335 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9337 Set to left means be the same key as `ns-command-modifier'.\n\
9338 Set to none means that the command / option key is not interpreted by Emacs\n\
9339 at all, allowing it to be used at a lower level for accented character entry.");
9340 ns_right_command_modifier = Qleft;
9342 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
9343 "This variable describes the behavior of the control key.\n\
9344 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9346 ns_control_modifier = Qcontrol;
9348 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
9349 "This variable describes the behavior of the right control key.\n\
9350 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9352 Set to left means be the same key as `ns-control-modifier'.\n\
9353 Set to none means that the control / option key is not interpreted by Emacs\n\
9354 at all, allowing it to be used at a lower level for accented character entry.");
9355 ns_right_control_modifier = Qleft;
9357 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
9358 "This variable describes the behavior of the function key (on laptops).\n\
9359 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9361 Set to none means that the function key is not interpreted by Emacs at all,\n\
9362 allowing it to be used at a lower level for accented character entry.");
9363 ns_function_modifier = Qnone;
9365 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
9366 "Non-nil (the default) means to render text antialiased.");
9367 ns_antialias_text = Qt;
9369 DEFVAR_LISP ("ns-use-thin-smoothing", ns_use_thin_smoothing,
9370 "Non-nil turns on a font smoothing method that produces thinner strokes.");
9371 ns_use_thin_smoothing = Qnil;
9373 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
9374 "Whether to confirm application quit using dialog.");
9375 ns_confirm_quit = Qnil;
9377 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
9378 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
9379 Only works on Mac OS X 10.6 or later. */);
9380 ns_auto_hide_menu_bar = Qnil;
9382 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
9383 doc: /*Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
9384 Nil means use fullscreen the old (< 10.7) way. The old way works better with
9385 multiple monitors, but lacks tool bar. This variable is ignored on
9386 Mac OS X < 10.7. Default is t. */);
9387 ns_use_native_fullscreen = YES;
9388 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
9390 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
9391 doc: /*Non-nil means use animation on non-native fullscreen.
9392 For native fullscreen, this does nothing.
9393 Default is nil. */);
9394 ns_use_fullscreen_animation = NO;
9396 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
9397 doc: /*Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
9398 Note that this does not apply to images.
9399 This variable is ignored on Mac OS X < 10.7 and GNUstep. */);
9400 ns_use_srgb_colorspace = YES;
9402 DEFVAR_BOOL ("ns-use-mwheel-acceleration",
9403 ns_use_mwheel_acceleration,
9404 doc: /*Non-nil means use macOS's standard mouse wheel acceleration.
9405 This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */);
9406 ns_use_mwheel_acceleration = YES;
9408 DEFVAR_LISP ("ns-mwheel-line-height", ns_mwheel_line_height,
9409 doc: /*The number of pixels touchpad scrolling considers one line.
9410 Nil or a non-number means use the default frame line height.
9411 This variable is ignored on macOS < 10.7 and GNUstep. Default is nil. */);
9412 ns_mwheel_line_height = Qnil;
9414 DEFVAR_BOOL ("ns-use-mwheel-momentum", ns_use_mwheel_momentum,
9415 doc: /*Non-nil means mouse wheel scrolling uses momentum.
9416 This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */);
9417 ns_use_mwheel_momentum = YES;
9419 /* TODO: move to common code */
9420 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
9421 doc: /* Which toolkit scroll bars Emacs uses, if any.
9422 A value of nil means Emacs doesn't use toolkit scroll bars.
9423 With the X Window system, the value is a symbol describing the
9424 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
9425 With MS Windows or Nextstep, the value is t. */);
9426 Vx_toolkit_scroll_bars = Qt;
9428 DEFVAR_BOOL ("x-use-underline-position-properties",
9429 x_use_underline_position_properties,
9430 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
9431 A value of nil means ignore them. If you encounter fonts with bogus
9432 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
9433 to 4.1, set this to nil. */);
9434 x_use_underline_position_properties = 0;
9436 DEFVAR_BOOL ("x-underline-at-descent-line",
9437 x_underline_at_descent_line,
9438 doc: /* Non-nil means to draw the underline at the same place as the descent line.
9439 (If `line-spacing' is in effect, that moves the underline lower by
9441 A value of nil means to draw the underline according to the value of the
9442 variable `x-use-underline-position-properties', which is usually at the
9443 baseline level. The default value is nil. */);
9444 x_underline_at_descent_line = 0;
9446 /* Tell Emacs about this window system. */
9447 Fprovide (Qns, Qnil);
9449 DEFSYM (Qcocoa, "cocoa");
9450 DEFSYM (Qgnustep, "gnustep");
9452 #ifdef NS_IMPL_COCOA
9453 Fprovide (Qcocoa, Qnil);
9456 Fprovide (Qgnustep, Qnil);