1 /* NeXT/Open/GNUstep / macOS communication module. -*- coding: utf-8 -*-
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2017 Free Software
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or (at
11 your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30 interpretation of even the system includes. */
36 #include <sys/types.h>
42 #include <c-strcase.h>
46 #include "blockinput.h"
47 #include "sysselect.h"
50 #include "character.h"
52 #include "composite.h"
55 #include "termhooks.h"
63 #ifdef NS_IMPL_GNUSTEP
71 static EmacsMenu *dockMenu;
73 static EmacsMenu *mainMenu;
76 /* ==========================================================================
78 NSTRACE, Trace support.
80 ========================================================================== */
84 /* The following use "volatile" since they can be accessed from
86 volatile int nstrace_num = 0;
87 volatile int nstrace_depth = 0;
89 /* When 0, no trace is emitted. This is used by NSTRACE_WHEN and
90 NSTRACE_UNLESS to silence functions called.
92 TODO: This should really be a thread-local variable, to avoid that
93 a function with disabled trace thread silence trace output in
94 another. However, in practice this seldom is a problem. */
95 volatile int nstrace_enabled_global = 1;
97 /* Called when nstrace_enabled goes out of scope. */
98 void nstrace_leave(int * pointer_to_nstrace_enabled)
100 if (*pointer_to_nstrace_enabled)
107 /* Called when nstrace_saved_enabled_global goes out of scope. */
108 void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
110 nstrace_enabled_global = *pointer_to_saved_enabled_global;
114 char const * nstrace_fullscreen_type_name (int fs_type)
118 case -1: return "-1";
119 case FULLSCREEN_NONE: return "FULLSCREEN_NONE";
120 case FULLSCREEN_WIDTH: return "FULLSCREEN_WIDTH";
121 case FULLSCREEN_HEIGHT: return "FULLSCREEN_HEIGHT";
122 case FULLSCREEN_BOTH: return "FULLSCREEN_BOTH";
123 case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
124 default: return "FULLSCREEN_?????";
130 /* ==========================================================================
132 NSColor, EmacsColor category.
134 ========================================================================== */
135 @implementation NSColor (EmacsColor)
136 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
137 blue:(CGFloat)blue alpha:(CGFloat)alpha
140 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
141 if (ns_use_srgb_colorspace)
142 return [NSColor colorWithSRGBRed: red
148 return [NSColor colorWithCalibratedRed: red
154 - (NSColor *)colorUsingDefaultColorSpace
157 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
158 if (ns_use_srgb_colorspace)
159 return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
162 return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
167 /* ==========================================================================
171 ========================================================================== */
173 /* Convert a symbol indexed with an NSxxx value to a value as defined
174 in keyboard.c (lispy_function_key). I hope this is a correct way
175 of doing things... */
176 static unsigned convert_ns_to_X_keysym[] =
178 NSHomeFunctionKey, 0x50,
179 NSLeftArrowFunctionKey, 0x51,
180 NSUpArrowFunctionKey, 0x52,
181 NSRightArrowFunctionKey, 0x53,
182 NSDownArrowFunctionKey, 0x54,
183 NSPageUpFunctionKey, 0x55,
184 NSPageDownFunctionKey, 0x56,
185 NSEndFunctionKey, 0x57,
186 NSBeginFunctionKey, 0x58,
187 NSSelectFunctionKey, 0x60,
188 NSPrintFunctionKey, 0x61,
189 NSClearLineFunctionKey, 0x0B,
190 NSExecuteFunctionKey, 0x62,
191 NSInsertFunctionKey, 0x63,
192 NSUndoFunctionKey, 0x65,
193 NSRedoFunctionKey, 0x66,
194 NSMenuFunctionKey, 0x67,
195 NSFindFunctionKey, 0x68,
196 NSHelpFunctionKey, 0x6A,
197 NSBreakFunctionKey, 0x6B,
199 NSF1FunctionKey, 0xBE,
200 NSF2FunctionKey, 0xBF,
201 NSF3FunctionKey, 0xC0,
202 NSF4FunctionKey, 0xC1,
203 NSF5FunctionKey, 0xC2,
204 NSF6FunctionKey, 0xC3,
205 NSF7FunctionKey, 0xC4,
206 NSF8FunctionKey, 0xC5,
207 NSF9FunctionKey, 0xC6,
208 NSF10FunctionKey, 0xC7,
209 NSF11FunctionKey, 0xC8,
210 NSF12FunctionKey, 0xC9,
211 NSF13FunctionKey, 0xCA,
212 NSF14FunctionKey, 0xCB,
213 NSF15FunctionKey, 0xCC,
214 NSF16FunctionKey, 0xCD,
215 NSF17FunctionKey, 0xCE,
216 NSF18FunctionKey, 0xCF,
217 NSF19FunctionKey, 0xD0,
218 NSF20FunctionKey, 0xD1,
219 NSF21FunctionKey, 0xD2,
220 NSF22FunctionKey, 0xD3,
221 NSF23FunctionKey, 0xD4,
222 NSF24FunctionKey, 0xD5,
224 NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
225 NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
226 NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */
228 NSTabCharacter, 0x09,
229 0x19, 0x09, /* left tab->regular since pass shift */
230 NSCarriageReturnCharacter, 0x0D,
231 NSNewlineCharacter, 0x0D,
232 NSEnterCharacter, 0x8D,
234 0x41|NSEventModifierFlagNumericPad, 0xAE, /* KP_Decimal */
235 0x43|NSEventModifierFlagNumericPad, 0xAA, /* KP_Multiply */
236 0x45|NSEventModifierFlagNumericPad, 0xAB, /* KP_Add */
237 0x4B|NSEventModifierFlagNumericPad, 0xAF, /* KP_Divide */
238 0x4E|NSEventModifierFlagNumericPad, 0xAD, /* KP_Subtract */
239 0x51|NSEventModifierFlagNumericPad, 0xBD, /* KP_Equal */
240 0x52|NSEventModifierFlagNumericPad, 0xB0, /* KP_0 */
241 0x53|NSEventModifierFlagNumericPad, 0xB1, /* KP_1 */
242 0x54|NSEventModifierFlagNumericPad, 0xB2, /* KP_2 */
243 0x55|NSEventModifierFlagNumericPad, 0xB3, /* KP_3 */
244 0x56|NSEventModifierFlagNumericPad, 0xB4, /* KP_4 */
245 0x57|NSEventModifierFlagNumericPad, 0xB5, /* KP_5 */
246 0x58|NSEventModifierFlagNumericPad, 0xB6, /* KP_6 */
247 0x59|NSEventModifierFlagNumericPad, 0xB7, /* KP_7 */
248 0x5B|NSEventModifierFlagNumericPad, 0xB8, /* KP_8 */
249 0x5C|NSEventModifierFlagNumericPad, 0xB9, /* KP_9 */
251 0x1B, 0x1B /* escape */
254 /* On macOS picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
255 the maximum font size to NOT antialias. On GNUstep there is currently
256 no way to control this behavior. */
257 float ns_antialias_threshold;
259 NSArray *ns_send_types = 0, *ns_return_types = 0;
260 static NSArray *ns_drag_types = 0;
261 NSString *ns_app_name = @"Emacs"; /* default changed later */
263 /* Display variables */
264 struct ns_display_info *x_display_list; /* Chain of existing displays */
265 long context_menu_value = 0;
268 static struct frame *ns_updating_frame;
269 static NSView *focus_view = NULL;
270 static int ns_window_num = 0;
271 #ifdef NS_IMPL_GNUSTEP
272 static NSRect uRect; // TODO: This is dead, remove it?
274 static BOOL gsaved = NO;
275 static BOOL ns_fake_keydown = NO;
277 static BOOL ns_menu_bar_is_hidden = NO;
279 /*static int debug_lock = 0; */
282 static BOOL send_appdefined = YES;
283 #define NO_APPDEFINED_DATA (-8)
284 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
285 static NSTimer *timed_entry = 0;
286 static NSTimer *scroll_repeat_entry = nil;
287 static fd_set select_readfds, select_writefds;
288 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
289 static int select_nfds = 0, select_valid = 0;
290 static struct timespec select_timeout = { 0, 0 };
291 static int selfds[2] = { -1, -1 };
292 static pthread_mutex_t select_mutex;
293 static NSAutoreleasePool *outerpool;
294 static struct input_event *emacs_event = NULL;
295 static struct input_event *q_event_ptr = NULL;
296 static int n_emacs_events_pending = 0;
297 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
298 *ns_pending_service_args;
299 static BOOL ns_do_open_file = NO;
300 static BOOL ns_last_use_native_fullscreen;
302 /* Non-zero means that a HELP_EVENT has been generated since Emacs
305 static BOOL any_help_event_p = NO;
308 struct input_event *q;
314 static NSString *represented_filename = nil;
315 static struct frame *represented_frame = 0;
319 * State for pending menu activation:
320 * MENU_NONE Normal state
321 * MENU_PENDING A menu has been clicked on, but has been canceled so we can
322 * run lisp to update the menu.
323 * MENU_OPENING Menu is up to date, and the click event is redone so the menu
327 #define MENU_PENDING 1
328 #define MENU_OPENING 2
329 static int menu_will_open_state = MENU_NONE;
331 /* Saved position for menu click. */
332 static CGPoint menu_mouse_point;
335 /* Convert modifiers in a NeXTstep event to emacs style modifiers. */
336 #define NS_FUNCTION_KEY_MASK 0x800000
337 #define NSLeftControlKeyMask (0x000001 | NSEventModifierFlagControl)
338 #define NSRightControlKeyMask (0x002000 | NSEventModifierFlagControl)
339 #define NSLeftCommandKeyMask (0x000008 | NSEventModifierFlagCommand)
340 #define NSRightCommandKeyMask (0x000010 | NSEventModifierFlagCommand)
341 #define NSLeftAlternateKeyMask (0x000020 | NSEventModifierFlagOption)
342 #define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption)
343 #define EV_MODIFIERS2(flags) \
344 (((flags & NSEventModifierFlagHelp) ? \
345 hyper_modifier : 0) \
346 | (!EQ (ns_right_alternate_modifier, Qleft) && \
347 ((flags & NSRightAlternateKeyMask) \
348 == NSRightAlternateKeyMask) ? \
349 parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
350 | ((flags & NSEventModifierFlagOption) ? \
351 parse_solitary_modifier (ns_alternate_modifier) : 0) \
352 | ((flags & NSEventModifierFlagShift) ? \
353 shift_modifier : 0) \
354 | (!EQ (ns_right_control_modifier, Qleft) && \
355 ((flags & NSRightControlKeyMask) \
356 == NSRightControlKeyMask) ? \
357 parse_solitary_modifier (ns_right_control_modifier) : 0) \
358 | ((flags & NSEventModifierFlagControl) ? \
359 parse_solitary_modifier (ns_control_modifier) : 0) \
360 | ((flags & NS_FUNCTION_KEY_MASK) ? \
361 parse_solitary_modifier (ns_function_modifier) : 0) \
362 | (!EQ (ns_right_command_modifier, Qleft) && \
363 ((flags & NSRightCommandKeyMask) \
364 == NSRightCommandKeyMask) ? \
365 parse_solitary_modifier (ns_right_command_modifier) : 0) \
366 | ((flags & NSEventModifierFlagCommand) ? \
367 parse_solitary_modifier (ns_command_modifier):0))
368 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
370 #define EV_UDMODIFIERS(e) \
371 ((([e type] == NSEventTypeLeftMouseDown) ? down_modifier : 0) \
372 | (([e type] == NSEventTypeRightMouseDown) ? down_modifier : 0) \
373 | (([e type] == NSEventTypeOtherMouseDown) ? down_modifier : 0) \
374 | (([e type] == NSEventTypeLeftMouseDragged) ? down_modifier : 0) \
375 | (([e type] == NSEventTypeRightMouseDragged) ? down_modifier : 0) \
376 | (([e type] == NSEventTypeOtherMouseDragged) ? down_modifier : 0) \
377 | (([e type] == NSEventTypeLeftMouseUp) ? up_modifier : 0) \
378 | (([e type] == NSEventTypeRightMouseUp) ? up_modifier : 0) \
379 | (([e type] == NSEventTypeOtherMouseUp) ? up_modifier : 0))
381 #define EV_BUTTON(e) \
382 ((([e type] == NSEventTypeLeftMouseDown) || ([e type] == NSEventTypeLeftMouseUp)) ? 0 : \
383 (([e type] == NSEventTypeRightMouseDown) || ([e type] == NSEventTypeRightMouseUp)) ? 2 : \
384 [e buttonNumber] - 1)
386 /* Convert the time field to a timestamp in milliseconds. */
387 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
389 /* This is a piece of code which is common to all the event handling
390 methods. Maybe it should even be a function. */
391 #define EV_TRAILER(e) \
393 XSETFRAME (emacs_event->frame_or_window, emacsframe); \
397 #define EV_TRAILER2(e) \
399 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
402 Lisp_Object tem = Vinhibit_quit; \
403 Vinhibit_quit = Qt; \
404 n_emacs_events_pending++; \
405 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
406 Vinhibit_quit = tem; \
409 hold_event (emacs_event); \
410 EVENT_INIT (*emacs_event); \
411 ns_send_appdefined (-1); \
415 /* GNUstep always shows decorations if the window is resizable,
416 miniaturizable or closable, but Cocoa does strange things in native
417 fullscreen mode if you don't have at least resizable enabled.
419 These flags will be OR'd or XOR'd with the NSWindow's styleMask
420 property depending on what we're doing. */
422 #define FRAME_DECORATED_FLAGS NSWindowStyleMaskTitled
424 #define FRAME_DECORATED_FLAGS (NSWindowStyleMaskTitled \
425 | NSWindowStyleMaskResizable \
426 | NSWindowStyleMaskMiniaturizable \
427 | NSWindowStyleMaskClosable)
429 #define FRAME_UNDECORATED_FLAGS NSWindowStyleMaskBorderless
431 /* TODO: get rid of need for these forward declarations */
432 static void ns_condemn_scroll_bars (struct frame *f);
433 static void ns_judge_scroll_bars (struct frame *f);
436 /* ==========================================================================
440 ========================================================================== */
443 ns_set_represented_filename (NSString *fstr, struct frame *f)
445 represented_filename = [fstr retain];
446 represented_frame = f;
450 ns_init_events (struct input_event *ev)
457 ns_finish_events (void)
463 hold_event (struct input_event *event)
465 if (hold_event_q.nr == hold_event_q.cap)
467 if (hold_event_q.cap == 0) hold_event_q.cap = 10;
468 else hold_event_q.cap *= 2;
470 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
473 hold_event_q.q[hold_event_q.nr++] = *event;
474 /* Make sure ns_read_socket is called, i.e. we have input. */
476 send_appdefined = YES;
480 append2 (Lisp_Object list, Lisp_Object item)
481 /* --------------------------------------------------------------------------
482 Utility to append to a list
483 -------------------------------------------------------------------------- */
485 return CALLN (Fnconc, list, list1 (item));
490 ns_etc_directory (void)
491 /* If running as a self-contained app bundle, return as a string the
492 filename of the etc directory, if present; else nil. */
494 NSBundle *bundle = [NSBundle mainBundle];
495 NSString *resourceDir = [bundle resourcePath];
496 NSString *resourcePath;
497 NSFileManager *fileManager = [NSFileManager defaultManager];
500 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
501 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
503 if (isDir) return [resourcePath UTF8String];
511 /* If running as a self-contained app bundle, return as a path string
512 the filenames of the libexec and bin directories, ie libexec:bin.
513 Otherwise, return nil.
514 Normally, Emacs does not add its own bin/ directory to the PATH.
515 However, a self-contained NS build has a different layout, with
516 bin/ and libexec/ subdirectories in the directory that contains
518 We put libexec first, because init_callproc_1 uses the first
519 element to initialize exec-directory. An alternative would be
520 for init_callproc to check for invocation-directory/libexec.
523 NSBundle *bundle = [NSBundle mainBundle];
524 NSString *resourceDir = [bundle resourcePath];
525 NSString *binDir = [bundle bundlePath];
526 NSString *resourcePath, *resourcePaths;
528 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
529 NSFileManager *fileManager = [NSFileManager defaultManager];
531 NSEnumerator *pathEnum;
534 range = [resourceDir rangeOfString: @"Contents"];
535 if (range.location != NSNotFound)
537 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
539 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
543 paths = [binDir stringsByAppendingPaths:
544 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
545 pathEnum = [paths objectEnumerator];
548 while ((resourcePath = [pathEnum nextObject]))
550 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
553 if ([resourcePaths length] > 0)
555 = [resourcePaths stringByAppendingString: pathSeparator];
557 = [resourcePaths stringByAppendingString: resourcePath];
560 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
568 /* If running as a self-contained app bundle, return as a path string
569 the filenames of the site-lisp and lisp directories.
570 Ie, site-lisp:lisp. Otherwise, return nil. */
572 NSBundle *bundle = [NSBundle mainBundle];
573 NSString *resourceDir = [bundle resourcePath];
574 NSString *resourcePath, *resourcePaths;
575 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
576 NSFileManager *fileManager = [NSFileManager defaultManager];
578 NSArray *paths = [resourceDir stringsByAppendingPaths:
579 [NSArray arrayWithObjects:
580 @"site-lisp", @"lisp", nil]];
581 NSEnumerator *pathEnum = [paths objectEnumerator];
584 /* Hack to skip site-lisp. */
585 if (no_site_lisp) resourcePath = [pathEnum nextObject];
587 while ((resourcePath = [pathEnum nextObject]))
589 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
592 if ([resourcePaths length] > 0)
594 = [resourcePaths stringByAppendingString: pathSeparator];
596 = [resourcePaths stringByAppendingString: resourcePath];
599 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
606 ns_init_locale (void)
607 /* macOS doesn't set any environment variables for the locale when run
608 from the GUI. Get the locale from the OS and set LANG. */
610 NSLocale *locale = [NSLocale currentLocale];
612 NSTRACE ("ns_init_locale");
616 /* It seems macOS should probably use UTF-8 everywhere.
617 'localeIdentifier' does not specify the encoding, and I can't
618 find any way to get the OS to tell us which encoding to use,
619 so hard-code '.UTF-8'. */
620 NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
621 [locale localeIdentifier]];
623 /* Set LANG to locale, but not if LANG is already set. */
624 setenv("LANG", [localeID UTF8String], 0);
626 @catch (NSException *e)
628 NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
634 ns_release_object (void *obj)
635 /* --------------------------------------------------------------------------
636 Release an object (callable from C)
637 -------------------------------------------------------------------------- */
644 ns_retain_object (void *obj)
645 /* --------------------------------------------------------------------------
646 Retain an object (callable from C)
647 -------------------------------------------------------------------------- */
654 ns_alloc_autorelease_pool (void)
655 /* --------------------------------------------------------------------------
656 Allocate a pool for temporary objects (callable from C)
657 -------------------------------------------------------------------------- */
659 return [[NSAutoreleasePool alloc] init];
664 ns_release_autorelease_pool (void *pool)
665 /* --------------------------------------------------------------------------
666 Free a pool and temporary objects it refers to (callable from C)
667 -------------------------------------------------------------------------- */
669 ns_release_object (pool);
674 ns_menu_bar_should_be_hidden (void)
675 /* True, if the menu bar should be hidden. */
677 return !NILP (ns_auto_hide_menu_bar)
678 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
691 static struct EmacsMargins
692 ns_screen_margins (NSScreen *screen)
693 /* The parts of SCREEN used by the operating system. */
695 NSTRACE ("ns_screen_margins");
697 struct EmacsMargins margins;
699 NSRect screenFrame = [screen frame];
700 NSRect screenVisibleFrame = [screen visibleFrame];
702 /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
703 menu bar, check this explicitly. */
704 if (ns_menu_bar_should_be_hidden())
710 CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
711 CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
712 + screenVisibleFrame.size.height);
714 margins.top = frameTop - visibleFrameTop;
718 CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
719 CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
720 + screenVisibleFrame.size.width);
721 margins.right = frameRight - visibleFrameRight;
724 margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
725 margins.left = screenVisibleFrame.origin.x - screenFrame.origin.x;
727 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
737 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
738 assumed to contain a hidden dock. macOS currently use 4 pixels for
739 this, however, to be future compatible, a larger value is used. */
740 #define DOCK_IGNORE_LIMIT 6
742 static struct EmacsMargins
743 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
744 /* The parts of SCREEN used by the operating system, excluding the parts
745 reserved for an hidden dock. */
747 NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
749 struct EmacsMargins margins = ns_screen_margins(screen);
751 /* macOS (currently) reserved 4 pixels along the edge where a hidden
752 dock is located. Unfortunately, it's not possible to find the
753 location and information about if the dock is hidden. Instead,
754 it is assumed that if the margin of an edge is less than
755 DOCK_IGNORE_LIMIT, it contains a hidden dock. */
756 if (margins.left <= DOCK_IGNORE_LIMIT)
760 if (margins.right <= DOCK_IGNORE_LIMIT)
764 if (margins.top <= DOCK_IGNORE_LIMIT)
768 /* Note: This doesn't occur in current versions of macOS, but
769 included for completeness and future compatibility. */
770 if (margins.bottom <= DOCK_IGNORE_LIMIT)
775 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
786 ns_menu_bar_height (NSScreen *screen)
787 /* The height of the menu bar, if visible.
789 Note: Don't use this when fullscreen is enabled -- the screen
790 sometimes includes, sometimes excludes the menu bar area. */
792 struct EmacsMargins margins = ns_screen_margins(screen);
794 CGFloat res = margins.top;
796 NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
802 /* ==========================================================================
804 Focus (clipping) and screen update
806 ========================================================================== */
809 // Window constraining
810 // -------------------
812 // To ensure that the windows are not placed under the menu bar, they
813 // are typically moved by the call-back constrainFrameRect. However,
814 // by overriding it, it's possible to inhibit this, leaving the window
815 // in it's original position.
817 // It's possible to hide the menu bar. However, technically, it's only
818 // possible to hide it when the application is active. To ensure that
819 // this work properly, the menu bar and window constraining are
820 // deferred until the application becomes active.
822 // Even though it's not possible to manually move a window above the
823 // top of the screen, it is allowed if it's done programmatically,
824 // when the menu is hidden. This allows the editable area to cover the
825 // full screen height.
830 // Use the following extra files:
833 // ;; Hide menu and place frame slightly above the top of the screen.
834 // (setq ns-auto-hide-menu-bar t)
835 // (set-frame-position (selected-frame) 0 -20)
839 // emacs -Q -l init.el
841 // Result: No menu bar, and the title bar should be above the screen.
847 // Result: Menu bar visible, frame placed immediately below the menu.
850 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
852 NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
853 NSTRACE_ARG_RECT (frameRect));
855 // --------------------
856 // Collect information about the screen the frame is covering.
859 NSArray *screens = [NSScreen screens];
860 NSUInteger nr_screens = [screens count];
864 // The height of the menu bar, if present in any screen the frame is
866 int menu_bar_height = 0;
868 // A rectangle covering all the screen the frame is displayed in.
869 NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
870 for (i = 0; i < nr_screens; ++i )
872 NSScreen *s = [screens objectAtIndex: i];
873 NSRect scrRect = [s frame];
875 NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
876 i, NSTRACE_ARG_RECT (scrRect));
878 if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
880 multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
884 CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
885 menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
890 NSTRACE_RECT ("multiscreenRect", multiscreenRect);
892 NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
894 if (multiscreenRect.size.width == 0
895 || multiscreenRect.size.height == 0)
897 // Failed to find any monitor, give up.
898 NSTRACE_MSG ("multiscreenRect empty");
899 NSTRACE_RETURN_RECT (frameRect);
904 // --------------------
905 // Find a suitable placement.
908 if (ns_menu_bar_should_be_hidden())
910 // When the menu bar is hidden, the user may place part of the
911 // frame above the top of the screen, for example to hide the
914 // Hence, keep the original position.
918 // Ensure that the frame is below the menu bar, or below the top
921 // This assume that the menu bar is placed at the top in the
922 // rectangle that covers the monitors. (It doesn't have to be,
923 // but if it's not it's hard to do anything useful.)
924 CGFloat topOfWorkArea = (multiscreenRect.origin.y
925 + multiscreenRect.size.height
928 CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
929 if (topOfFrame > topOfWorkArea)
931 frameRect.origin.y -= topOfFrame - topOfWorkArea;
932 NSTRACE_RECT ("After placement adjust", frameRect);
936 // Include the following section to restrict frame to the screens.
937 // (If so, update it to allow the frame to stretch down below the
940 // --------------------
941 // Ensure frame doesn't stretch below the screens.
944 CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
948 frameRect.origin.y = multiscreenRect.origin.y;
949 frameRect.size.height -= diff;
953 NSTRACE_RETURN_RECT (frameRect);
959 ns_constrain_all_frames (void)
960 /* --------------------------------------------------------------------------
961 Ensure that the menu bar doesn't cover any frames.
962 -------------------------------------------------------------------------- */
964 Lisp_Object tail, frame;
966 NSTRACE ("ns_constrain_all_frames");
970 FOR_EACH_FRAME (tail, frame)
972 struct frame *f = XFRAME (frame);
975 EmacsView *view = FRAME_NS_VIEW (f);
977 if (![view isFullscreen])
980 setFrame:constrain_frame_rect([[view window] frame], false)
991 ns_update_auto_hide_menu_bar (void)
992 /* --------------------------------------------------------------------------
993 Show or hide the menu bar, based on user setting.
994 -------------------------------------------------------------------------- */
997 NSTRACE ("ns_update_auto_hide_menu_bar");
1001 if (NSApp != nil && [NSApp isActive])
1003 // Note, "setPresentationOptions" triggers an error unless the
1004 // application is active.
1005 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
1007 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
1009 NSApplicationPresentationOptions options
1010 = NSApplicationPresentationDefault;
1012 if (menu_bar_should_be_hidden)
1013 options |= NSApplicationPresentationAutoHideMenuBar
1014 | NSApplicationPresentationAutoHideDock;
1016 [NSApp setPresentationOptions: options];
1018 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
1020 if (!ns_menu_bar_is_hidden)
1022 ns_constrain_all_frames ();
1033 ns_update_begin (struct frame *f)
1034 /* --------------------------------------------------------------------------
1035 Prepare for a grouped sequence of drawing calls
1036 external (RIF) call; whole frame, called before update_window_begin
1037 -------------------------------------------------------------------------- */
1039 EmacsView *view = FRAME_NS_VIEW (f);
1040 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1042 ns_update_auto_hide_menu_bar ();
1044 #ifdef NS_IMPL_COCOA
1045 if ([view isFullscreen] && [view fsIsNative])
1047 // Fix reappearing tool bar in fullscreen for Mac OS X 10.7
1048 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1049 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1050 if (! tbar_visible != ! [toolbar isVisible])
1051 [toolbar setVisible: tbar_visible];
1055 ns_updating_frame = f;
1058 /* drawRect may have been called for say the minibuffer, and then clip path
1059 is for the minibuffer. But the display engine may draw more because
1060 we have set the frame as garbaged. So reset clip path to the whole
1062 #ifdef NS_IMPL_COCOA
1065 NSRect r = [view frame];
1066 NSRect cr = [[view window] frame];
1067 /* If a large frame size is set, r may be larger than the window frame
1068 before constrained. In that case don't change the clip path, as we
1069 will clear in to the tool bar and title bar. */
1071 + FRAME_NS_TITLEBAR_HEIGHT (f)
1072 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1074 bp = [[NSBezierPath bezierPathWithRect: r] retain];
1081 #ifdef NS_IMPL_GNUSTEP
1082 uRect = NSMakeRect (0, 0, 0, 0);
1088 ns_update_window_begin (struct window *w)
1089 /* --------------------------------------------------------------------------
1090 Prepare for a grouped sequence of drawing calls
1091 external (RIF) call; for one window, called after update_begin
1092 -------------------------------------------------------------------------- */
1094 struct frame *f = XFRAME (WINDOW_FRAME (w));
1095 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1097 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1098 w->output_cursor = w->cursor;
1102 if (f == hlinfo->mouse_face_mouse_frame)
1104 /* Don't do highlighting for mouse motion during the update. */
1105 hlinfo->mouse_face_defer = 1;
1107 /* If the frame needs to be redrawn,
1108 simply forget about any prior mouse highlighting. */
1109 if (FRAME_GARBAGED_P (f))
1110 hlinfo->mouse_face_window = Qnil;
1112 /* (further code for mouse faces ifdef'd out in other terms elided) */
1120 ns_update_window_end (struct window *w, bool cursor_on_p,
1121 bool mouse_face_overwritten_p)
1122 /* --------------------------------------------------------------------------
1123 Finished a grouped sequence of drawing calls
1124 external (RIF) call; for one window called before update_end
1125 -------------------------------------------------------------------------- */
1127 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1129 /* note: this fn is nearly identical in all terms */
1130 if (!w->pseudo_window_p)
1135 display_and_set_cursor (w, 1,
1136 w->output_cursor.hpos, w->output_cursor.vpos,
1137 w->output_cursor.x, w->output_cursor.y);
1139 if (draw_window_fringes (w, 1))
1141 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1142 x_draw_right_divider (w);
1144 x_draw_vertical_border (w);
1150 /* If a row with mouse-face was overwritten, arrange for
1151 frame_up_to_date to redisplay the mouse highlight. */
1152 if (mouse_face_overwritten_p)
1153 reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1158 ns_update_end (struct frame *f)
1159 /* --------------------------------------------------------------------------
1160 Finished a grouped sequence of drawing calls
1161 external (RIF) call; for whole frame, called after update_window_end
1162 -------------------------------------------------------------------------- */
1164 EmacsView *view = FRAME_NS_VIEW (f);
1166 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1168 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1169 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1174 [[view window] flushWindow];
1177 ns_updating_frame = NULL;
1181 ns_focus (struct frame *f, NSRect *r, int n)
1182 /* --------------------------------------------------------------------------
1183 Internal: Focus on given frame. During small local updates this is used to
1184 draw, however during large updates, ns_update_begin and ns_update_end are
1185 called to wrap the whole thing, in which case these calls are stubbed out.
1186 Except, on GNUstep, we accumulate the rectangle being drawn into, because
1187 the back end won't do this automatically, and will just end up flushing
1189 -------------------------------------------------------------------------- */
1191 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1194 NSTRACE_RECT ("r", *r);
1197 if (f != ns_updating_frame)
1199 NSView *view = FRAME_NS_VIEW (f);
1200 if (view != focus_view)
1202 if (focus_view != NULL)
1204 [focus_view unlockFocus];
1205 [[focus_view window] flushWindow];
1212 /*if (view) debug_lock++; */
1219 [[NSGraphicsContext currentContext] saveGraphicsState];
1221 NSRectClipList (r, 2);
1230 ns_unfocus (struct frame *f)
1231 /* --------------------------------------------------------------------------
1232 Internal: Remove focus on given frame
1233 -------------------------------------------------------------------------- */
1235 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1239 [[NSGraphicsContext currentContext] restoreGraphicsState];
1243 if (f != ns_updating_frame)
1245 if (focus_view != NULL)
1247 [focus_view unlockFocus];
1248 [[focus_view window] flushWindow];
1257 ns_clip_to_row (struct window *w, struct glyph_row *row,
1258 enum glyph_row_area area, BOOL gc)
1259 /* --------------------------------------------------------------------------
1260 Internal (but parallels other terms): Focus drawing on given row
1261 -------------------------------------------------------------------------- */
1263 struct frame *f = XFRAME (WINDOW_FRAME (w));
1265 int window_x, window_y, window_width;
1267 window_box (w, area, &window_x, &window_y, &window_width, 0);
1269 clip_rect.origin.x = window_x;
1270 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1271 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1272 clip_rect.size.width = window_width;
1273 clip_rect.size.height = row->visible_height;
1275 ns_focus (f, &clip_rect, 1);
1279 /* ==========================================================================
1281 Visible bell and beep.
1283 ========================================================================== */
1286 // This bell implementation shows the visual bell image asynchronously
1287 // from the rest of Emacs. This is done by adding a NSView to the
1288 // superview of the Emacs window and removing it using a timer.
1290 // Unfortunately, some Emacs operations, like scrolling, is done using
1291 // low-level primitives that copy the content of the window, including
1292 // the bell image. To some extent, this is handled by removing the
1293 // image prior to scrolling and marking that the window is in need for
1296 // To test this code, make sure that there is no artifacts of the bell
1297 // image in the following situations. Use a non-empty buffer (like the
1298 // tutorial) to ensure that a scroll is performed:
1300 // * Single-window: C-g C-v
1302 // * Side-by-windows: C-x 3 C-g C-v
1304 // * Windows above each other: C-x 2 C-g C-v
1306 @interface EmacsBell : NSImageView
1308 // Number of currently active bell:s.
1309 unsigned int nestCount;
1313 - (void)show:(NSView *)view;
1318 @implementation EmacsBell
1322 NSTRACE ("[EmacsBell init]");
1323 if ((self = [super init]))
1327 #ifdef NS_IMPL_GNUSTEP
1328 // GNUstep doesn't provide named images. This was reported in
1329 // 2011, see https://savannah.gnu.org/bugs/?33396
1331 // As a drop in replacement, a semitransparent gray square is used.
1332 self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1333 [self.image lockFocus];
1334 [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1335 NSRectFill(NSMakeRect(0, 0, 32, 32));
1336 [self.image unlockFocus];
1338 self.image = [NSImage imageNamed:NSImageNameCaution];
1339 [self.image setSize:NSMakeSize(self.image.size.width * 5,
1340 self.image.size.height * 5)];
1346 - (void)show:(NSView *)view
1348 NSTRACE ("[EmacsBell show:]");
1349 NSTRACE_MSG ("nestCount: %u", nestCount);
1351 // Show the image, unless it's already shown.
1354 NSRect rect = [view bounds];
1356 pos.x = rect.origin.x + (rect.size.width - self.image.size.width )/2;
1357 pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1359 [self setFrameOrigin:pos];
1360 [self setFrameSize:self.image.size];
1364 [[[view window] contentView] addSubview:self
1365 positioned:NSWindowAbove
1371 [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1377 // Note: Trace output from this method isn't shown, reason unknown.
1378 // NSTRACE ("[EmacsBell hide]");
1383 // Remove the image once the last bell became inactive.
1393 NSTRACE ("[EmacsBell remove]");
1396 NSTRACE_MSG ("removeFromSuperview");
1397 [self removeFromSuperview];
1398 mView.needsDisplay = YES;
1406 static EmacsBell * bell_view = nil;
1409 ns_ring_bell (struct frame *f)
1410 /* --------------------------------------------------------------------------
1412 -------------------------------------------------------------------------- */
1414 NSTRACE ("ns_ring_bell");
1417 struct frame *frame = SELECTED_FRAME ();
1420 if (bell_view == nil)
1422 bell_view = [[EmacsBell alloc] init];
1428 view = FRAME_NS_VIEW (frame);
1431 [bell_view show:view];
1445 /* --------------------------------------------------------------------------
1446 Ensure the bell is hidden.
1447 -------------------------------------------------------------------------- */
1449 NSTRACE ("hide_bell");
1451 if (bell_view != nil)
1458 /* ==========================================================================
1460 Frame / window manager related functions
1462 ========================================================================== */
1466 ns_raise_frame (struct frame *f)
1467 /* --------------------------------------------------------------------------
1468 Bring window to foreground and make it active
1469 -------------------------------------------------------------------------- */
1473 check_window_system (f);
1474 view = FRAME_NS_VIEW (f);
1476 if (FRAME_VISIBLE_P (f))
1477 [[view window] makeKeyAndOrderFront: NSApp];
1483 ns_lower_frame (struct frame *f)
1484 /* --------------------------------------------------------------------------
1486 -------------------------------------------------------------------------- */
1490 check_window_system (f);
1491 view = FRAME_NS_VIEW (f);
1493 [[view window] orderBack: NSApp];
1499 ns_frame_raise_lower (struct frame *f, bool raise)
1500 /* --------------------------------------------------------------------------
1502 -------------------------------------------------------------------------- */
1504 NSTRACE ("ns_frame_raise_lower");
1514 ns_frame_rehighlight (struct frame *frame)
1515 /* --------------------------------------------------------------------------
1516 External (hook): called on things like window switching within frame
1517 -------------------------------------------------------------------------- */
1519 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1520 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1522 NSTRACE ("ns_frame_rehighlight");
1523 if (dpyinfo->x_focus_frame)
1525 dpyinfo->x_highlight_frame
1526 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1527 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1528 : dpyinfo->x_focus_frame);
1529 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1531 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1532 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1536 dpyinfo->x_highlight_frame = 0;
1538 if (dpyinfo->x_highlight_frame &&
1539 dpyinfo->x_highlight_frame != old_highlight)
1543 x_update_cursor (old_highlight, 1);
1544 x_set_frame_alpha (old_highlight);
1546 if (dpyinfo->x_highlight_frame)
1548 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1549 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1556 x_make_frame_visible (struct frame *f)
1557 /* --------------------------------------------------------------------------
1558 External: Show the window (X11 semantics)
1559 -------------------------------------------------------------------------- */
1561 NSTRACE ("x_make_frame_visible");
1562 /* XXX: at some points in past this was not needed, as the only place that
1563 called this (frame.c:Fraise_frame ()) also called raise_lower;
1564 if this ends up the case again, comment this out again. */
1565 if (!FRAME_VISIBLE_P (f))
1567 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1569 SET_FRAME_VISIBLE (f, 1);
1572 /* Making a new frame from a fullscreen frame will make the new frame
1573 fullscreen also. So skip handleFS as this will print an error. */
1574 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1575 && [view isFullscreen])
1578 if (f->want_fullscreen != FULLSCREEN_NONE)
1589 x_make_frame_invisible (struct frame *f)
1590 /* --------------------------------------------------------------------------
1591 External: Hide the window (X11 semantics)
1592 -------------------------------------------------------------------------- */
1595 NSTRACE ("x_make_frame_invisible");
1596 check_window_system (f);
1597 view = FRAME_NS_VIEW (f);
1598 [[view window] orderOut: NSApp];
1599 SET_FRAME_VISIBLE (f, 0);
1600 SET_FRAME_ICONIFIED (f, 0);
1605 x_iconify_frame (struct frame *f)
1606 /* --------------------------------------------------------------------------
1607 External: Iconify window
1608 -------------------------------------------------------------------------- */
1611 struct ns_display_info *dpyinfo;
1613 NSTRACE ("x_iconify_frame");
1614 check_window_system (f);
1615 view = FRAME_NS_VIEW (f);
1616 dpyinfo = FRAME_DISPLAY_INFO (f);
1618 if (dpyinfo->x_highlight_frame == f)
1619 dpyinfo->x_highlight_frame = 0;
1621 if ([[view window] windowNumber] <= 0)
1623 /* the window is still deferred. Make it very small, bring it
1624 on screen and order it out. */
1625 NSRect s = { { 100, 100}, {0, 0} };
1627 t = [[view window] frame];
1628 [[view window] setFrame: s display: NO];
1629 [[view window] orderBack: NSApp];
1630 [[view window] orderOut: NSApp];
1631 [[view window] setFrame: t display: NO];
1634 /* Processing input while Emacs is being minimized can cause a
1635 crash, so block it for the duration. */
1637 [[view window] miniaturize: NSApp];
1641 /* Free X resources of frame F. */
1644 x_free_frame_resources (struct frame *f)
1647 struct ns_display_info *dpyinfo;
1648 Mouse_HLInfo *hlinfo;
1650 NSTRACE ("x_free_frame_resources");
1651 check_window_system (f);
1652 view = FRAME_NS_VIEW (f);
1653 dpyinfo = FRAME_DISPLAY_INFO (f);
1654 hlinfo = MOUSE_HL_INFO (f);
1656 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1660 free_frame_menubar (f);
1661 free_frame_faces (f);
1663 if (f == dpyinfo->x_focus_frame)
1664 dpyinfo->x_focus_frame = 0;
1665 if (f == dpyinfo->x_highlight_frame)
1666 dpyinfo->x_highlight_frame = 0;
1667 if (f == hlinfo->mouse_face_mouse_frame)
1668 reset_mouse_highlight (hlinfo);
1670 if (f->output_data.ns->miniimage != nil)
1671 [f->output_data.ns->miniimage release];
1673 [[view window] close];
1676 xfree (f->output_data.ns);
1682 x_destroy_window (struct frame *f)
1683 /* --------------------------------------------------------------------------
1684 External: Delete the window
1685 -------------------------------------------------------------------------- */
1687 NSTRACE ("x_destroy_window");
1689 /* If this frame has a parent window, detach it as not doing so can
1690 cause a crash in GNUStep. */
1691 if (FRAME_PARENT_FRAME (f) != NULL)
1693 NSWindow *child = [FRAME_NS_VIEW (f) window];
1694 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1696 [parent removeChildWindow: child];
1699 check_window_system (f);
1700 x_free_frame_resources (f);
1706 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1707 /* --------------------------------------------------------------------------
1708 External: Position the window
1709 -------------------------------------------------------------------------- */
1711 NSView *view = FRAME_NS_VIEW (f);
1712 NSArray *screens = [NSScreen screens];
1713 NSScreen *fscreen = [screens objectAtIndex: 0];
1714 NSScreen *screen = [[view window] screen];
1716 NSTRACE ("x_set_offset");
1723 if (view != nil && screen && fscreen)
1725 f->left_pos = f->size_hint_flags & XNegative
1726 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1728 /* We use visibleFrame here to take menu bar into account.
1729 Ideally we should also adjust left/top with visibleFrame.origin. */
1731 f->top_pos = f->size_hint_flags & YNegative
1732 ? ([screen visibleFrame].size.height + f->top_pos
1733 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1734 - FRAME_TOOLBAR_HEIGHT (f))
1736 #ifdef NS_IMPL_GNUSTEP
1737 if (FRAME_PARENT_FRAME (f) == NULL)
1739 if (f->left_pos < 100)
1740 f->left_pos = 100; /* don't overlap menu */
1743 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1745 NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
1746 + NS_PARENT_WINDOW_LEFT_POS (f)),
1747 SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
1749 NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1750 [[view window] setFrameTopLeftPoint: pt];
1751 f->size_hint_flags &= ~(XNegative|YNegative);
1759 x_set_window_size (struct frame *f,
1760 bool change_gravity,
1764 /* --------------------------------------------------------------------------
1765 Adjust window pixel size based on given character grid size
1766 Impl is a bit more complex than other terms, need to do some
1768 -------------------------------------------------------------------------- */
1770 EmacsView *view = FRAME_NS_VIEW (f);
1771 NSWindow *window = [view window];
1772 NSRect wr = [window frame];
1773 int pixelwidth, pixelheight;
1774 int orig_height = wr.size.height;
1776 NSTRACE ("x_set_window_size");
1781 NSTRACE_RECT ("current", wr);
1782 NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1783 NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1789 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1790 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1794 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1795 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1798 wr.size.width = pixelwidth + f->border_width;
1799 wr.size.height = pixelheight;
1800 if (! [view isFullscreen])
1801 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1802 + FRAME_TOOLBAR_HEIGHT (f);
1804 /* Do not try to constrain to this screen. We may have multiple
1805 screens, and want Emacs to span those. Constraining to screen
1806 prevents that, and that is not nice to the user. */
1807 if (f->output_data.ns->zooming)
1808 f->output_data.ns->zooming = 0;
1810 wr.origin.y += orig_height - wr.size.height;
1812 frame_size_history_add
1813 (f, Qx_set_window_size_1, width, height,
1814 list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1815 Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1816 make_number (f->border_width),
1817 make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1818 make_number (FRAME_TOOLBAR_HEIGHT (f))));
1820 [window setFrame: wr display: YES];
1822 [view updateFrameSize: NO];
1826 #ifdef NS_IMPL_COCOA
1828 x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1829 /* --------------------------------------------------------------------------
1830 Set frame F's `undecorated' parameter. If non-nil, F's window-system
1831 window is drawn without decorations, title, minimize/maximize boxes
1832 and external borders. This usually means that the window cannot be
1833 dragged, resized, iconified, maximized or deleted with the mouse. If
1834 nil, draw the frame with all the elements listed above unless these
1835 have been suspended via window manager settings.
1837 GNUStep cannot change an existing window's style.
1838 -------------------------------------------------------------------------- */
1840 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1841 NSWindow *window = [view window];
1843 NSTRACE ("x_set_undecorated");
1845 if (!EQ (new_value, old_value))
1849 if (NILP (new_value))
1851 FRAME_UNDECORATED (f) = false;
1852 [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
1853 ^ FRAME_UNDECORATED_FLAGS)];
1855 [view createToolbar: f];
1859 [window setToolbar: nil];
1860 /* Do I need to release the toolbar here? */
1862 FRAME_UNDECORATED (f) = true;
1863 [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS)
1864 ^ FRAME_DECORATED_FLAGS)];
1867 /* At this point it seems we don't have an active NSResponder,
1868 so some key presses (TAB) are swallowed by the system. */
1869 [window makeFirstResponder: view];
1871 [view updateFrameSize: NO];
1875 #endif /* NS_IMPL_COCOA */
1878 x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1879 /* --------------------------------------------------------------------------
1880 Set frame F's `parent-frame' parameter. If non-nil, make F a child
1881 frame of the frame specified by that parameter. Technically, this
1882 makes F's window-system window a child window of the parent frame's
1883 window-system window. If nil, make F's window-system window a
1884 top-level window--a child of its display's root window.
1886 A child frame's `left' and `top' parameters specify positions
1887 relative to the top-left corner of its parent frame's native
1888 rectangle. On macOS moving a parent frame moves all its child
1889 frames too, keeping their position relative to the parent
1890 unaltered. When a parent frame is iconified or made invisible, its
1891 child frames are made invisible. When a parent frame is deleted,
1892 its child frames are deleted too.
1894 Whether a child frame has a tool bar may be window-system or window
1895 manager dependent. It's advisable to disable it via the frame
1898 Some window managers may not honor this parameter.
1899 -------------------------------------------------------------------------- */
1901 struct frame *p = NULL;
1902 NSWindow *parent, *child;
1904 NSTRACE ("x_set_parent_frame");
1906 if (!NILP (new_value)
1907 && (!FRAMEP (new_value)
1908 || !FRAME_LIVE_P (p = XFRAME (new_value))
1911 store_frame_param (f, Qparent_frame, old_value);
1912 error ("Invalid specification of `parent-frame'");
1915 if (p != FRAME_PARENT_FRAME (f))
1917 parent = [FRAME_NS_VIEW (p) window];
1918 child = [FRAME_NS_VIEW (f) window];
1921 [parent addChildWindow: child
1922 ordered: NSWindowAbove];
1925 fset_parent_frame (f, new_value);
1930 x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1931 /* Set frame F's `no-accept-focus' parameter which, if non-nil, hints
1932 * that F's window-system window does not want to receive input focus
1933 * via mouse clicks or by moving the mouse into it.
1935 * If non-nil, this may have the unwanted side-effect that a user cannot
1936 * scroll a non-selected frame with the mouse.
1938 * Some window managers may not honor this parameter. */
1940 NSTRACE ("x_set_no_accept_focus");
1942 if (!EQ (new_value, old_value))
1943 FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
1947 x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1948 /* Set frame F's `z-group' parameter. If `above', F's window-system
1949 window is displayed above all windows that do not have the `above'
1950 property set. If nil, F's window is shown below all windows that
1951 have the `above' property set and above all windows that have the
1952 `below' property set. If `below', F's window is displayed below
1953 all windows that do.
1955 Some window managers may not honor this parameter. */
1957 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1958 NSWindow *window = [view window];
1960 NSTRACE ("x_set_z_group");
1962 if (NILP (new_value))
1964 window.level = NSNormalWindowLevel;
1965 FRAME_Z_GROUP (f) = z_group_none;
1967 else if (EQ (new_value, Qabove))
1969 window.level = NSNormalWindowLevel + 1;
1970 FRAME_Z_GROUP (f) = z_group_above;
1972 else if (EQ (new_value, Qabove_suspended))
1974 /* Not sure what level this should be. */
1975 window.level = NSNormalWindowLevel + 1;
1976 FRAME_Z_GROUP (f) = z_group_above_suspended;
1978 else if (EQ (new_value, Qbelow))
1980 window.level = NSNormalWindowLevel - 1;
1981 FRAME_Z_GROUP (f) = z_group_below;
1984 error ("Invalid z-group specification");
1988 ns_fullscreen_hook (struct frame *f)
1990 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1992 NSTRACE ("ns_fullscreen_hook");
1994 if (!FRAME_VISIBLE_P (f))
1997 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1999 /* Old style fs don't initiate correctly if created from
2000 init/default-frame alist, so use a timer (not nice...).
2002 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
2003 selector: @selector (handleFS)
2004 userInfo: nil repeats: NO];
2013 /* ==========================================================================
2017 ========================================================================== */
2021 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
2023 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2024 if (idx < 1 || idx >= color_table->avail)
2026 return color_table->colors[idx];
2031 ns_index_color (NSColor *color, struct frame *f)
2033 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2037 if (!color_table->colors)
2039 color_table->size = NS_COLOR_CAPACITY;
2040 color_table->avail = 1; /* skip idx=0 as marker */
2041 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
2042 color_table->colors[0] = nil;
2043 color_table->empty_indices = [[NSMutableSet alloc] init];
2046 /* Do we already have this color? */
2047 for (i = 1; i < color_table->avail; i++)
2048 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
2051 if ([color_table->empty_indices count] > 0)
2053 NSNumber *index = [color_table->empty_indices anyObject];
2054 [color_table->empty_indices removeObject: index];
2055 idx = [index unsignedLongValue];
2059 if (color_table->avail == color_table->size)
2060 color_table->colors =
2061 xpalloc (color_table->colors, &color_table->size, 1,
2062 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
2063 idx = color_table->avail++;
2066 color_table->colors[idx] = color;
2068 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
2074 ns_get_color (const char *name, NSColor **col)
2075 /* --------------------------------------------------------------------------
2077 -------------------------------------------------------------------------- */
2078 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
2079 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
2080 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
2083 static char hex[20];
2085 float r = -1.0, g, b;
2086 NSString *nsname = [NSString stringWithUTF8String: name];
2088 NSTRACE ("ns_get_color(%s, **)", name);
2092 if ([nsname isEqualToString: @"ns_selection_bg_color"])
2094 #ifdef NS_IMPL_COCOA
2095 NSString *defname = [[NSUserDefaults standardUserDefaults]
2096 stringForKey: @"AppleHighlightColor"];
2101 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
2103 *col = [new colorUsingDefaultColorSpace];
2108 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
2110 name = [nsname UTF8String];
2112 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
2114 /* NOTE: macOS applications normally don't set foreground
2115 selection, but text may be unreadable if we don't.
2117 if ((new = [NSColor selectedTextColor]) != nil)
2119 *col = [new colorUsingDefaultColorSpace];
2124 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
2125 name = [nsname UTF8String];
2128 /* First, check for some sort of numeric specification. */
2131 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
2133 NSScanner *scanner = [NSScanner scannerWithString: nsname];
2134 [scanner scanFloat: &r];
2135 [scanner scanFloat: &g];
2136 [scanner scanFloat: &b];
2138 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
2139 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2140 else if (name[0] == '#') /* An old X11 format; convert to newer */
2142 int len = (strlen(name) - 1);
2143 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2145 scaling = strlen(name+start) / 3;
2146 for (i = 0; i < 3; i++)
2147 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2148 name + start + i * scaling);
2149 hex[3 * (scaling + 1) - 1] = '\0';
2154 unsigned int rr, gg, bb;
2155 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2156 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2166 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2171 /* Otherwise, color is expected to be from a list */
2173 NSEnumerator *lenum, *cenum;
2177 #ifdef NS_IMPL_GNUSTEP
2178 /* XXX: who is wrong, the requestor or the implementation? */
2179 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2181 nsname = @"highlightColor";
2184 lenum = [[NSColorList availableColorLists] objectEnumerator];
2185 while ( (clist = [lenum nextObject]) && new == nil)
2187 cenum = [[clist allKeys] objectEnumerator];
2188 while ( (name = [cenum nextObject]) && new == nil )
2190 if ([name compare: nsname
2191 options: NSCaseInsensitiveSearch] == NSOrderedSame )
2192 new = [clist colorWithKey: name];
2198 *col = [new colorUsingDefaultColorSpace];
2205 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2206 /* --------------------------------------------------------------------------
2207 Convert a Lisp string object to a NS color
2208 -------------------------------------------------------------------------- */
2210 NSTRACE ("ns_lisp_to_color");
2211 if (STRINGP (color))
2212 return ns_get_color (SSDATA (color), col);
2213 else if (SYMBOLP (color))
2214 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2220 ns_query_color(void *col, XColor *color_def, int setPixel)
2221 /* --------------------------------------------------------------------------
2222 Get ARGB values out of NSColor col and put them into color_def.
2223 If setPixel, set the pixel to a concatenated version.
2224 and set color_def pixel to the resulting index.
2225 -------------------------------------------------------------------------- */
2227 EmacsCGFloat r, g, b, a;
2229 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2230 color_def->red = r * 65535;
2231 color_def->green = g * 65535;
2232 color_def->blue = b * 65535;
2234 if (setPixel == YES)
2236 = ARGB_TO_ULONG((int)(a*255),
2237 (int)(r*255), (int)(g*255), (int)(b*255));
2242 ns_defined_color (struct frame *f,
2247 /* --------------------------------------------------------------------------
2248 Return true if named color found, and set color_def rgb accordingly.
2249 If makeIndex and alloc are nonzero put the color in the color_table,
2250 and set color_def pixel to the resulting index.
2251 If makeIndex is zero, set color_def pixel to ARGB.
2252 Return false if not found
2253 -------------------------------------------------------------------------- */
2256 NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2259 if (ns_get_color (name, &col) != 0) /* Color not found */
2264 if (makeIndex && alloc)
2265 color_def->pixel = ns_index_color (col, f);
2266 ns_query_color (col, color_def, !makeIndex);
2273 x_set_frame_alpha (struct frame *f)
2274 /* --------------------------------------------------------------------------
2275 change the entire-frame transparency
2276 -------------------------------------------------------------------------- */
2278 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2280 double alpha_min = 1.0;
2282 NSTRACE ("x_set_frame_alpha");
2284 if (dpyinfo->x_highlight_frame == f)
2285 alpha = f->alpha[0];
2287 alpha = f->alpha[1];
2289 if (FLOATP (Vframe_alpha_lower_limit))
2290 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2291 else if (INTEGERP (Vframe_alpha_lower_limit))
2292 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2296 else if (1.0 < alpha)
2298 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2301 #ifdef NS_IMPL_COCOA
2303 EmacsView *view = FRAME_NS_VIEW (f);
2304 [[view window] setAlphaValue: alpha];
2310 /* ==========================================================================
2314 ========================================================================== */
2318 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2319 /* --------------------------------------------------------------------------
2320 Programmatically reposition mouse pointer in pixel coordinates
2321 -------------------------------------------------------------------------- */
2323 NSTRACE ("frame_set_mouse_pixel_position");
2326 /* FIXME: this does not work, and what about GNUstep? */
2327 #ifdef NS_IMPL_COCOA
2328 [FRAME_NS_VIEW (f) lockFocus];
2329 PSsetmouse ((float)pix_x, (float)pix_y);
2330 [FRAME_NS_VIEW (f) unlockFocus];
2336 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2337 /* ------------------------------------------------------------------------
2338 Called by EmacsView on mouseMovement events. Passes on
2339 to emacs mainstream code if we moved off of a rect of interest
2340 known as last_mouse_glyph.
2341 ------------------------------------------------------------------------ */
2343 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2346 // NSTRACE ("note_mouse_movement");
2348 dpyinfo->last_mouse_motion_frame = frame;
2349 r = &dpyinfo->last_mouse_glyph;
2351 /* Note, this doesn't get called for enter/leave, since we don't have a
2352 position. Those are taken care of in the corresponding NSView methods. */
2354 /* has movement gone beyond last rect we were tracking? */
2355 if (x < r->origin.x || x >= r->origin.x + r->size.width
2356 || y < r->origin.y || y >= r->origin.y + r->size.height)
2358 ns_update_begin (frame);
2359 frame->mouse_moved = 1;
2360 note_mouse_highlight (frame, x, y);
2361 remember_mouse_glyph (frame, x, y, r);
2362 ns_update_end (frame);
2371 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2372 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2374 /* --------------------------------------------------------------------------
2375 External (hook): inform emacs about mouse position and hit parts.
2376 If a scrollbar is being dragged, set bar_window, part, x, y, time.
2377 x & y should be position in the scrollbar (the whole bar, not the handle)
2378 and length of scrollbar respectively
2379 -------------------------------------------------------------------------- */
2383 Lisp_Object frame, tail;
2385 struct ns_display_info *dpyinfo;
2387 NSTRACE ("ns_mouse_position");
2391 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2395 dpyinfo = FRAME_DISPLAY_INFO (*fp);
2399 /* Clear the mouse-moved flag for every frame on this display. */
2400 FOR_EACH_FRAME (tail, frame)
2401 if (FRAME_NS_P (XFRAME (frame))
2402 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2403 XFRAME (frame)->mouse_moved = 0;
2405 dpyinfo->last_mouse_scroll_bar = nil;
2406 if (dpyinfo->last_mouse_frame
2407 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2408 f = dpyinfo->last_mouse_frame;
2410 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2412 if (f && FRAME_NS_P (f))
2414 view = FRAME_NS_VIEW (*fp);
2416 position = [[view window] mouseLocationOutsideOfEventStream];
2417 position = [view convertPoint: position fromView: nil];
2418 remember_mouse_glyph (f, position.x, position.y,
2419 &dpyinfo->last_mouse_glyph);
2420 NSTRACE_POINT ("position", position);
2422 if (bar_window) *bar_window = Qnil;
2423 if (part) *part = scroll_bar_above_handle;
2425 if (x) XSETINT (*x, lrint (position.x));
2426 if (y) XSETINT (*y, lrint (position.y));
2428 *time = dpyinfo->last_mouse_movement_time;
2437 ns_frame_up_to_date (struct frame *f)
2438 /* --------------------------------------------------------------------------
2439 External (hook): Fix up mouse highlighting right after a full update.
2440 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2441 -------------------------------------------------------------------------- */
2443 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2447 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2448 if (f == hlinfo->mouse_face_mouse_frame)
2452 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2453 hlinfo->mouse_face_mouse_x,
2454 hlinfo->mouse_face_mouse_y);
2463 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2464 /* --------------------------------------------------------------------------
2465 External (RIF): set frame mouse pointer type.
2466 -------------------------------------------------------------------------- */
2468 NSTRACE ("ns_define_frame_cursor");
2469 if (FRAME_POINTER_TYPE (f) != cursor)
2471 EmacsView *view = FRAME_NS_VIEW (f);
2472 FRAME_POINTER_TYPE (f) = cursor;
2473 [[view window] invalidateCursorRectsForView: view];
2474 /* Redisplay assumes this function also draws the changed frame
2475 cursor, but this function doesn't, so do it explicitly. */
2476 x_update_cursor (f, 1);
2482 /* ==========================================================================
2486 ========================================================================== */
2490 ns_convert_key (unsigned code)
2491 /* --------------------------------------------------------------------------
2492 Internal call used by NSView-keyDown.
2493 -------------------------------------------------------------------------- */
2495 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2497 /* An array would be faster, but less easy to read. */
2498 for (keysym = 0; keysym < last_keysym; keysym += 2)
2499 if (code == convert_ns_to_X_keysym[keysym])
2500 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2502 /* if decide to use keyCode and Carbon table, use this line:
2503 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2508 x_get_keysym_name (int keysym)
2509 /* --------------------------------------------------------------------------
2510 Called by keyboard.c. Not sure if the return val is important, except
2512 -------------------------------------------------------------------------- */
2514 static char value[16];
2515 NSTRACE ("x_get_keysym_name");
2516 sprintf (value, "%d", keysym);
2522 /* ==========================================================================
2524 Block drawing operations
2526 ========================================================================== */
2530 ns_redraw_scroll_bars (struct frame *f)
2534 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2535 NSTRACE ("ns_redraw_scroll_bars");
2536 for (i =[subviews count]-1; i >= 0; i--)
2538 view = [subviews objectAtIndex: i];
2539 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2546 ns_clear_frame (struct frame *f)
2547 /* --------------------------------------------------------------------------
2548 External (hook): Erase the entire frame
2549 -------------------------------------------------------------------------- */
2551 NSView *view = FRAME_NS_VIEW (f);
2554 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2556 /* comes on initial frame because we have
2557 after-make-frame-functions = select-frame */
2558 if (!FRAME_DEFAULT_FACE (f))
2561 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2566 ns_focus (f, &r, 1);
2567 [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2568 (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
2572 /* as of 2006/11 or so this is now needed */
2573 ns_redraw_scroll_bars (f);
2579 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2580 /* --------------------------------------------------------------------------
2581 External (RIF): Clear section of frame
2582 -------------------------------------------------------------------------- */
2584 NSRect r = NSMakeRect (x, y, width, height);
2585 NSView *view = FRAME_NS_VIEW (f);
2586 struct face *face = FRAME_DEFAULT_FACE (f);
2591 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2593 r = NSIntersectionRect (r, [view frame]);
2594 ns_focus (f, &r, 1);
2595 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2604 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2606 NSTRACE ("ns_copy_bits");
2608 if (FRAME_NS_VIEW (f))
2610 hide_bell(); // Ensure the bell image isn't scrolled.
2612 ns_focus (f, &dest, 1);
2613 [FRAME_NS_VIEW (f) scrollRect: src
2614 by: NSMakeSize (dest.origin.x - src.origin.x,
2615 dest.origin.y - src.origin.y)];
2621 ns_scroll_run (struct window *w, struct run *run)
2622 /* --------------------------------------------------------------------------
2623 External (RIF): Insert or delete n lines at line vpos
2624 -------------------------------------------------------------------------- */
2626 struct frame *f = XFRAME (w->frame);
2627 int x, y, width, height, from_y, to_y, bottom_y;
2629 NSTRACE ("ns_scroll_run");
2631 /* begin copy from other terms */
2632 /* Get frame-relative bounding box of the text display area of W,
2633 without mode lines. Include in this box the left and right
2635 window_box (w, ANY_AREA, &x, &y, &width, &height);
2637 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2638 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2639 bottom_y = y + height;
2643 /* Scrolling up. Make sure we don't copy part of the mode
2644 line at the bottom. */
2645 if (from_y + run->height > bottom_y)
2646 height = bottom_y - from_y;
2648 height = run->height;
2652 /* Scrolling down. Make sure we don't copy over the mode line.
2654 if (to_y + run->height > bottom_y)
2655 height = bottom_y - to_y;
2657 height = run->height;
2659 /* end copy from other terms */
2669 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2670 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2672 ns_copy_bits (f, srcRect , dstRect);
2680 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2681 /* --------------------------------------------------------------------------
2682 External (RIF): preparatory to fringe update after text was updated
2683 -------------------------------------------------------------------------- */
2688 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2690 /* begin copy from other terms */
2693 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2694 desired_row->redraw_fringe_bitmaps_p = 1;
2696 /* When a window has disappeared, make sure that no rest of
2697 full-width rows stays visible in the internal border. */
2698 if (windows_or_buffers_changed
2699 && desired_row->full_width_p
2700 && (f = XFRAME (w->frame),
2701 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2703 && (height = desired_row->visible_height,
2706 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2709 ns_clear_frame_area (f, 0, y, width, height);
2710 ns_clear_frame_area (f,
2711 FRAME_PIXEL_WIDTH (f) - width,
2719 ns_shift_glyphs_for_insert (struct frame *f,
2720 int x, int y, int width, int height,
2722 /* --------------------------------------------------------------------------
2723 External (RIF): copy an area horizontally, don't worry about clearing src
2724 -------------------------------------------------------------------------- */
2726 NSRect srcRect = NSMakeRect (x, y, width, height);
2727 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2729 NSTRACE ("ns_shift_glyphs_for_insert");
2731 ns_copy_bits (f, srcRect, dstRect);
2736 /* ==========================================================================
2738 Character encoding and metrics
2740 ========================================================================== */
2744 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2745 /* --------------------------------------------------------------------------
2746 External (RIF); compute left/right overhang of whole string and set in s
2747 -------------------------------------------------------------------------- */
2749 struct font *font = s->font;
2753 struct font_metrics metrics;
2754 unsigned int codes[2];
2755 codes[0] = *(s->char2b);
2756 codes[1] = *(s->char2b + s->nchars - 1);
2758 font->driver->text_extents (font, codes, 2, &metrics);
2759 s->left_overhang = -metrics.lbearing;
2761 = metrics.rbearing > metrics.width
2762 ? metrics.rbearing - metrics.width : 0;
2766 s->left_overhang = 0;
2767 if (EQ (font->driver->type, Qns))
2768 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2769 FONT_HEIGHT (font) * 0.2 : 0;
2771 s->right_overhang = 0;
2777 /* ==========================================================================
2779 Fringe and cursor drawing
2781 ========================================================================== */
2784 extern int max_used_fringe_bitmap;
2786 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2787 struct draw_fringe_bitmap_params *p)
2788 /* --------------------------------------------------------------------------
2789 External (RIF); fringe-related
2790 -------------------------------------------------------------------------- */
2792 /* Fringe bitmaps comes in two variants, normal and periodic. A
2793 periodic bitmap is used to create a continuous pattern. Since a
2794 bitmap is rendered one text line at a time, the start offset (dh)
2795 of the bitmap varies. Concretely, this is used for the empty
2798 For a bitmap, "h + dh" is the full height and is always
2799 invariant. For a normal bitmap "dh" is zero.
2801 For example, when the period is three and the full height is 72
2802 the following combinations exists:
2808 struct frame *f = XFRAME (WINDOW_FRAME (w));
2809 struct face *face = p->face;
2810 static EmacsImage **bimgs = NULL;
2811 static int nBimgs = 0;
2813 NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2814 NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2815 p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2817 /* grow bimgs if needed */
2818 if (nBimgs < max_used_fringe_bitmap)
2820 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2821 memset (bimgs + nBimgs, 0,
2822 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2823 nBimgs = max_used_fringe_bitmap;
2826 /* Must clip because of partially visible lines. */
2827 ns_clip_to_row (w, row, ANY_AREA, YES);
2831 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2833 if (bx >= 0 && nx > 0)
2835 NSRect r = NSMakeRect (bx, by, nx, ny);
2837 [ns_lookup_indexed_color (face->background, f) set];
2844 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2845 EmacsImage *img = bimgs[p->which - 1];
2849 // Note: For "periodic" images, allocate one EmacsImage for
2850 // the base image, and use it for all dh:s.
2851 unsigned short *bits = p->bits;
2852 int full_height = p->h + p->dh;
2854 unsigned char *cbits = xmalloc (full_height);
2856 for (i = 0; i < full_height; i++)
2858 img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2861 bimgs[p->which - 1] = img;
2865 NSTRACE_RECT ("r", r);
2868 /* Since we composite the bitmap instead of just blitting it, we need
2869 to erase the whole background. */
2870 [ns_lookup_indexed_color(face->background, f) set];
2876 bm_color = ns_lookup_indexed_color(face->foreground, f);
2877 else if (p->overlay_p)
2878 bm_color = ns_lookup_indexed_color(face->background, f);
2880 bm_color = f->output_data.ns->cursor_color;
2881 [img setXBMColor: bm_color];
2884 #ifdef NS_IMPL_COCOA
2885 // Note: For periodic images, the full image height is "h + hd".
2886 // By using the height h, a suitable part of the image is used.
2887 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2889 NSTRACE_RECT ("fromRect", fromRect);
2893 operation: NSCompositingOperationSourceOver
2899 NSPoint pt = r.origin;
2901 [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
2910 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2911 int x, int y, enum text_cursor_kinds cursor_type,
2912 int cursor_width, bool on_p, bool active_p)
2913 /* --------------------------------------------------------------------------
2914 External call (RIF): draw cursor.
2915 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2916 -------------------------------------------------------------------------- */
2919 int fx, fy, h, cursor_height;
2920 struct frame *f = WINDOW_XFRAME (w);
2921 struct glyph *phys_cursor_glyph;
2922 struct glyph *cursor_glyph;
2924 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2926 /* If cursor is out of bounds, don't draw garbage. This can happen
2927 in mini-buffer windows when switching between echo area glyphs
2930 NSTRACE ("ns_draw_window_cursor");
2935 w->phys_cursor_type = cursor_type;
2936 w->phys_cursor_on_p = on_p;
2938 if (cursor_type == NO_CURSOR)
2940 w->phys_cursor_width = 0;
2944 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2946 if (glyph_row->exact_window_width_line_p
2947 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2949 glyph_row->cursor_in_fringe_p = 1;
2950 draw_fringe_bitmap (w, glyph_row, 0);
2955 /* We draw the cursor (with NSRectFill), then draw the glyph on top
2956 (other terminals do it the other way round). We must set
2957 w->phys_cursor_width to the cursor width. For bar cursors, that
2958 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
2959 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2961 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2962 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2963 if (cursor_type == BAR_CURSOR)
2965 if (cursor_width < 1)
2966 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2968 /* The bar cursor should never be wider than the glyph. */
2969 if (cursor_width < w->phys_cursor_width)
2970 w->phys_cursor_width = cursor_width;
2972 /* If we have an HBAR, "cursor_width" MAY specify height. */
2973 else if (cursor_type == HBAR_CURSOR)
2975 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2976 if (cursor_height > glyph_row->height)
2977 cursor_height = glyph_row->height;
2978 if (h > cursor_height) // Cursor smaller than line height, move down
2979 fy += h - cursor_height;
2983 r.origin.x = fx, r.origin.y = fy;
2985 r.size.width = w->phys_cursor_width;
2987 /* Prevent the cursor from being drawn outside the text area. */
2988 ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2991 face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
2992 if (face && NS_FACE_BACKGROUND (face)
2993 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2995 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2996 hollow_color = FRAME_CURSOR_COLOR (f);
2999 [FRAME_CURSOR_COLOR (f) set];
3001 #ifdef NS_IMPL_COCOA
3002 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
3003 atomic. Cleaner ways of doing this should be investigated.
3004 One way would be to set a global variable DRAWING_CURSOR
3005 when making the call to draw_phys..(), don't focus in that
3006 case, then move the ns_unfocus() here after that call. */
3007 NSDisableScreenUpdates ();
3010 switch (cursor_type)
3012 case DEFAULT_CURSOR:
3015 case FILLED_BOX_CURSOR:
3018 case HOLLOW_BOX_CURSOR:
3021 NSRectFill (NSInsetRect (r, 1, 1));
3022 [FRAME_CURSOR_COLOR (f) set];
3029 /* If the character under cursor is R2L, draw the bar cursor
3030 on the right of its glyph, rather than on the left. */
3031 cursor_glyph = get_phys_cursor_glyph (w);
3032 if ((cursor_glyph->resolved_level & 1) != 0)
3033 s.origin.x += cursor_glyph->pixel_width - s.size.width;
3040 /* draw the character under the cursor */
3041 if (cursor_type != NO_CURSOR)
3042 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3044 #ifdef NS_IMPL_COCOA
3045 NSEnableScreenUpdates ();
3052 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
3053 /* --------------------------------------------------------------------------
3054 External (RIF): Draw a vertical line.
3055 -------------------------------------------------------------------------- */
3057 struct frame *f = XFRAME (WINDOW_FRAME (w));
3059 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
3061 NSTRACE ("ns_draw_vertical_window_border");
3063 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
3065 ns_focus (f, &r, 1);
3067 [ns_lookup_indexed_color(face->foreground, f) set];
3075 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3076 /* --------------------------------------------------------------------------
3077 External (RIF): Draw a window divider.
3078 -------------------------------------------------------------------------- */
3080 struct frame *f = XFRAME (WINDOW_FRAME (w));
3082 NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
3084 NSTRACE ("ns_draw_window_divider");
3086 face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
3088 ns_focus (f, &r, 1);
3090 [ns_lookup_indexed_color(face->foreground, f) set];
3097 ns_show_hourglass (struct frame *f)
3099 /* TODO: add NSProgressIndicator to all frames. */
3103 ns_hide_hourglass (struct frame *f)
3105 /* TODO: remove NSProgressIndicator from all frames. */
3108 /* ==========================================================================
3110 Glyph drawing operations
3112 ========================================================================== */
3115 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3116 /* --------------------------------------------------------------------------
3117 Wrapper utility to account for internal border width on full-width lines,
3118 and allow top full-width rows to hit the frame top. nr should be pointer
3119 to two successive NSRects. Number of rects actually used is returned.
3120 -------------------------------------------------------------------------- */
3122 int n = get_glyph_string_clip_rects (s, nr, 2);
3126 /* --------------------------------------------------------------------
3127 Draw a wavy line under glyph string s. The wave fills wave_height
3134 wave_height = 3 | * * * *
3135 --------------------------------------------------------------------- */
3138 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3140 int wave_height = 3, wave_length = 2;
3141 int y, dx, dy, odd, xmax;
3146 dy = wave_height - 1;
3147 y = s->ybase - wave_height + 3;
3150 /* Find and set clipping rectangle */
3151 waveClip = NSMakeRect (x, y, width, wave_height);
3152 [[NSGraphicsContext currentContext] saveGraphicsState];
3153 NSRectClip (waveClip);
3155 /* Draw the waves */
3156 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3158 odd = (int)(a.x/dx) % 2;
3159 a.y = b.y = y + 0.5;
3168 [NSBezierPath strokeLineFromPoint:a toPoint:b];
3169 a.x = b.x, a.y = b.y;
3170 b.x += dx, b.y = y + 0.5 + odd*dy;
3174 /* Restore previous clipping rectangle(s) */
3175 [[NSGraphicsContext currentContext] restoreGraphicsState];
3181 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3182 NSColor *defaultCol, CGFloat width, CGFloat x)
3183 /* --------------------------------------------------------------------------
3184 Draw underline, overline, and strike-through on glyph string s.
3185 -------------------------------------------------------------------------- */
3187 if (s->for_overlaps)
3191 if (face->underline_p)
3193 if (s->face->underline_type == FACE_UNDER_WAVE)
3195 if (face->underline_defaulted_p)
3198 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3200 ns_draw_underwave (s, width, x);
3202 else if (s->face->underline_type == FACE_UNDER_LINE)
3206 unsigned long thickness, position;
3208 /* If the prev was underlined, match its appearance. */
3209 if (s->prev && s->prev->face->underline_p
3210 && s->prev->face->underline_type == FACE_UNDER_LINE
3211 && s->prev->underline_thickness > 0)
3213 thickness = s->prev->underline_thickness;
3214 position = s->prev->underline_position;
3218 struct font *font = font_for_underline_metrics (s);
3219 unsigned long descent = s->y + s->height - s->ybase;
3221 /* Use underline thickness of font, defaulting to 1. */
3222 thickness = (font && font->underline_thickness > 0)
3223 ? font->underline_thickness : 1;
3225 /* Determine the offset of underlining from the baseline. */
3226 if (x_underline_at_descent_line)
3227 position = descent - thickness;
3228 else if (x_use_underline_position_properties
3229 && font && font->underline_position >= 0)
3230 position = font->underline_position;
3232 position = lround (font->descent / 2);
3234 position = underline_minimum_offset;
3236 position = max (position, underline_minimum_offset);
3238 /* Ensure underlining is not cropped. */
3239 if (descent <= position)
3241 position = descent - 1;
3244 else if (descent < position + thickness)
3248 s->underline_thickness = thickness;
3249 s->underline_position = position;
3251 r = NSMakeRect (x, s->ybase + position, width, thickness);
3253 if (face->underline_defaulted_p)
3256 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3260 /* Do overline. We follow other terms in using a thickness of 1
3261 and ignoring overline_margin. */
3262 if (face->overline_p)
3265 r = NSMakeRect (x, s->y, width, 1);
3267 if (face->overline_color_defaulted_p)
3270 [ns_lookup_indexed_color (face->overline_color, s->f) set];
3274 /* Do strike-through. We follow other terms for thickness and
3275 vertical position.*/
3276 if (face->strike_through_p)
3279 /* Y-coordinate and height of the glyph string's first glyph.
3280 We cannot use s->y and s->height because those could be
3281 larger if there are taller display elements (e.g., characters
3282 displayed with a larger font) in the same glyph row. */
3283 int glyph_y = s->ybase - s->first_glyph->ascent;
3284 int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
3285 /* Strike-through width and offset from the glyph string's
3287 unsigned long h = 1;
3290 dy = lrint ((glyph_height - h) / 2);
3291 r = NSMakeRect (x, glyph_y + dy, width, 1);
3293 if (face->strike_through_color_defaulted_p)
3296 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3302 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3303 char left_p, char right_p)
3304 /* --------------------------------------------------------------------------
3305 Draw an unfilled rect inside r, optionally leaving left and/or right open.
3306 Note we can't just use an NSDrawRect command, because of the possibility
3307 of some sides not being drawn, and because the rect will be filled.
3308 -------------------------------------------------------------------------- */
3314 s.size.height = thickness;
3316 s.origin.y += r.size.height - thickness;
3319 s.size.height = r.size.height;
3320 s.origin.y = r.origin.y;
3322 /* left, right (optional) */
3323 s.size.width = thickness;
3328 s.origin.x += r.size.width - thickness;
3335 ns_draw_relief (NSRect r, int thickness, char raised_p,
3336 char top_p, char bottom_p, char left_p, char right_p,
3337 struct glyph_string *s)
3338 /* --------------------------------------------------------------------------
3339 Draw a relief rect inside r, optionally leaving some sides open.
3340 Note we can't just use an NSDrawBezel command, because of the possibility
3341 of some sides not being drawn, and because the rect will be filled.
3342 -------------------------------------------------------------------------- */
3344 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3345 NSColor *newBaseCol = nil;
3348 NSTRACE ("ns_draw_relief");
3352 if (s->face->use_box_color_for_shadows_p)
3354 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3356 /* else if (s->first_glyph->type == IMAGE_GLYPH
3358 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3360 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
3364 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3367 if (newBaseCol == nil)
3368 newBaseCol = [NSColor grayColor];
3370 if (newBaseCol != baseCol) /* TODO: better check */
3373 baseCol = [newBaseCol retain];
3375 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3377 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3380 [(raised_p ? lightCol : darkCol) set];
3382 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3385 sr.size.height = thickness;
3386 if (top_p) NSRectFill (sr);
3389 sr.size.height = r.size.height;
3390 sr.size.width = thickness;
3391 if (left_p) NSRectFill (sr);
3393 [(raised_p ? darkCol : lightCol) set];
3396 sr.size.width = r.size.width;
3397 sr.size.height = thickness;
3398 sr.origin.y += r.size.height - thickness;
3399 if (bottom_p) NSRectFill (sr);
3402 sr.size.height = r.size.height;
3403 sr.origin.y = r.origin.y;
3404 sr.size.width = thickness;
3405 sr.origin.x += r.size.width - thickness;
3406 if (right_p) NSRectFill (sr);
3411 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3412 /* --------------------------------------------------------------------------
3413 Function modeled after x_draw_glyph_string_box ().
3414 Sets up parameters for drawing.
3415 -------------------------------------------------------------------------- */
3417 int right_x, last_x;
3418 char left_p, right_p;
3419 struct glyph *last_glyph;
3424 if (s->hl == DRAW_MOUSE_FACE)
3426 face = FACE_FROM_ID_OR_NULL (s->f,
3427 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3429 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3434 thickness = face->box_line_width;
3436 NSTRACE ("ns_dumpglyphs_box_or_relief");
3438 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3439 ? WINDOW_RIGHT_EDGE_X (s->w)
3440 : window_box_right (s->w, s->area));
3441 last_glyph = (s->cmp || s->img
3442 ? s->first_glyph : s->first_glyph + s->nchars-1);
3444 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3445 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3447 left_p = (s->first_glyph->left_box_line_p
3448 || (s->hl == DRAW_MOUSE_FACE
3449 && (s->prev == NULL || s->prev->hl != s->hl)));
3450 right_p = (last_glyph->right_box_line_p
3451 || (s->hl == DRAW_MOUSE_FACE
3452 && (s->next == NULL || s->next->hl != s->hl)));
3454 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3456 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3457 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3459 ns_draw_box (r, abs (thickness),
3460 ns_lookup_indexed_color (face->box_color, s->f),
3465 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3466 1, 1, left_p, right_p, s);
3472 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3473 /* --------------------------------------------------------------------------
3474 Modeled after x_draw_glyph_string_background, which draws BG in
3475 certain cases. Others are left to the text rendering routine.
3476 -------------------------------------------------------------------------- */
3478 NSTRACE ("ns_maybe_dumpglyphs_background");
3480 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3482 int box_line_width = max (s->face->box_line_width, 0);
3483 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3484 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3485 dimensions, since the actual glyphs might be much
3486 smaller. So in that case we always clear the rectangle
3487 with background color. */
3488 || FONT_TOO_HIGH (s->font)
3489 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3492 if (s->hl == DRAW_MOUSE_FACE)
3495 = FACE_FROM_ID_OR_NULL (s->f,
3496 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3498 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3501 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3503 [(NS_FACE_BACKGROUND (face) != 0
3504 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3505 : FRAME_BACKGROUND_COLOR (s->f)) set];
3508 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3509 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3512 if (s->hl != DRAW_CURSOR)
3514 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3515 s->background_width,
3516 s->height-2*box_line_width);
3520 s->background_filled_p = 1;
3527 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3528 /* --------------------------------------------------------------------------
3529 Renders an image and associated borders.
3530 -------------------------------------------------------------------------- */
3532 EmacsImage *img = s->img->pixmap;
3533 int box_line_vwidth = max (s->face->box_line_width, 0);
3534 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3535 int bg_x, bg_y, bg_height;
3542 NSTRACE ("ns_dumpglyphs_image");
3544 if (s->face->box != FACE_NO_BOX
3545 && s->first_glyph->left_box_line_p && s->slice.x == 0)
3546 x += abs (s->face->box_line_width);
3549 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3550 bg_height = s->height;
3551 /* other terms have this, but was causing problems w/tabbar mode */
3552 /* - 2 * box_line_vwidth; */
3554 if (s->slice.x == 0) x += s->img->hmargin;
3555 if (s->slice.y == 0) y += s->img->vmargin;
3557 /* Draw BG: if we need larger area than image itself cleared, do that,
3558 otherwise, since we composite the image under NS (instead of mucking
3559 with its background color), we must clear just the image area. */
3560 if (s->hl == DRAW_MOUSE_FACE)
3562 face = FACE_FROM_ID_OR_NULL (s->f,
3563 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3565 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3568 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3570 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3572 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3573 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3575 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3576 s->background_filled_p = 1;
3580 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3585 /* Draw the image.. do we need to draw placeholder if img ==nil? */
3588 #ifdef NS_IMPL_COCOA
3589 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3590 NSRect ir = NSMakeRect (s->slice.x,
3591 s->img->height - s->slice.y - s->slice.height,
3592 s->slice.width, s->slice.height);
3595 operation: NSCompositingOperationSourceOver
3600 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3601 operation: NSCompositingOperationSourceOver];
3605 if (s->hl == DRAW_CURSOR)
3607 [FRAME_CURSOR_COLOR (s->f) set];
3608 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3609 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3611 /* Currently on NS img->mask is always 0. Since
3612 get_window_cursor_type specifies a hollow box cursor when on
3613 a non-masked image we never reach this clause. But we put it
3614 in in anticipation of better support for image masks on
3616 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3620 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3623 /* Draw underline, overline, strike-through. */
3624 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3626 /* Draw relief, if requested */
3627 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3629 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3631 th = tool_bar_button_relief >= 0 ?
3632 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3633 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3637 th = abs (s->img->relief);
3638 raised_p = (s->img->relief > 0);
3641 r.origin.x = x - th;
3642 r.origin.y = y - th;
3643 r.size.width = s->slice.width + 2*th-1;
3644 r.size.height = s->slice.height + 2*th-1;
3645 ns_draw_relief (r, th, raised_p,
3647 s->slice.y + s->slice.height == s->img->height,
3649 s->slice.x + s->slice.width == s->img->width, s);
3652 /* If there is no mask, the background won't be seen,
3653 so draw a rectangle on the image for the cursor.
3654 Do this for all images, getting transparency right is not reliable. */
3655 if (s->hl == DRAW_CURSOR)
3657 int thickness = abs (s->img->relief);
3658 if (thickness == 0) thickness = 1;
3659 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3665 ns_dumpglyphs_stretch (struct glyph_string *s)
3670 NSColor *fgCol, *bgCol;
3672 if (!s->background_filled_p)
3674 n = ns_get_glyph_string_clip_rect (s, r);
3675 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3677 ns_focus (s->f, r, n);
3679 if (s->hl == DRAW_MOUSE_FACE)
3681 face = FACE_FROM_ID_OR_NULL (s->f,
3682 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3684 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3687 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3689 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3690 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3692 for (i = 0; i < n; ++i)
3694 if (!s->row->full_width_p)
3696 int overrun, leftoverrun;
3698 /* truncate to avoid overwriting fringe and/or scrollbar */
3699 overrun = max (0, (s->x + s->background_width)
3700 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3701 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3702 r[i].size.width -= overrun;
3704 /* truncate to avoid overwriting to left of the window box */
3705 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3706 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3708 if (leftoverrun > 0)
3710 r[i].origin.x += leftoverrun;
3711 r[i].size.width -= leftoverrun;
3714 /* XXX: Try to work between problem where a stretch glyph on
3715 a partially-visible bottom row will clear part of the
3716 modeline, and another where list-buffers headers and similar
3717 rows erroneously have visible_height set to 0. Not sure
3718 where this is coming from as other terms seem not to show. */
3719 r[i].size.height = min (s->height, s->row->visible_height);
3724 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3725 overwriting cursor (usually when cursor on a tab) */
3726 if (s->hl == DRAW_CURSOR)
3731 width = s->w->phys_cursor_width;
3732 r[i].size.width -= width;
3733 r[i].origin.x += width;
3737 /* Draw overlining, etc. on the cursor. */
3738 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3739 ns_draw_text_decoration (s, face, bgCol, width, x);
3741 ns_draw_text_decoration (s, face, fgCol, width, x);
3748 /* Draw overlining, etc. on the stretch glyph (or the part
3749 of the stretch glyph after the cursor). */
3750 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3754 s->background_filled_p = 1;
3760 ns_draw_glyph_string_foreground (struct glyph_string *s)
3763 struct font *font = s->font;
3765 /* If first glyph of S has a left box line, start drawing the text
3766 of S to the right of that box line. */
3767 if (s->face && s->face->box != FACE_NO_BOX
3768 && s->first_glyph->left_box_line_p)
3769 x = s->x + eabs (s->face->box_line_width);
3773 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3774 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3775 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3776 NS_DUMPGLYPH_NORMAL));
3779 (s, s->cmp_from, s->nchars, x, s->ybase,
3780 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3781 || flags == NS_DUMPGLYPH_MOUSEFACE);
3786 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3789 struct font *font = s->font;
3791 /* If first glyph of S has a left box line, start drawing the text
3792 of S to the right of that box line. */
3793 if (s->face && s->face->box != FACE_NO_BOX
3794 && s->first_glyph->left_box_line_p)
3795 x = s->x + eabs (s->face->box_line_width);
3799 /* S is a glyph string for a composition. S->cmp_from is the index
3800 of the first character drawn for glyphs of this composition.
3801 S->cmp_from == 0 means we are drawing the very first character of
3802 this composition. */
3804 /* Draw a rectangle for the composition if the font for the very
3805 first character of the composition could not be loaded. */
3806 if (s->font_not_found_p)
3808 if (s->cmp_from == 0)
3810 NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3811 ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3814 else if (! s->first_glyph->u.cmp.automatic)
3818 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3819 /* TAB in a composition means display glyphs with padding
3820 space on the left or right. */
3821 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3823 int xx = x + s->cmp->offsets[j * 2];
3824 int yy = y - s->cmp->offsets[j * 2 + 1];
3826 font->driver->draw (s, j, j + 1, xx, yy, false);
3827 if (s->face->overstrike)
3828 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3833 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3838 for (i = j = s->cmp_from; i < s->cmp_to; i++)
3840 glyph = LGSTRING_GLYPH (gstring, i);
3841 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3842 width += LGLYPH_WIDTH (glyph);
3845 int xoff, yoff, wadjust;
3849 font->driver->draw (s, j, i, x, y, false);
3850 if (s->face->overstrike)
3851 font->driver->draw (s, j, i, x + 1, y, false);
3854 xoff = LGLYPH_XOFF (glyph);
3855 yoff = LGLYPH_YOFF (glyph);
3856 wadjust = LGLYPH_WADJUST (glyph);
3857 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3858 if (s->face->overstrike)
3859 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3868 font->driver->draw (s, j, i, x, y, false);
3869 if (s->face->overstrike)
3870 font->driver->draw (s, j, i, x + 1, y, false);
3876 ns_draw_glyph_string (struct glyph_string *s)
3877 /* --------------------------------------------------------------------------
3878 External (RIF): Main draw-text call.
3879 -------------------------------------------------------------------------- */
3881 /* TODO (optimize): focus for box and contents draw */
3884 char box_drawn_p = 0;
3885 struct font *font = s->face->font;
3886 if (! font) font = FRAME_FONT (s->f);
3888 NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3890 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3893 struct glyph_string *next;
3895 for (width = 0, next = s->next;
3896 next && width < s->right_overhang;
3897 width += next->width, next = next->next)
3898 if (next->first_glyph->type != IMAGE_GLYPH)
3900 if (next->first_glyph->type != STRETCH_GLYPH)
3902 n = ns_get_glyph_string_clip_rect (s->next, r);
3903 ns_focus (s->f, r, n);
3904 ns_maybe_dumpglyphs_background (s->next, 1);
3909 ns_dumpglyphs_stretch (s->next);
3911 next->num_clips = 0;
3915 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3916 && (s->first_glyph->type == CHAR_GLYPH
3917 || s->first_glyph->type == COMPOSITE_GLYPH))
3919 n = ns_get_glyph_string_clip_rect (s, r);
3920 ns_focus (s->f, r, n);
3921 ns_maybe_dumpglyphs_background (s, 1);
3922 ns_dumpglyphs_box_or_relief (s);
3927 switch (s->first_glyph->type)
3931 n = ns_get_glyph_string_clip_rect (s, r);
3932 ns_focus (s->f, r, n);
3933 ns_dumpglyphs_image (s, r[0]);
3938 ns_dumpglyphs_stretch (s);
3942 case COMPOSITE_GLYPH:
3943 n = ns_get_glyph_string_clip_rect (s, r);
3944 ns_focus (s->f, r, n);
3946 if (s->for_overlaps || (s->cmp_from > 0
3947 && ! s->first_glyph->u.cmp.automatic))
3948 s->background_filled_p = 1;
3950 ns_maybe_dumpglyphs_background
3951 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3953 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3955 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3956 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3957 NS_FACE_FOREGROUND (s->face) = tmp;
3961 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3964 ns_draw_composite_glyph_string_foreground (s);
3966 ns_draw_glyph_string_foreground (s);
3970 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3971 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3973 : FRAME_FOREGROUND_COLOR (s->f));
3976 /* Draw underline, overline, strike-through. */
3977 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3980 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3982 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3983 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3984 NS_FACE_FOREGROUND (s->face) = tmp;
3990 case GLYPHLESS_GLYPH:
3991 n = ns_get_glyph_string_clip_rect (s, r);
3992 ns_focus (s->f, r, n);
3994 if (s->for_overlaps || (s->cmp_from > 0
3995 && ! s->first_glyph->u.cmp.automatic))
3996 s->background_filled_p = 1;
3998 ns_maybe_dumpglyphs_background
3999 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4001 /* Not yet implemented. */
4010 /* Draw box if not done already. */
4011 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
4013 n = ns_get_glyph_string_clip_rect (s, r);
4014 ns_focus (s->f, r, n);
4015 ns_dumpglyphs_box_or_relief (s);
4024 /* ==========================================================================
4028 ========================================================================== */
4032 ns_send_appdefined (int value)
4033 /* --------------------------------------------------------------------------
4034 Internal: post an appdefined event which EmacsApp-sendEvent will
4035 recognize and take as a command to halt the event loop.
4036 -------------------------------------------------------------------------- */
4038 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
4040 // GNUstep needs postEvent to happen on the main thread.
4041 // Cocoa needs nextEventMatchingMask to happen on the main thread too.
4042 if (! [[NSThread currentThread] isMainThread])
4044 EmacsApp *app = (EmacsApp *)NSApp;
4045 app->nextappdefined = value;
4046 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
4052 /* Only post this event if we haven't already posted one. This will end
4053 the [NXApp run] main loop after having processed all events queued at
4056 #ifdef NS_IMPL_COCOA
4057 if (! send_appdefined)
4059 /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves
4060 in certain situations (rapid incoming events).
4061 So check if we have one, if not add one. */
4062 NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
4063 untilDate:[NSDate distantPast]
4064 inMode:NSDefaultRunLoopMode
4066 if (! appev) send_appdefined = YES;
4070 if (send_appdefined)
4074 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
4075 send_appdefined = NO;
4077 /* Don't need wakeup timer any more */
4080 [timed_entry invalidate];
4081 [timed_entry release];
4085 nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
4086 location: NSMakePoint (0, 0)
4089 windowNumber: [[NSApp mainWindow] windowNumber]
4090 context: [NSApp context]
4095 /* Post an application defined event on the event queue. When this is
4096 received the [NXApp run] will return, thus having processed all
4097 events which are currently queued. */
4098 [NSApp postEvent: nxev atStart: NO];
4102 #ifdef HAVE_NATIVE_FS
4106 Lisp_Object frame, tail;
4108 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
4111 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
4113 FOR_EACH_FRAME (tail, frame)
4115 struct frame *f = XFRAME (frame);
4118 EmacsView *view = FRAME_NS_VIEW (f);
4119 [view updateCollectionBehavior];
4125 /* GNUstep does not have cancelTracking. */
4126 #ifdef NS_IMPL_COCOA
4127 /* Check if menu open should be canceled or continued as normal. */
4129 ns_check_menu_open (NSMenu *menu)
4131 /* Click in menu bar? */
4132 NSArray *a = [[NSApp mainMenu] itemArray];
4136 if (menu == nil) // Menu tracking ended.
4138 if (menu_will_open_state == MENU_OPENING)
4139 menu_will_open_state = MENU_NONE;
4143 for (i = 0; ! found && i < [a count]; i++)
4144 found = menu == [[a objectAtIndex:i] submenu];
4147 if (menu_will_open_state == MENU_NONE && emacs_event)
4149 NSEvent *theEvent = [NSApp currentEvent];
4150 struct frame *emacsframe = SELECTED_FRAME ();
4152 [menu cancelTracking];
4153 menu_will_open_state = MENU_PENDING;
4154 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4155 EV_TRAILER (theEvent);
4157 CGEventRef ourEvent = CGEventCreate (NULL);
4158 menu_mouse_point = CGEventGetLocation (ourEvent);
4159 CFRelease (ourEvent);
4161 else if (menu_will_open_state == MENU_OPENING)
4163 menu_will_open_state = MENU_NONE;
4168 /* Redo saved menu click if state is MENU_PENDING. */
4170 ns_check_pending_open_menu ()
4172 if (menu_will_open_state == MENU_PENDING)
4174 CGEventSourceRef source
4175 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4177 CGEventRef event = CGEventCreateMouseEvent (source,
4178 kCGEventLeftMouseDown,
4180 kCGMouseButtonLeft);
4181 CGEventSetType (event, kCGEventLeftMouseDown);
4182 CGEventPost (kCGHIDEventTap, event);
4186 menu_will_open_state = MENU_OPENING;
4189 #endif /* NS_IMPL_COCOA */
4192 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4193 /* --------------------------------------------------------------------------
4194 External (hook): Post an event to ourself and keep reading events until
4195 we read it back again. In effect process all events which were waiting.
4196 From 21+ we have to manage the event buffer ourselves.
4197 -------------------------------------------------------------------------- */
4199 struct input_event ev;
4202 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4204 #ifdef HAVE_NATIVE_FS
4208 if ([NSApp modalWindow] != nil)
4211 if (hold_event_q.nr > 0)
4214 for (i = 0; i < hold_event_q.nr; ++i)
4215 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4216 hold_event_q.nr = 0;
4220 if ([NSThread isMainThread])
4223 n_emacs_events_pending = 0;
4224 ns_init_events (&ev);
4225 q_event_ptr = hold_quit;
4227 /* we manage autorelease pools by allocate/reallocate each time around
4228 the loop; strict nesting is occasionally violated but seems not to
4229 matter.. earlier methods using full nesting caused major memory leaks */
4230 [outerpool release];
4231 outerpool = [[NSAutoreleasePool alloc] init];
4233 /* If have pending open-file requests, attend to the next one of those. */
4234 if (ns_pending_files && [ns_pending_files count] != 0
4235 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4237 [ns_pending_files removeObjectAtIndex: 0];
4239 /* Deal with pending service requests. */
4240 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4242 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4243 withArg: [ns_pending_service_args objectAtIndex: 0]])
4245 [ns_pending_service_names removeObjectAtIndex: 0];
4246 [ns_pending_service_args removeObjectAtIndex: 0];
4250 ptrdiff_t specpdl_count = SPECPDL_INDEX ();
4251 /* Run and wait for events. We must always send one NX_APPDEFINED event
4252 to ourself, otherwise [NXApp run] will never exit. */
4253 send_appdefined = YES;
4254 ns_send_appdefined (-1);
4259 nevents = n_emacs_events_pending;
4260 n_emacs_events_pending = 0;
4261 ns_finish_events ();
4271 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4272 fd_set *exceptfds, struct timespec const *timeout,
4273 sigset_t const *sigmask)
4274 /* --------------------------------------------------------------------------
4275 Replacement for select, checking for events
4276 -------------------------------------------------------------------------- */
4280 struct input_event event;
4283 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4285 #ifdef HAVE_NATIVE_FS
4289 if (hold_event_q.nr > 0)
4291 /* We already have events pending. */
4297 for (k = 0; k < nfds+1; k++)
4299 if (readfds && FD_ISSET(k, readfds)) ++nr;
4300 if (writefds && FD_ISSET(k, writefds)) ++nr;
4304 || ![NSThread isMainThread]
4305 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4306 return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
4308 [outerpool release];
4309 outerpool = [[NSAutoreleasePool alloc] init];
4312 send_appdefined = YES;
4315 pthread_mutex_lock (&select_mutex);
4320 select_readfds = *readfds;
4321 select_valid += SELECT_HAVE_READ;
4325 select_writefds = *writefds;
4326 select_valid += SELECT_HAVE_WRITE;
4331 select_timeout = *timeout;
4332 select_valid += SELECT_HAVE_TMO;
4335 pthread_mutex_unlock (&select_mutex);
4337 /* Inform fd_handler that select should be called */
4339 emacs_write_sig (selfds[1], &c, 1);
4341 else if (nr == 0 && timeout)
4343 /* No file descriptor, just a timeout, no need to wake fd_handler */
4344 double time = timespectod (*timeout);
4345 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4348 @selector (timeout_handler:)
4353 else /* No timeout and no file descriptors, can this happen? */
4355 /* Send appdefined so we exit from the loop */
4356 ns_send_appdefined (-1);
4360 ns_init_events (&event);
4364 ns_finish_events ();
4365 if (nr > 0 && readfds)
4368 emacs_write_sig (selfds[1], &c, 1);
4372 t = last_appdefined_event_data;
4374 if (t != NO_APPDEFINED_DATA)
4376 last_appdefined_event_data = NO_APPDEFINED_DATA;
4380 /* The NX_APPDEFINED event we received was a timeout. */
4385 /* The NX_APPDEFINED event we received was the result of
4386 at least one real input event arriving. */
4392 /* Received back from select () in fd_handler; copy the results */
4393 pthread_mutex_lock (&select_mutex);
4394 if (readfds) *readfds = select_readfds;
4395 if (writefds) *writefds = select_writefds;
4396 pthread_mutex_unlock (&select_mutex);
4411 /* ==========================================================================
4415 ========================================================================== */
4419 ns_set_vertical_scroll_bar (struct window *window,
4420 int portion, int whole, int position)
4421 /* --------------------------------------------------------------------------
4422 External (hook): Update or add scrollbar
4423 -------------------------------------------------------------------------- */
4427 struct frame *f = XFRAME (WINDOW_FRAME (window));
4428 EmacsView *view = FRAME_NS_VIEW (f);
4430 int window_y, window_height;
4431 int top, left, height, width;
4432 BOOL update_p = YES;
4434 /* optimization; display engine sends WAY too many of these.. */
4435 if (!NILP (window->vertical_scroll_bar))
4437 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4438 if ([bar checkSamePosition: position portion: portion whole: whole])
4440 if (view->scrollbarsNeedingUpdate == 0)
4442 if (!windows_or_buffers_changed)
4446 view->scrollbarsNeedingUpdate--;
4451 NSTRACE ("ns_set_vertical_scroll_bar");
4453 /* Get dimensions. */
4454 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4456 height = window_height;
4457 width = NS_SCROLL_BAR_WIDTH (f);
4458 left = WINDOW_SCROLL_BAR_AREA_X (window);
4460 r = NSMakeRect (left, top, width, height);
4461 /* the parent view is flipped, so we need to flip y value */
4463 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4465 XSETWINDOW (win, window);
4468 /* we want at least 5 lines to display a scrollbar */
4469 if (WINDOW_TOTAL_LINES (window) < 5)
4471 if (!NILP (window->vertical_scroll_bar))
4473 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4474 [bar removeFromSuperview];
4475 wset_vertical_scroll_bar (window, Qnil);
4478 ns_clear_frame_area (f, left, top, width, height);
4483 if (NILP (window->vertical_scroll_bar))
4485 if (width > 0 && height > 0)
4486 ns_clear_frame_area (f, left, top, width, height);
4488 bar = [[EmacsScroller alloc] initFrame: r window: win];
4489 wset_vertical_scroll_bar (window, make_save_ptr (bar));
4495 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4496 oldRect = [bar frame];
4497 r.size.width = oldRect.size.width;
4498 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4500 if (oldRect.origin.x != r.origin.x)
4501 ns_clear_frame_area (f, left, top, width, height);
4507 [bar setPosition: position portion: portion whole: whole];
4513 ns_set_horizontal_scroll_bar (struct window *window,
4514 int portion, int whole, int position)
4515 /* --------------------------------------------------------------------------
4516 External (hook): Update or add scrollbar
4517 -------------------------------------------------------------------------- */
4521 struct frame *f = XFRAME (WINDOW_FRAME (window));
4522 EmacsView *view = FRAME_NS_VIEW (f);
4524 int top, height, left, width;
4525 int window_x, window_width;
4526 BOOL update_p = YES;
4528 /* optimization; display engine sends WAY too many of these.. */
4529 if (!NILP (window->horizontal_scroll_bar))
4531 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4532 if ([bar checkSamePosition: position portion: portion whole: whole])
4534 if (view->scrollbarsNeedingUpdate == 0)
4536 if (!windows_or_buffers_changed)
4540 view->scrollbarsNeedingUpdate--;
4545 NSTRACE ("ns_set_horizontal_scroll_bar");
4547 /* Get dimensions. */
4548 window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4550 width = window_width;
4551 height = NS_SCROLL_BAR_HEIGHT (f);
4552 top = WINDOW_SCROLL_BAR_AREA_Y (window);
4554 r = NSMakeRect (left, top, width, height);
4555 /* the parent view is flipped, so we need to flip y value */
4557 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4559 XSETWINDOW (win, window);
4562 if (NILP (window->horizontal_scroll_bar))
4564 if (width > 0 && height > 0)
4565 ns_clear_frame_area (f, left, top, width, height);
4567 bar = [[EmacsScroller alloc] initFrame: r window: win];
4568 wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4574 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4575 oldRect = [bar frame];
4576 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4578 if (oldRect.origin.y != r.origin.y)
4579 ns_clear_frame_area (f, left, top, width, height);
4585 /* If there are both horizontal and vertical scroll-bars they leave
4586 a square that belongs to neither. We need to clear it otherwise
4587 it fills with junk. */
4588 if (!NILP (window->vertical_scroll_bar))
4589 ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4590 NS_SCROLL_BAR_HEIGHT (f), height);
4593 [bar setPosition: position portion: portion whole: whole];
4599 ns_condemn_scroll_bars (struct frame *f)
4600 /* --------------------------------------------------------------------------
4601 External (hook): arrange for all frame's scrollbars to be removed
4602 at next call to judge_scroll_bars, except for those redeemed.
4603 -------------------------------------------------------------------------- */
4607 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4609 NSTRACE ("ns_condemn_scroll_bars");
4611 for (i =[subviews count]-1; i >= 0; i--)
4613 view = [subviews objectAtIndex: i];
4614 if ([view isKindOfClass: [EmacsScroller class]])
4621 ns_redeem_scroll_bar (struct window *window)
4622 /* --------------------------------------------------------------------------
4623 External (hook): arrange to spare this window's scrollbar
4624 at next call to judge_scroll_bars.
4625 -------------------------------------------------------------------------- */
4628 NSTRACE ("ns_redeem_scroll_bar");
4629 if (!NILP (window->vertical_scroll_bar)
4630 && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4632 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4636 if (!NILP (window->horizontal_scroll_bar)
4637 && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4639 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4646 ns_judge_scroll_bars (struct frame *f)
4647 /* --------------------------------------------------------------------------
4648 External (hook): destroy all scrollbars on frame that weren't
4649 redeemed after call to condemn_scroll_bars.
4650 -------------------------------------------------------------------------- */
4654 EmacsView *eview = FRAME_NS_VIEW (f);
4655 NSArray *subviews = [[eview superview] subviews];
4658 NSTRACE ("ns_judge_scroll_bars");
4659 for (i = [subviews count]-1; i >= 0; --i)
4661 view = [subviews objectAtIndex: i];
4662 if (![view isKindOfClass: [EmacsScroller class]]) continue;
4668 [eview updateFrameSize: NO];
4671 /* ==========================================================================
4675 ========================================================================== */
4678 x_display_pixel_height (struct ns_display_info *dpyinfo)
4680 NSArray *screens = [NSScreen screens];
4681 NSEnumerator *enumerator = [screens objectEnumerator];
4686 while ((screen = [enumerator nextObject]) != nil)
4687 frame = NSUnionRect (frame, [screen frame]);
4689 return NSHeight (frame);
4693 x_display_pixel_width (struct ns_display_info *dpyinfo)
4695 NSArray *screens = [NSScreen screens];
4696 NSEnumerator *enumerator = [screens objectEnumerator];
4701 while ((screen = [enumerator nextObject]) != nil)
4702 frame = NSUnionRect (frame, [screen frame]);
4704 return NSWidth (frame);
4708 static Lisp_Object ns_string_to_lispmod (const char *s)
4709 /* --------------------------------------------------------------------------
4710 Convert modifier name to lisp symbol
4711 -------------------------------------------------------------------------- */
4713 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4715 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4717 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4719 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4721 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4723 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4731 ns_default (const char *parameter, Lisp_Object *result,
4732 Lisp_Object yesval, Lisp_Object noval,
4733 BOOL is_float, BOOL is_modstring)
4734 /* --------------------------------------------------------------------------
4735 Check a parameter value in user's preferences
4736 -------------------------------------------------------------------------- */
4738 const char *value = ns_get_defaults_value (parameter);
4744 if (c_strcasecmp (value, "YES") == 0)
4746 else if (c_strcasecmp (value, "NO") == 0)
4748 else if (is_float && (f = strtod (value, &pos), pos != value))
4749 *result = make_float (f);
4750 else if (is_modstring && value)
4751 *result = ns_string_to_lispmod (value);
4752 else fprintf (stderr,
4753 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4759 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4760 /* --------------------------------------------------------------------------
4761 Initialize global info and storage for display.
4762 -------------------------------------------------------------------------- */
4764 NSScreen *screen = [NSScreen mainScreen];
4765 NSWindowDepth depth = [screen depth];
4767 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4768 dpyinfo->resy = 72.27;
4769 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4770 NSColorSpaceFromDepth (depth)]
4771 && ![NSCalibratedWhiteColorSpace isEqualToString:
4772 NSColorSpaceFromDepth (depth)];
4773 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4774 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4775 dpyinfo->color_table->colors = NULL;
4776 dpyinfo->root_window = 42; /* a placeholder.. */
4777 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4778 dpyinfo->n_fonts = 0;
4779 dpyinfo->smallest_font_height = 1;
4780 dpyinfo->smallest_char_width = 1;
4782 reset_mouse_highlight (&dpyinfo->mouse_highlight);
4786 /* This and next define (many of the) public functions in this file. */
4787 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4788 with using despite presence in the "system dependent" redisplay
4789 interface. In addition, many of the ns_ methods have code that is
4790 shared with all terms, indicating need for further refactoring. */
4791 extern frame_parm_handler ns_frame_parm_handlers[];
4792 static struct redisplay_interface ns_redisplay_interface =
4794 ns_frame_parm_handlers,
4798 x_clear_end_of_line,
4800 ns_after_update_window_line,
4801 ns_update_window_begin,
4802 ns_update_window_end,
4803 0, /* flush_display */
4804 x_clear_window_mouse_face,
4805 x_get_glyph_overhangs,
4806 x_fix_overlapping_area,
4807 ns_draw_fringe_bitmap,
4808 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4809 0, /* destroy_fringe_bitmap */
4810 ns_compute_glyph_string_overhangs,
4811 ns_draw_glyph_string,
4812 ns_define_frame_cursor,
4813 ns_clear_frame_area,
4814 ns_draw_window_cursor,
4815 ns_draw_vertical_window_border,
4816 ns_draw_window_divider,
4817 ns_shift_glyphs_for_insert,
4824 ns_delete_display (struct ns_display_info *dpyinfo)
4830 /* This function is called when the last frame on a display is deleted. */
4832 ns_delete_terminal (struct terminal *terminal)
4834 struct ns_display_info *dpyinfo = terminal->display_info.ns;
4836 NSTRACE ("ns_delete_terminal");
4838 /* Protect against recursive calls. delete_frame in
4839 delete_terminal calls us back when it deletes our last frame. */
4840 if (!terminal->name)
4845 x_destroy_all_bitmaps (dpyinfo);
4846 ns_delete_display (dpyinfo);
4851 static struct terminal *
4852 ns_create_terminal (struct ns_display_info *dpyinfo)
4853 /* --------------------------------------------------------------------------
4854 Set up use of NS before we make the first connection.
4855 -------------------------------------------------------------------------- */
4857 struct terminal *terminal;
4859 NSTRACE ("ns_create_terminal");
4861 terminal = create_terminal (output_ns, &ns_redisplay_interface);
4863 terminal->display_info.ns = dpyinfo;
4864 dpyinfo->terminal = terminal;
4866 terminal->clear_frame_hook = ns_clear_frame;
4867 terminal->ring_bell_hook = ns_ring_bell;
4868 terminal->update_begin_hook = ns_update_begin;
4869 terminal->update_end_hook = ns_update_end;
4870 terminal->read_socket_hook = ns_read_socket;
4871 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4872 terminal->mouse_position_hook = ns_mouse_position;
4873 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4874 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4875 terminal->fullscreen_hook = ns_fullscreen_hook;
4876 terminal->menu_show_hook = ns_menu_show;
4877 terminal->popup_dialog_hook = ns_popup_dialog;
4878 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4879 terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4880 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4881 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4882 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4883 terminal->delete_frame_hook = x_destroy_window;
4884 terminal->delete_terminal_hook = ns_delete_terminal;
4885 /* Other hooks are NULL by default. */
4891 struct ns_display_info *
4892 ns_term_init (Lisp_Object display_name)
4893 /* --------------------------------------------------------------------------
4894 Start the Application and get things rolling.
4895 -------------------------------------------------------------------------- */
4897 struct terminal *terminal;
4898 struct ns_display_info *dpyinfo;
4899 static int ns_initialized = 0;
4902 if (ns_initialized) return x_display_list;
4907 NSTRACE ("ns_term_init");
4909 [outerpool release];
4910 outerpool = [[NSAutoreleasePool alloc] init];
4912 /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */
4913 /*GSDebugAllocationActive (YES); */
4917 Fset_input_interrupt_mode (Qnil);
4919 if (selfds[0] == -1)
4921 if (emacs_pipe (selfds) != 0)
4923 fprintf (stderr, "Failed to create pipe: %s\n",
4924 emacs_strerror (errno));
4928 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4929 FD_ZERO (&select_readfds);
4930 FD_ZERO (&select_writefds);
4931 pthread_mutex_init (&select_mutex, NULL);
4934 ns_pending_files = [[NSMutableArray alloc] init];
4935 ns_pending_service_names = [[NSMutableArray alloc] init];
4936 ns_pending_service_args = [[NSMutableArray alloc] init];
4938 /* Start app and create the main menu, window, view.
4939 Needs to be here because ns_initialize_display_info () uses AppKit classes.
4940 The view will then ask the NSApp to stop and return to Emacs. */
4941 [EmacsApp sharedApplication];
4944 [NSApp setDelegate: NSApp];
4946 /* Start the select thread. */
4947 [NSThread detachNewThreadSelector:@selector (fd_handler:)
4951 /* debugging: log all notifications */
4952 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
4953 selector: @selector (logNotification:)
4954 name: nil object: nil]; */
4956 dpyinfo = xzalloc (sizeof *dpyinfo);
4958 ns_initialize_display_info (dpyinfo);
4959 terminal = ns_create_terminal (dpyinfo);
4961 terminal->kboard = allocate_kboard (Qns);
4962 /* Don't let the initial kboard remain current longer than necessary.
4963 That would cause problems if a file loaded on startup tries to
4964 prompt in the mini-buffer. */
4965 if (current_kboard == initial_kboard)
4966 current_kboard = terminal->kboard;
4967 terminal->kboard->reference_count++;
4969 dpyinfo->next = x_display_list;
4970 x_display_list = dpyinfo;
4972 dpyinfo->name_list_element = Fcons (display_name, Qnil);
4974 terminal->name = xlispstrdup (display_name);
4978 if (!inhibit_x_resources)
4980 ns_default ("GSFontAntiAlias", &ns_antialias_text,
4983 /* this is a standard variable */
4984 ns_default ("AppleAntiAliasingThreshold", &tmp,
4985 make_float (10.0), make_float (6.0), YES, NO);
4986 ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp);
4989 NSTRACE_MSG ("Colors");
4992 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4996 Lisp_Object color_file, color_map, color;
5000 color_file = Fexpand_file_name (build_string ("rgb.txt"),
5001 Fsymbol_value (intern ("data-directory")));
5003 color_map = Fx_load_color_file (color_file);
5004 if (NILP (color_map))
5005 fatal ("Could not read %s.\n", SDATA (color_file));
5007 cl = [[NSColorList alloc] initWithName: @"Emacs"];
5008 for ( ; CONSP (color_map); color_map = XCDR (color_map))
5010 color = XCAR (color_map);
5011 name = SSDATA (XCAR (color));
5012 c = XINT (XCDR (color));
5014 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
5015 green: GREEN_FROM_ULONG (c) / 255.0
5016 blue: BLUE_FROM_ULONG (c) / 255.0
5018 forKey: [NSString stringWithUTF8String: name]];
5020 [cl writeToFile: nil];
5024 NSTRACE_MSG ("Versions");
5027 #ifdef NS_IMPL_GNUSTEP
5028 Vwindow_system_version = build_string (gnustep_base_version);
5030 /*PSnextrelease (128, c); */
5031 char c[DBL_BUFSIZE_BOUND];
5032 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
5033 Vwindow_system_version = make_unibyte_string (c, len);
5037 delete_keyboard_wait_descriptor (0);
5039 ns_app_name = [[NSProcessInfo processInfo] processName];
5041 /* Set up macOS app menu */
5043 NSTRACE_MSG ("Menu init");
5045 #ifdef NS_IMPL_COCOA
5049 /* set up the application menu */
5050 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
5051 [svcsMenu setAutoenablesItems: NO];
5052 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
5053 [appMenu setAutoenablesItems: NO];
5054 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
5055 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
5057 [appMenu insertItemWithTitle: @"About Emacs"
5058 action: @selector (orderFrontStandardAboutPanel:)
5061 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
5062 [appMenu insertItemWithTitle: @"Preferences..."
5063 action: @selector (showPreferencesWindow:)
5066 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
5067 item = [appMenu insertItemWithTitle: @"Services"
5068 action: @selector (menuDown:)
5071 [appMenu setSubmenu: svcsMenu forItem: item];
5072 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
5073 [appMenu insertItemWithTitle: @"Hide Emacs"
5074 action: @selector (hide:)
5077 item = [appMenu insertItemWithTitle: @"Hide Others"
5078 action: @selector (hideOtherApplications:)
5081 [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption];
5082 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
5083 [appMenu insertItemWithTitle: @"Quit Emacs"
5084 action: @selector (terminate:)
5088 item = [mainMenu insertItemWithTitle: ns_app_name
5089 action: @selector (menuDown:)
5092 [mainMenu setSubmenu: appMenu forItem: item];
5093 [dockMenu insertItemWithTitle: @"New Frame"
5094 action: @selector (newFrame:)
5098 [NSApp setMainMenu: mainMenu];
5099 [NSApp setAppleMenu: appMenu];
5100 [NSApp setServicesMenu: svcsMenu];
5101 /* Needed at least on Cocoa, to get dock menu to show windows */
5102 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5104 [[NSNotificationCenter defaultCenter]
5105 addObserver: mainMenu
5106 selector: @selector (trackingNotification:)
5107 name: NSMenuDidBeginTrackingNotification object: mainMenu];
5108 [[NSNotificationCenter defaultCenter]
5109 addObserver: mainMenu
5110 selector: @selector (trackingNotification:)
5111 name: NSMenuDidEndTrackingNotification object: mainMenu];
5113 #endif /* macOS menu setup */
5115 /* Register our external input/output types, used for determining
5116 applicable services and also drag/drop eligibility. */
5118 NSTRACE_MSG ("Input/output types");
5120 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5121 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5123 ns_drag_types = [[NSArray arrayWithObjects:
5125 NSTabularTextPboardType,
5126 NSFilenamesPboardType,
5127 NSURLPboardType, nil] retain];
5129 /* If fullscreen is in init/default-frame-alist, focus isn't set
5130 right for fullscreen windows, so set this. */
5131 [NSApp activateIgnoringOtherApps:YES];
5133 NSTRACE_MSG ("Call NSApp run");
5136 ns_do_open_file = YES;
5138 #ifdef NS_IMPL_GNUSTEP
5139 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5140 We must re-catch it so subprocess works. */
5141 catch_child_signal ();
5144 NSTRACE_MSG ("ns_term_init done");
5153 ns_term_shutdown (int sig)
5155 [[NSUserDefaults standardUserDefaults] synchronize];
5157 /* code not reached in emacs.c after this is called by shut_down_emacs: */
5158 if (STRINGP (Vauto_save_list_file_name))
5159 unlink (SSDATA (Vauto_save_list_file_name));
5161 if (sig == 0 || sig == SIGTERM)
5163 [NSApp terminate: NSApp];
5165 else // force a stack trace to happen
5172 /* ==========================================================================
5174 EmacsApp implementation
5176 ========================================================================== */
5179 @implementation EmacsApp
5183 NSTRACE ("[EmacsApp init]");
5185 if ((self = [super init]))
5187 #ifdef NS_IMPL_COCOA
5188 self->isFirst = YES;
5190 #ifdef NS_IMPL_GNUSTEP
5191 self->applicationDidFinishLaunchingCalled = NO;
5198 #ifdef NS_IMPL_COCOA
5201 NSTRACE ("[EmacsApp run]");
5203 #ifndef NSAppKitVersionNumber10_9
5204 #define NSAppKitVersionNumber10_9 1265
5207 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5213 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5215 if (isFirst) [self finishLaunching];
5218 shouldKeepRunning = YES;
5222 pool = [[NSAutoreleasePool alloc] init];
5225 [self nextEventMatchingMask:NSEventMaskAny
5226 untilDate:[NSDate distantFuture]
5227 inMode:NSDefaultRunLoopMode
5230 [self sendEvent:event];
5231 [self updateWindows];
5232 } while (shouldKeepRunning);
5237 - (void)stop: (id)sender
5239 NSTRACE ("[EmacsApp stop:]");
5241 shouldKeepRunning = NO;
5242 // Stop possible dialog also. Noop if no dialog present.
5243 // The file dialog still leaks 7k - 10k on 10.9 though.
5244 [super stop:sender];
5246 #endif /* NS_IMPL_COCOA */
5248 - (void)logNotification: (NSNotification *)notification
5250 NSTRACE ("[EmacsApp logNotification:]");
5252 const char *name = [[notification name] UTF8String];
5253 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5254 && !strstr (name, "WindowNumber"))
5255 NSLog (@"notification: '%@'", [notification name]);
5259 - (void)sendEvent: (NSEvent *)theEvent
5260 /* --------------------------------------------------------------------------
5261 Called when NSApp is running for each event received. Used to stop
5262 the loop when we choose, since there's no way to just run one iteration.
5263 -------------------------------------------------------------------------- */
5265 int type = [theEvent type];
5266 NSWindow *window = [theEvent window];
5268 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5269 NSTRACE_MSG ("Type: %d", type);
5271 #ifdef NS_IMPL_GNUSTEP
5272 // Keyboard events aren't propagated to file dialogs for some reason.
5273 if ([NSApp modalWindow] != nil &&
5274 (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged))
5276 [[NSApp modalWindow] sendEvent: theEvent];
5281 if (represented_filename != nil && represented_frame)
5283 NSString *fstr = represented_filename;
5284 NSView *view = FRAME_NS_VIEW (represented_frame);
5285 #ifdef NS_IMPL_COCOA
5286 /* work around a bug observed on 10.3 and later where
5287 setTitleWithRepresentedFilename does not clear out previous state
5288 if given filename does not exist */
5289 if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5290 [[view window] setRepresentedFilename: @""];
5292 [[view window] setRepresentedFilename: fstr];
5293 [represented_filename release];
5294 represented_filename = nil;
5295 represented_frame = NULL;
5298 if (type == NSEventTypeApplicationDefined)
5300 switch ([theEvent data2])
5302 #ifdef NS_IMPL_COCOA
5303 case NSAPP_DATA2_RUNASSCRIPT:
5308 case NSAPP_DATA2_RUNFILEDIALOG:
5309 ns_run_file_dialog ();
5315 if (type == NSEventTypeCursorUpdate && window == nil)
5317 fprintf (stderr, "Dropping external cursor update event.\n");
5321 if (type == NSEventTypeApplicationDefined)
5323 /* Events posted by ns_send_appdefined interrupt the run loop here.
5324 But, if a modal window is up, an appdefined can still come through,
5325 (e.g., from a makeKeyWindow event) but stopping self also stops the
5326 modal loop. Just defer it until later. */
5327 if ([NSApp modalWindow] == nil)
5329 last_appdefined_event_data = [theEvent data1];
5334 send_appdefined = YES;
5339 #ifdef NS_IMPL_COCOA
5340 /* If no dialog and none of our frames have focus and it is a move, skip it.
5341 It is a mouse move in an auxiliary menu, i.e. on the top right on macOS,
5342 such as Wifi, sound, date or similar.
5343 This prevents "spooky" highlighting in the frame under the menu. */
5344 if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil)
5346 struct ns_display_info *di;
5347 BOOL has_focus = NO;
5348 for (di = x_display_list; ! has_focus && di; di = di->next)
5349 has_focus = di->x_focus_frame != 0;
5355 NSTRACE_UNSILENCE();
5357 [super sendEvent: theEvent];
5361 - (void)showPreferencesWindow: (id)sender
5363 struct frame *emacsframe = SELECTED_FRAME ();
5364 NSEvent *theEvent = [NSApp currentEvent];
5368 emacs_event->kind = NS_NONKEY_EVENT;
5369 emacs_event->code = KEY_NS_SHOW_PREFS;
5370 emacs_event->modifiers = 0;
5371 EV_TRAILER (theEvent);
5375 - (void)newFrame: (id)sender
5377 NSTRACE ("[EmacsApp newFrame:]");
5379 struct frame *emacsframe = SELECTED_FRAME ();
5380 NSEvent *theEvent = [NSApp currentEvent];
5384 emacs_event->kind = NS_NONKEY_EVENT;
5385 emacs_event->code = KEY_NS_NEW_FRAME;
5386 emacs_event->modifiers = 0;
5387 EV_TRAILER (theEvent);
5391 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5392 - (BOOL) openFile: (NSString *)fileName
5394 NSTRACE ("[EmacsApp openFile:]");
5396 struct frame *emacsframe = SELECTED_FRAME ();
5397 NSEvent *theEvent = [NSApp currentEvent];
5402 emacs_event->kind = NS_NONKEY_EVENT;
5403 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5404 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5405 ns_input_line = Qnil; /* can be start or cons start,end */
5406 emacs_event->modifiers =0;
5407 EV_TRAILER (theEvent);
5413 /* **************************************************************************
5415 EmacsApp delegate implementation
5417 ************************************************************************** */
5419 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5420 /* --------------------------------------------------------------------------
5421 When application is loaded, terminate event loop in ns_term_init
5422 -------------------------------------------------------------------------- */
5424 NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5426 #ifdef NS_IMPL_GNUSTEP
5427 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5429 [NSApp setServicesProvider: NSApp];
5431 [self antialiasThresholdDidChange:nil];
5432 #ifdef NS_IMPL_COCOA
5433 [[NSNotificationCenter defaultCenter]
5435 selector:@selector(antialiasThresholdDidChange:)
5436 name:NSAntialiasThresholdChangedNotification
5440 ns_send_appdefined (-2);
5443 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5445 #ifdef NS_IMPL_COCOA
5446 macfont_update_antialias_threshold ();
5451 /* Termination sequences:
5454 MenuBar | File | Exit:
5455 Select Quit from App menubar:
5457 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5460 Select Quit from Dock menu:
5463 Cancel -> Nothing else
5467 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5472 - (void) terminate: (id)sender
5474 NSTRACE ("[EmacsApp terminate:]");
5476 struct frame *emacsframe = SELECTED_FRAME ();
5481 emacs_event->kind = NS_NONKEY_EVENT;
5482 emacs_event->code = KEY_NS_POWER_OFF;
5483 emacs_event->arg = Qt; /* mark as non-key event */
5484 EV_TRAILER ((id)nil);
5488 runAlertPanel(NSString *title,
5489 NSString *msgFormat,
5490 NSString *defaultButton,
5491 NSString *alternateButton)
5493 #if !defined (NS_IMPL_COCOA) || \
5494 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
5495 return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5496 == NSAlertDefaultReturn;
5498 NSAlert *alert = [[NSAlert alloc] init];
5499 [alert setAlertStyle: NSAlertStyleCritical];
5500 [alert setMessageText: msgFormat];
5501 [alert addButtonWithTitle: defaultButton];
5502 [alert addButtonWithTitle: alternateButton];
5503 NSInteger ret = [alert runModal];
5505 return ret == NSAlertFirstButtonReturn;
5510 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5512 NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5516 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
5517 return NSTerminateNow;
5519 ret = runAlertPanel(ns_app_name,
5520 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
5521 @"Save Buffers and Exit", @"Cancel");
5523 return ret ? NSTerminateNow : NSTerminateCancel;
5527 not_in_argv (NSString *arg)
5530 const char *a = [arg UTF8String];
5531 for (k = 1; k < initial_argc; ++k)
5532 if (strcmp (a, initial_argv[k]) == 0) return 0;
5536 /* Notification from the Workspace to open a file */
5537 - (BOOL)application: sender openFile: (NSString *)file
5539 if (ns_do_open_file || not_in_argv (file))
5540 [ns_pending_files addObject: file];
5545 /* Open a file as a temporary file */
5546 - (BOOL)application: sender openTempFile: (NSString *)file
5548 if (ns_do_open_file || not_in_argv (file))
5549 [ns_pending_files addObject: file];
5554 /* Notification from the Workspace to open a file noninteractively (?) */
5555 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5557 if (ns_do_open_file || not_in_argv (file))
5558 [ns_pending_files addObject: file];
5562 /* Notification from the Workspace to open multiple files */
5563 - (void)application: sender openFiles: (NSArray *)fileList
5565 NSEnumerator *files = [fileList objectEnumerator];
5567 /* Don't open files from the command line unconditionally,
5568 Cocoa parses the command line wrong, --option value tries to open value
5569 if --option is the last option. */
5570 while ((file = [files nextObject]) != nil)
5571 if (ns_do_open_file || not_in_argv (file))
5572 [ns_pending_files addObject: file];
5574 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5579 /* Handle dock menu requests. */
5580 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5586 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5587 - (void)applicationWillBecomeActive: (NSNotification *)notification
5589 NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5590 //ns_app_active=YES;
5593 - (void)applicationDidBecomeActive: (NSNotification *)notification
5595 NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5597 #ifdef NS_IMPL_GNUSTEP
5598 if (! applicationDidFinishLaunchingCalled)
5599 [self applicationDidFinishLaunching:notification];
5601 //ns_app_active=YES;
5603 ns_update_auto_hide_menu_bar ();
5604 // No constraining takes place when the application is not active.
5605 ns_constrain_all_frames ();
5607 - (void)applicationDidResignActive: (NSNotification *)notification
5609 NSTRACE ("[EmacsApp applicationDidResignActive:]");
5612 ns_send_appdefined (-1);
5617 /* ==========================================================================
5619 EmacsApp aux handlers for managing event loop
5621 ========================================================================== */
5624 - (void)timeout_handler: (NSTimer *)timedEntry
5625 /* --------------------------------------------------------------------------
5626 The timeout specified to ns_select has passed.
5627 -------------------------------------------------------------------------- */
5629 /*NSTRACE ("timeout_handler"); */
5630 ns_send_appdefined (-2);
5633 - (void)sendFromMainThread:(id)unused
5635 ns_send_appdefined (nextappdefined);
5638 - (void)fd_handler:(id)unused
5639 /* --------------------------------------------------------------------------
5640 Check data waiting on file descriptors and terminate if so
5641 -------------------------------------------------------------------------- */
5644 int waiting = 1, nfds;
5647 fd_set readfds, writefds, *wfds;
5648 struct timespec timeout, *tmo;
5649 NSAutoreleasePool *pool = nil;
5651 /* NSTRACE ("fd_handler"); */
5656 pool = [[NSAutoreleasePool alloc] init];
5662 FD_SET (selfds[0], &fds);
5663 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5664 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5669 pthread_mutex_lock (&select_mutex);
5672 if (select_valid & SELECT_HAVE_READ)
5673 readfds = select_readfds;
5677 if (select_valid & SELECT_HAVE_WRITE)
5679 writefds = select_writefds;
5684 if (select_valid & SELECT_HAVE_TMO)
5686 timeout = select_timeout;
5692 pthread_mutex_unlock (&select_mutex);
5694 FD_SET (selfds[0], &readfds);
5695 if (selfds[0] >= nfds) nfds = selfds[0]+1;
5697 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5700 ns_send_appdefined (-2);
5701 else if (result > 0)
5703 if (FD_ISSET (selfds[0], &readfds))
5705 if (read (selfds[0], &c, 1) == 1 && c == 's')
5710 pthread_mutex_lock (&select_mutex);
5711 if (select_valid & SELECT_HAVE_READ)
5712 select_readfds = readfds;
5713 if (select_valid & SELECT_HAVE_WRITE)
5714 select_writefds = writefds;
5715 if (select_valid & SELECT_HAVE_TMO)
5716 select_timeout = timeout;
5717 pthread_mutex_unlock (&select_mutex);
5719 ns_send_appdefined (result);
5729 /* ==========================================================================
5733 ========================================================================== */
5735 /* called from system: queue for next pass through event loop */
5736 - (void)requestService: (NSPasteboard *)pboard
5737 userData: (NSString *)userData
5738 error: (NSString **)error
5740 [ns_pending_service_names addObject: userData];
5741 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5742 SSDATA (ns_string_from_pasteboard (pboard))]];
5746 /* called from ns_read_socket to clear queue */
5747 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5749 struct frame *emacsframe = SELECTED_FRAME ();
5750 NSEvent *theEvent = [NSApp currentEvent];
5752 NSTRACE ("[EmacsApp fulfillService:withArg:]");
5757 emacs_event->kind = NS_NONKEY_EVENT;
5758 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5759 ns_input_spi_name = build_string ([name UTF8String]);
5760 ns_input_spi_arg = build_string ([arg UTF8String]);
5761 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5762 EV_TRAILER (theEvent);
5772 /* ==========================================================================
5774 EmacsView implementation
5776 ========================================================================== */
5779 @implementation EmacsView
5781 /* needed to inform when window closed from LISP */
5782 - (void) setWindowClosing: (BOOL)closing
5784 NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5786 windowClosing = closing;
5792 NSTRACE ("[EmacsView dealloc]");
5794 if (fs_state == FULLSCREEN_BOTH)
5795 [nonfs_window release];
5800 /* called on font panel selection */
5801 - (void)changeFont: (id)sender
5803 NSEvent *e = [[self window] currentEvent];
5804 struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID);
5805 struct font *font = face->font;
5810 NSTRACE ("[EmacsView changeFont:]");
5815 #ifdef NS_IMPL_GNUSTEP
5816 nsfont = ((struct nsfont_info *)font)->nsfont;
5818 #ifdef NS_IMPL_COCOA
5819 nsfont = (NSFont *) macfont_get_nsctfont (font);
5822 if ((newFont = [sender convertFont: nsfont]))
5824 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5826 emacs_event->kind = NS_NONKEY_EVENT;
5827 emacs_event->modifiers = 0;
5828 emacs_event->code = KEY_NS_CHANGE_FONT;
5830 size = [newFont pointSize];
5831 ns_input_fontsize = make_number (lrint (size));
5832 ns_input_font = build_string ([[newFont familyName] UTF8String]);
5838 - (BOOL)acceptsFirstResponder
5840 NSTRACE ("[EmacsView acceptsFirstResponder]");
5845 - (void)resetCursorRects
5847 NSRect visible = [self visibleRect];
5848 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5849 NSTRACE ("[EmacsView resetCursorRects]");
5851 if (currentCursor == nil)
5852 currentCursor = [NSCursor arrowCursor];
5854 if (!NSIsEmptyRect (visible))
5855 [self addCursorRect: visible cursor: currentCursor];
5856 [currentCursor setOnMouseEntered: YES];
5861 /*****************************************************************************/
5862 /* Keyboard handling. */
5865 - (void)keyDown: (NSEvent *)theEvent
5867 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5869 unsigned fnKeysym = 0;
5870 static NSMutableArray *nsEvArray;
5872 unsigned int flags = [theEvent modifierFlags];
5874 NSTRACE ("[EmacsView keyDown:]");
5876 /* Rhapsody and macOS give up and down events for the arrow keys */
5877 if (ns_fake_keydown == YES)
5878 ns_fake_keydown = NO;
5879 else if ([theEvent type] != NSEventTypeKeyDown)
5885 if (![[self window] isKeyWindow]
5886 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5887 /* we must avoid an infinite loop here. */
5888 && (EmacsView *)[[theEvent window] delegate] != self)
5890 /* XXX: There is an occasional condition in which, when Emacs display
5891 updates a different frame from the current one, and temporarily
5892 selects it, then processes some interrupt-driven input
5893 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5894 for some reason that window has its first responder set to the NSView
5895 most recently updated (I guess), which is not the correct one. */
5896 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5900 if (nsEvArray == nil)
5901 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5903 [NSCursor setHiddenUntilMouseMoves: YES];
5905 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5907 clear_mouse_face (hlinfo);
5908 hlinfo->mouse_face_hidden = 1;
5911 if (!processingCompose)
5913 /* When using screen sharing, no left or right information is sent,
5914 so use Left key in those cases. */
5915 int is_left_key, is_right_key;
5917 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5918 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5920 /* (Carbon way: [theEvent keyCode]) */
5922 /* is it a "function key"? */
5923 /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad
5924 flag set (this is probably a bug in the OS).
5926 if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad))
5928 fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad);
5932 fnKeysym = ns_convert_key (code);
5937 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5938 because Emacs treats Delete and KP-Delete same (in simple.el). */
5939 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5940 #ifdef NS_IMPL_GNUSTEP
5941 /* GNUstep uses incompatible keycodes, even for those that are
5942 supposed to be hardware independent. Just check for delete.
5943 Keypad delete does not have keysym 0xFFFF.
5944 See http://savannah.gnu.org/bugs/?25395
5946 || (fnKeysym == 0xFFFF && code == 127)
5949 code = 0xFF08; /* backspace */
5954 /* are there modifiers? */
5955 emacs_event->modifiers = 0;
5957 if (flags & NSEventModifierFlagHelp)
5958 emacs_event->modifiers |= hyper_modifier;
5960 if (flags & NSEventModifierFlagShift)
5961 emacs_event->modifiers |= shift_modifier;
5963 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5964 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5965 || (! is_right_key && (flags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand);
5968 emacs_event->modifiers |= parse_solitary_modifier
5969 (EQ (ns_right_command_modifier, Qleft)
5970 ? ns_command_modifier
5971 : ns_right_command_modifier);
5975 emacs_event->modifiers |= parse_solitary_modifier
5976 (ns_command_modifier);
5978 /* if super (default), take input manager's word so things like
5979 dvorak / qwerty layout work */
5980 if (EQ (ns_command_modifier, Qsuper)
5982 && [[theEvent characters] length] != 0)
5984 /* XXX: the code we get will be unshifted, so if we have
5985 a shift modifier, must convert ourselves */
5986 if (!(flags & NSEventModifierFlagShift))
5987 code = [[theEvent characters] characterAtIndex: 0];
5989 /* this is ugly and also requires linking w/Carbon framework
5990 (for LMGetKbdType) so for now leave this rare (?) case
5991 undealt with.. in future look into CGEvent methods */
5994 long smv = GetScriptManagerVariable (smKeyScript);
5995 Handle uchrHandle = GetResource
5996 ('uchr', GetScriptVariable (smv, smScriptKeys));
5998 UCKeyTranslate ((UCKeyboardLayout *) *uchrHandle,
5999 [[theEvent characters] characterAtIndex: 0],
6000 kUCKeyActionDisplay,
6001 (flags & ~NSEventModifierFlagCommand) >> 8,
6002 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
6003 &dummy, 1, &dummy, &code);
6010 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
6011 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
6012 || (! is_right_key && (flags & NSEventModifierFlagControl) == NSEventModifierFlagControl);
6015 emacs_event->modifiers |= parse_solitary_modifier
6016 (EQ (ns_right_control_modifier, Qleft)
6017 ? ns_control_modifier
6018 : ns_right_control_modifier);
6021 emacs_event->modifiers |= parse_solitary_modifier
6022 (ns_control_modifier);
6024 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
6025 emacs_event->modifiers |=
6026 parse_solitary_modifier (ns_function_modifier);
6028 left_is_none = NILP (ns_alternate_modifier)
6029 || EQ (ns_alternate_modifier, Qnone);
6031 is_right_key = (flags & NSRightAlternateKeyMask)
6032 == NSRightAlternateKeyMask;
6033 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
6035 && (flags & NSEventModifierFlagOption) == NSEventModifierFlagOption);
6039 if ((NILP (ns_right_alternate_modifier)
6040 || EQ (ns_right_alternate_modifier, Qnone)
6041 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
6043 { /* accept pre-interp alt comb */
6044 if ([[theEvent characters] length] > 0)
6045 code = [[theEvent characters] characterAtIndex: 0];
6046 /*HACK: clear lone shift modifier to stop next if from firing */
6047 if (emacs_event->modifiers == shift_modifier)
6048 emacs_event->modifiers = 0;
6051 emacs_event->modifiers |= parse_solitary_modifier
6052 (EQ (ns_right_alternate_modifier, Qleft)
6053 ? ns_alternate_modifier
6054 : ns_right_alternate_modifier);
6057 if (is_left_key) /* default = meta */
6059 if (left_is_none && !fnKeysym)
6060 { /* accept pre-interp alt comb */
6061 if ([[theEvent characters] length] > 0)
6062 code = [[theEvent characters] characterAtIndex: 0];
6063 /*HACK: clear lone shift modifier to stop next if from firing */
6064 if (emacs_event->modifiers == shift_modifier)
6065 emacs_event->modifiers = 0;
6068 emacs_event->modifiers |=
6069 parse_solitary_modifier (ns_alternate_modifier);
6073 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6074 (unsigned) code, fnKeysym, flags, emacs_event->modifiers);
6076 /* if it was a function key or had modifiers, pass it directly to emacs */
6077 if (fnKeysym || (emacs_event->modifiers
6078 && (emacs_event->modifiers != shift_modifier)
6079 && [[theEvent charactersIgnoringModifiers] length] > 0))
6080 /*[[theEvent characters] length] */
6082 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6084 code |= (1<<28)|(3<<16);
6085 else if (code == 0x7f)
6086 code |= (1<<28)|(3<<16);
6088 emacs_event->kind = code > 0xFF
6089 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6091 emacs_event->code = code;
6092 EV_TRAILER (theEvent);
6093 processingCompose = NO;
6099 if (NS_KEYLOG && !processingCompose)
6100 fprintf (stderr, "keyDown: Begin compose sequence.\n");
6102 processingCompose = YES;
6103 [nsEvArray addObject: theEvent];
6104 [self interpretKeyEvents: nsEvArray];
6105 [nsEvArray removeObject: theEvent];
6109 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6112 /* <NSTextInput>: called when done composing;
6113 NOTE: also called when we delete over working text, followed immed.
6114 by doCommandBySelector: deleteBackward: */
6115 - (void)insertText: (id)aString
6118 int len = [(NSString *)aString length];
6121 NSTRACE ("[EmacsView insertText:]");
6124 NSLog (@"insertText '%@'\tlen = %d", aString, len);
6125 processingCompose = NO;
6130 /* first, clear any working text */
6131 if (workingText != nil)
6132 [self deleteWorkingText];
6134 /* now insert the string as keystrokes */
6135 for (i =0; i<len; i++)
6137 code = [aString characterAtIndex: i];
6138 /* TODO: still need this? */
6140 code = '~'; /* 0x7E */
6141 if (code != 32) /* Space */
6142 emacs_event->modifiers = 0;
6144 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6145 emacs_event->code = code;
6146 EV_TRAILER ((id)nil);
6151 /* <NSTextInput>: inserts display of composing characters */
6152 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6154 NSString *str = [aString respondsToSelector: @selector (string)] ?
6155 [aString string] : aString;
6157 NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6160 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6161 str, (unsigned long)[str length],
6162 (unsigned long)selRange.length,
6163 (unsigned long)selRange.location);
6165 if (workingText != nil)
6166 [self deleteWorkingText];
6167 if ([str length] == 0)
6173 processingCompose = YES;
6174 workingText = [str copy];
6175 ns_working_text = build_string ([workingText UTF8String]);
6177 emacs_event->kind = NS_TEXT_EVENT;
6178 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6179 EV_TRAILER ((id)nil);
6183 /* delete display of composing characters [not in <NSTextInput>] */
6184 - (void)deleteWorkingText
6186 NSTRACE ("[EmacsView deleteWorkingText]");
6188 if (workingText == nil)
6191 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6192 [workingText release];
6194 processingCompose = NO;
6199 emacs_event->kind = NS_TEXT_EVENT;
6200 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6201 EV_TRAILER ((id)nil);
6205 - (BOOL)hasMarkedText
6207 NSTRACE ("[EmacsView hasMarkedText]");
6209 return workingText != nil;
6213 - (NSRange)markedRange
6215 NSTRACE ("[EmacsView markedRange]");
6217 NSRange rng = workingText != nil
6218 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6220 NSLog (@"markedRange request");
6227 NSTRACE ("[EmacsView unmarkText]");
6230 NSLog (@"unmark (accept) text");
6231 [self deleteWorkingText];
6232 processingCompose = NO;
6236 /* used to position char selection windows, etc. */
6237 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6241 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6243 NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6246 NSLog (@"firstRectForCharRange request");
6248 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6249 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6250 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6251 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6252 +FRAME_LINE_HEIGHT (emacsframe));
6254 pt = [self convertPoint: pt toView: nil];
6255 #if !defined (NS_IMPL_COCOA) || \
6256 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
6257 pt = [[self window] convertBaseToScreen: pt];
6261 rect = [[self window] convertRectToScreen: rect];
6267 - (NSInteger)conversationIdentifier
6269 return (NSInteger)self;
6273 - (void)doCommandBySelector: (SEL)aSelector
6275 NSTRACE ("[EmacsView doCommandBySelector:]");
6278 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6280 processingCompose = NO;
6281 if (aSelector == @selector (deleteBackward:))
6283 /* happens when user backspaces over an ongoing composition:
6284 throw a 'delete' into the event queue */
6287 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6288 emacs_event->code = 0xFF08;
6289 EV_TRAILER ((id)nil);
6293 - (NSArray *)validAttributesForMarkedText
6295 static NSArray *arr = nil;
6296 if (arr == nil) arr = [NSArray new];
6297 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6301 - (NSRange)selectedRange
6304 NSLog (@"selectedRange request");
6305 return NSMakeRange (NSNotFound, 0);
6308 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6309 GNUSTEP_GUI_MINOR_VERSION > 22
6310 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6312 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6316 NSLog (@"characterIndexForPoint request");
6320 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6322 static NSAttributedString *str = nil;
6323 if (str == nil) str = [NSAttributedString new];
6325 NSLog (@"attributedSubstringFromRange request");
6329 /* End <NSTextInput> impl. */
6330 /*****************************************************************************/
6333 /* This is what happens when the user presses a mouse button. */
6334 - (void)mouseDown: (NSEvent *)theEvent
6336 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6337 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6339 NSTRACE ("[EmacsView mouseDown:]");
6341 [self deleteWorkingText];
6346 dpyinfo->last_mouse_frame = emacsframe;
6347 /* appears to be needed to prevent spurious movement events generated on
6349 emacsframe->mouse_moved = 0;
6351 if ([theEvent type] == NSEventTypeScrollWheel)
6353 CGFloat delta = [theEvent deltaY];
6354 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6357 delta = [theEvent deltaX];
6360 NSTRACE_MSG ("deltaIsZero");
6363 emacs_event->kind = HORIZ_WHEEL_EVENT;
6366 emacs_event->kind = WHEEL_EVENT;
6368 emacs_event->code = 0;
6369 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6370 ((delta > 0) ? up_modifier : down_modifier);
6374 emacs_event->kind = MOUSE_CLICK_EVENT;
6375 emacs_event->code = EV_BUTTON (theEvent);
6376 emacs_event->modifiers = EV_MODIFIERS (theEvent)
6377 | EV_UDMODIFIERS (theEvent);
6379 XSETINT (emacs_event->x, lrint (p.x));
6380 XSETINT (emacs_event->y, lrint (p.y));
6381 EV_TRAILER (theEvent);
6385 - (void)rightMouseDown: (NSEvent *)theEvent
6387 NSTRACE ("[EmacsView rightMouseDown:]");
6388 [self mouseDown: theEvent];
6392 - (void)otherMouseDown: (NSEvent *)theEvent
6394 NSTRACE ("[EmacsView otherMouseDown:]");
6395 [self mouseDown: theEvent];
6399 - (void)mouseUp: (NSEvent *)theEvent
6401 NSTRACE ("[EmacsView mouseUp:]");
6402 [self mouseDown: theEvent];
6406 - (void)rightMouseUp: (NSEvent *)theEvent
6408 NSTRACE ("[EmacsView rightMouseUp:]");
6409 [self mouseDown: theEvent];
6413 - (void)otherMouseUp: (NSEvent *)theEvent
6415 NSTRACE ("[EmacsView otherMouseUp:]");
6416 [self mouseDown: theEvent];
6420 - (void) scrollWheel: (NSEvent *)theEvent
6422 NSTRACE ("[EmacsView scrollWheel:]");
6423 [self mouseDown: theEvent];
6427 /* Tell emacs the mouse has moved. */
6428 - (void)mouseMoved: (NSEvent *)e
6430 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6431 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6435 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6437 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6438 pt = [self convertPoint: [e locationInWindow] fromView: nil];
6439 dpyinfo->last_mouse_motion_x = pt.x;
6440 dpyinfo->last_mouse_motion_y = pt.y;
6442 /* update any mouse face */
6443 if (hlinfo->mouse_face_hidden)
6445 hlinfo->mouse_face_hidden = 0;
6446 clear_mouse_face (hlinfo);
6449 /* tooltip handling */
6450 previous_help_echo_string = help_echo_string;
6451 help_echo_string = Qnil;
6453 if (!NILP (Vmouse_autoselect_window))
6455 NSTRACE_MSG ("mouse_autoselect_window");
6456 static Lisp_Object last_mouse_window;
6458 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6460 if (WINDOWP (window)
6461 && !EQ (window, last_mouse_window)
6462 && !EQ (window, selected_window)
6463 && (!NILP (focus_follows_mouse)
6464 || (EQ (XWINDOW (window)->frame,
6465 XWINDOW (selected_window)->frame))))
6467 NSTRACE_MSG ("in_window");
6468 emacs_event->kind = SELECT_WINDOW_EVENT;
6469 emacs_event->frame_or_window = window;
6472 /* Remember the last window where we saw the mouse. */
6473 last_mouse_window = window;
6476 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6477 help_echo_string = previous_help_echo_string;
6479 XSETFRAME (frame, emacsframe);
6480 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6482 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6483 (note_mouse_highlight), which is called through the
6484 note_mouse_movement () call above */
6485 any_help_event_p = YES;
6486 gen_help_event (help_echo_string, frame, help_echo_window,
6487 help_echo_object, help_echo_pos);
6490 if (emacsframe->mouse_moved && send_appdefined)
6491 ns_send_appdefined (-1);
6495 - (void)mouseDragged: (NSEvent *)e
6497 NSTRACE ("[EmacsView mouseDragged:]");
6498 [self mouseMoved: e];
6502 - (void)rightMouseDragged: (NSEvent *)e
6504 NSTRACE ("[EmacsView rightMouseDragged:]");
6505 [self mouseMoved: e];
6509 - (void)otherMouseDragged: (NSEvent *)e
6511 NSTRACE ("[EmacsView otherMouseDragged:]");
6512 [self mouseMoved: e];
6516 - (BOOL)windowShouldClose: (id)sender
6518 NSEvent *e =[[self window] currentEvent];
6520 NSTRACE ("[EmacsView windowShouldClose:]");
6521 windowClosing = YES;
6524 emacs_event->kind = DELETE_WINDOW_EVENT;
6525 emacs_event->modifiers = 0;
6526 emacs_event->code = 0;
6528 /* Don't close this window, let this be done from lisp code. */
6532 - (void) updateFrameSize: (BOOL) delay;
6534 NSWindow *window = [self window];
6535 NSRect wr = [window frame];
6537 int oldc = cols, oldr = rows;
6538 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6539 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6542 NSTRACE ("[EmacsView updateFrameSize:]");
6543 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6544 NSTRACE_RECT ("Original frame", wr);
6545 NSTRACE_MSG ("Original columns: %d", cols);
6546 NSTRACE_MSG ("Original rows: %d", rows);
6548 if (! [self isFullscreen])
6550 #ifdef NS_IMPL_GNUSTEP
6551 // GNUstep does not always update the tool bar height. Force it.
6552 if (toolbar && [toolbar isVisible])
6553 update_frame_tool_bar (emacsframe);
6556 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6557 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6560 if (wait_for_tool_bar)
6562 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
6564 NSTRACE_MSG ("Waiting for toolbar");
6567 wait_for_tool_bar = NO;
6570 neww = (int)wr.size.width - emacsframe->border_width;
6571 newh = (int)wr.size.height - extra;
6573 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6574 NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
6575 NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
6577 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6578 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6580 if (cols < MINWIDTH)
6583 if (rows < MINHEIGHT)
6586 NSTRACE_MSG ("New columns: %d", cols);
6587 NSTRACE_MSG ("New rows: %d", rows);
6589 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6591 NSView *view = FRAME_NS_VIEW (emacsframe);
6593 change_frame_size (emacsframe,
6594 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6595 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6597 SET_FRAME_GARBAGED (emacsframe);
6598 cancel_mouse_face (emacsframe);
6600 /* The next two lines appear to be setting the frame to the same
6601 size as it already is. Why are they there? */
6602 // wr = NSMakeRect (0, 0, neww, newh);
6604 // [view setFrame: wr];
6606 // to do: consider using [NSNotificationCenter postNotificationName:].
6607 [self windowDidMove: // Update top/left.
6608 [NSNotification notificationWithName:NSWindowDidMoveNotification
6609 object:[view window]]];
6613 NSTRACE_MSG ("No change");
6617 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6618 /* normalize frame to gridded text size */
6622 NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6623 NSTRACE_ARG_SIZE (frameSize));
6624 NSTRACE_RECT ("[sender frame]", [sender frame]);
6625 NSTRACE_FSTYPE ("fs_state", fs_state);
6627 if (fs_state == FULLSCREEN_MAXIMIZED
6628 && (maximized_width != (int)frameSize.width
6629 || maximized_height != (int)frameSize.height))
6630 [self setFSValue: FULLSCREEN_NONE];
6631 else if (fs_state == FULLSCREEN_WIDTH
6632 && maximized_width != (int)frameSize.width)
6633 [self setFSValue: FULLSCREEN_NONE];
6634 else if (fs_state == FULLSCREEN_HEIGHT
6635 && maximized_height != (int)frameSize.height)
6636 [self setFSValue: FULLSCREEN_NONE];
6638 if (fs_state == FULLSCREEN_NONE)
6639 maximized_width = maximized_height = -1;
6641 if (! [self isFullscreen])
6643 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6644 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6647 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6648 if (cols < MINWIDTH)
6651 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6652 frameSize.height - extra);
6653 if (rows < MINHEIGHT)
6655 #ifdef NS_IMPL_COCOA
6657 /* this sets window title to have size in it; the wm does this under GS */
6658 NSRect r = [[self window] frame];
6659 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6667 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
6668 && [[self window] title] != NULL)
6671 NSWindow *window = [self window];
6674 char *t = strdup ([[[self window] title] UTF8String]);
6675 char *pos = strstr (t, " — ");
6680 size_title = xmalloc (strlen (old_title) + 40);
6681 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
6682 [window setTitle: [NSString stringWithUTF8String: size_title]];
6687 #endif /* NS_IMPL_COCOA */
6689 NSTRACE_MSG ("cols: %d rows: %d", cols, rows);
6691 /* Restrict the new size to the text gird.
6693 Don't restrict the width if the user only adjusted the height, and
6694 vice versa. (Without this, the frame would shrink, and move
6695 slightly, if the window was resized by dragging one of its
6697 if (!frame_resize_pixelwise)
6699 NSRect r = [[self window] frame];
6701 if (r.size.width != frameSize.width)
6704 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
6707 if (r.size.height != frameSize.height)
6710 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6714 NSTRACE_RETURN_SIZE (frameSize);
6720 - (void)windowDidResize: (NSNotification *)notification
6722 NSTRACE ("[EmacsView windowDidResize:]");
6723 if (!FRAME_LIVE_P (emacsframe))
6725 NSTRACE_MSG ("Ignored (frame dead)");
6728 if (emacsframe->output_data.ns->in_animation)
6730 NSTRACE_MSG ("Ignored (in animation)");
6734 if (! [self fsIsNative])
6736 NSWindow *theWindow = [notification object];
6737 /* We can get notification on the non-FS window when in
6739 if ([self window] != theWindow) return;
6742 NSTRACE_RECT ("frame", [[notification object] frame]);
6744 #ifdef NS_IMPL_GNUSTEP
6745 NSWindow *theWindow = [notification object];
6747 /* In GNUstep, at least currently, it's possible to get a didResize
6748 without getting a willResize.. therefore we need to act as if we got
6749 the willResize now */
6750 NSSize sz = [theWindow frame].size;
6751 sz = [self windowWillResize: theWindow toSize: sz];
6752 #endif /* NS_IMPL_GNUSTEP */
6754 if (cols > 0 && rows > 0)
6756 [self updateFrameSize: YES];
6759 ns_send_appdefined (-1);
6762 #ifdef NS_IMPL_COCOA
6763 - (void)viewDidEndLiveResize
6765 NSTRACE ("[EmacsView viewDidEndLiveResize]");
6767 [super viewDidEndLiveResize];
6770 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6774 maximizing_resize = NO;
6776 #endif /* NS_IMPL_COCOA */
6779 - (void)windowDidBecomeKey: (NSNotification *)notification
6780 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6782 [self windowDidBecomeKey];
6786 - (void)windowDidBecomeKey /* for direct calls */
6788 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6789 struct frame *old_focus = dpyinfo->x_focus_frame;
6791 NSTRACE ("[EmacsView windowDidBecomeKey]");
6793 if (emacsframe != old_focus)
6794 dpyinfo->x_focus_frame = emacsframe;
6796 ns_frame_rehighlight (emacsframe);
6800 emacs_event->kind = FOCUS_IN_EVENT;
6801 EV_TRAILER ((id)nil);
6806 - (void)windowDidResignKey: (NSNotification *)notification
6807 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6809 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6810 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6811 NSTRACE ("[EmacsView windowDidResignKey:]");
6814 dpyinfo->x_focus_frame = 0;
6816 emacsframe->mouse_moved = 0;
6817 ns_frame_rehighlight (emacsframe);
6819 /* FIXME: for some reason needed on second and subsequent clicks away
6820 from sole-frame Emacs to get hollow box to show */
6821 if (!windowClosing && [[self window] isVisible] == YES)
6823 x_update_cursor (emacsframe, 1);
6824 x_set_frame_alpha (emacsframe);
6827 if (any_help_event_p)
6830 XSETFRAME (frame, emacsframe);
6831 help_echo_string = Qnil;
6832 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6835 if (emacs_event && is_focus_frame)
6837 [self deleteWorkingText];
6838 emacs_event->kind = FOCUS_OUT_EVENT;
6839 EV_TRAILER ((id)nil);
6844 - (void)windowWillMiniaturize: sender
6846 NSTRACE ("[EmacsView windowWillMiniaturize:]");
6850 - (void)setFrame:(NSRect)frameRect;
6852 NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
6853 NSTRACE_ARG_RECT (frameRect));
6855 [super setFrame:(NSRect)frameRect];
6871 - (void)createToolbar: (struct frame *)f
6873 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
6874 NSWindow *window = [view window];
6876 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6877 [NSString stringWithFormat: @"Emacs Frame %d",
6879 [toolbar setVisible: NO];
6880 [window setToolbar: toolbar];
6882 /* Don't set frame garbaged until tool bar is up to date?
6883 This avoids an extra clear and redraw (flicker) at frame creation. */
6884 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6885 else wait_for_tool_bar = NO;
6888 #ifdef NS_IMPL_COCOA
6890 NSButton *toggleButton;
6891 toggleButton = [window standardWindowButton: NSWindowToolbarButton];
6892 [toggleButton setTarget: self];
6893 [toggleButton setAction: @selector (toggleToolbar: )];
6899 - initFrameFromEmacs: (struct frame *)f
6907 NSTRACE ("[EmacsView initFrameFromEmacs:]");
6908 NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
6911 processingCompose = NO;
6912 scrollbarsNeedingUpdate = 0;
6913 fs_state = FULLSCREEN_NONE;
6914 fs_before_fs = next_maximized = -1;
6915 #ifdef HAVE_NATIVE_FS
6916 fs_is_native = ns_use_native_fullscreen;
6920 maximized_width = maximized_height = -1;
6923 ns_userRect = NSMakeRect (0, 0, 0, 0);
6924 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6925 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6926 [self initWithFrame: r];
6927 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6929 FRAME_NS_VIEW (f) = self;
6931 #ifdef NS_IMPL_COCOA
6933 maximizing_resize = NO;
6936 win = [[EmacsWindow alloc]
6937 initWithContentRect: r
6938 styleMask: (FRAME_UNDECORATED (f)
6939 ? FRAME_UNDECORATED_FLAGS
6940 : FRAME_DECORATED_FLAGS
6941 #ifdef NS_IMPL_COCOA
6942 | NSWindowStyleMaskResizable
6943 | NSWindowStyleMaskMiniaturizable
6944 | NSWindowStyleMaskClosable
6947 backing: NSBackingStoreBuffered
6950 #ifdef HAVE_NATIVE_FS
6951 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6955 bwidth = f->border_width = wr.size.width - r.size.width;
6957 [win setAcceptsMouseMovedEvents: YES];
6958 [win setDelegate: self];
6959 #if !defined (NS_IMPL_COCOA) || \
6960 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6961 [win useOptimizedDrawing: YES];
6964 [[win contentView] addSubview: self];
6967 [self registerForDraggedTypes: ns_drag_types];
6970 name = [NSString stringWithUTF8String:
6971 NILP (tem) ? "Emacs" : SSDATA (tem)];
6972 [win setTitle: name];
6974 /* toolbar support */
6975 if (! FRAME_UNDECORATED (f))
6976 [self createToolbar: f];
6980 [win setMiniwindowTitle:
6981 [NSString stringWithUTF8String: SSDATA (tem)]];
6983 if (FRAME_PARENT_FRAME (f) != NULL)
6985 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
6986 [parent addChildWindow: win
6987 ordered: NSWindowAbove];
6990 if (FRAME_Z_GROUP (f) != z_group_none)
6991 win.level = NSNormalWindowLevel
6992 + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
6995 NSScreen *screen = [win screen];
6999 NSPoint pt = NSMakePoint
7000 (IN_BOUND (-SCREENMAX, f->left_pos
7001 + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7002 IN_BOUND (-SCREENMAX,
7003 NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7006 [win setFrameTopLeftPoint: pt];
7008 NSTRACE_RECT ("new frame", [win frame]);
7012 [win makeFirstResponder: self];
7014 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7015 (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7017 [win setBackgroundColor: col];
7018 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7019 [win setOpaque: NO];
7021 #if !defined (NS_IMPL_COCOA) || \
7022 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7023 [self allocateGState];
7025 [NSApp registerServicesMenuSendTypes: ns_send_types
7028 /* macOS Sierra automatically enables tabbed windows. We can't
7029 allow this to be enabled until it's available on a Free system.
7030 Currently it only happens by accident and is buggy anyway. */
7031 #if defined (NS_IMPL_COCOA) && \
7032 MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
7033 [win setTabbingMode: NSWindowTabbingModeDisallowed];
7041 - (void)windowDidMove: sender
7043 NSWindow *win = [self window];
7044 NSRect r = [win frame];
7045 NSArray *screens = [NSScreen screens];
7046 NSScreen *screen = [screens objectAtIndex: 0];
7048 NSTRACE ("[EmacsView windowDidMove:]");
7050 if (!emacsframe->output_data.ns)
7054 emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7055 emacsframe->top_pos =
7056 NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7060 emacs_event->kind = MOVE_FRAME_EVENT;
7061 EV_TRAILER ((id)nil);
7067 /* Called AFTER method below, but before our windowWillResize call there leads
7068 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
7069 location so set_window_size moves the frame. */
7070 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7072 NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7073 NSTRACE_FMT_RETURN "YES"),
7074 NSTRACE_ARG_RECT (newFrame));
7076 emacsframe->output_data.ns->zooming = 1;
7081 /* Override to do something slightly nonstandard, but nice. First click on
7082 zoom button will zoom vertically. Second will zoom completely. Third
7083 returns to original. */
7084 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7085 defaultFrame:(NSRect)defaultFrame
7087 // TODO: Rename to "currentFrame" and assign "result" properly in
7089 NSRect result = [sender frame];
7091 NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7092 NSTRACE_FMT_RECT "]"),
7093 NSTRACE_ARG_RECT (defaultFrame));
7094 NSTRACE_FSTYPE ("fs_state", fs_state);
7095 NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7096 NSTRACE_FSTYPE ("next_maximized", next_maximized);
7097 NSTRACE_RECT ("ns_userRect", ns_userRect);
7098 NSTRACE_RECT ("[sender frame]", [sender frame]);
7100 if (fs_before_fs != -1) /* Entering fullscreen */
7102 NSTRACE_MSG ("Entering fullscreen");
7103 result = defaultFrame;
7107 // Save the window size and position (frame) before the resize.
7108 if (fs_state != FULLSCREEN_MAXIMIZED
7109 && fs_state != FULLSCREEN_WIDTH)
7111 ns_userRect.size.width = result.size.width;
7112 ns_userRect.origin.x = result.origin.x;
7115 if (fs_state != FULLSCREEN_MAXIMIZED
7116 && fs_state != FULLSCREEN_HEIGHT)
7118 ns_userRect.size.height = result.size.height;
7119 ns_userRect.origin.y = result.origin.y;
7122 NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7124 if (next_maximized == FULLSCREEN_HEIGHT
7125 || (next_maximized == -1
7126 && abs ((int)(defaultFrame.size.height - result.size.height))
7127 > FRAME_LINE_HEIGHT (emacsframe)))
7130 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7131 maximized_height = result.size.height = defaultFrame.size.height;
7132 maximized_width = -1;
7133 result.origin.y = defaultFrame.origin.y;
7134 if (ns_userRect.size.height != 0)
7136 result.origin.x = ns_userRect.origin.x;
7137 result.size.width = ns_userRect.size.width;
7139 [self setFSValue: FULLSCREEN_HEIGHT];
7140 #ifdef NS_IMPL_COCOA
7141 maximizing_resize = YES;
7144 else if (next_maximized == FULLSCREEN_WIDTH)
7146 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7147 maximized_width = result.size.width = defaultFrame.size.width;
7148 maximized_height = -1;
7149 result.origin.x = defaultFrame.origin.x;
7150 if (ns_userRect.size.width != 0)
7152 result.origin.y = ns_userRect.origin.y;
7153 result.size.height = ns_userRect.size.height;
7155 [self setFSValue: FULLSCREEN_WIDTH];
7157 else if (next_maximized == FULLSCREEN_MAXIMIZED
7158 || (next_maximized == -1
7159 && abs ((int)(defaultFrame.size.width - result.size.width))
7160 > FRAME_COLUMN_WIDTH (emacsframe)))
7162 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7164 result = defaultFrame; /* second click */
7165 maximized_width = result.size.width;
7166 maximized_height = result.size.height;
7167 [self setFSValue: FULLSCREEN_MAXIMIZED];
7168 #ifdef NS_IMPL_COCOA
7169 maximizing_resize = YES;
7175 NSTRACE_MSG ("Restore");
7176 result = ns_userRect.size.height ? ns_userRect : result;
7177 NSTRACE_RECT ("restore (2)", result);
7178 ns_userRect = NSMakeRect (0, 0, 0, 0);
7179 #ifdef NS_IMPL_COCOA
7180 maximizing_resize = fs_state != FULLSCREEN_NONE;
7182 [self setFSValue: FULLSCREEN_NONE];
7183 maximized_width = maximized_height = -1;
7187 if (fs_before_fs == -1) next_maximized = -1;
7189 NSTRACE_RECT ("Final ns_userRect", ns_userRect);
7190 NSTRACE_MSG ("Final maximized_width: %d", maximized_width);
7191 NSTRACE_MSG ("Final maximized_height: %d", maximized_height);
7192 NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7194 [self windowWillResize: sender toSize: result.size];
7196 NSTRACE_RETURN_RECT (result);
7202 - (void)windowDidDeminiaturize: sender
7204 NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7205 if (!emacsframe->output_data.ns)
7208 SET_FRAME_ICONIFIED (emacsframe, 0);
7209 SET_FRAME_VISIBLE (emacsframe, 1);
7210 windows_or_buffers_changed = 63;
7214 emacs_event->kind = DEICONIFY_EVENT;
7215 EV_TRAILER ((id)nil);
7220 - (void)windowDidExpose: sender
7222 NSTRACE ("[EmacsView windowDidExpose:]");
7223 if (!emacsframe->output_data.ns)
7226 SET_FRAME_VISIBLE (emacsframe, 1);
7227 SET_FRAME_GARBAGED (emacsframe);
7229 if (send_appdefined)
7230 ns_send_appdefined (-1);
7234 - (void)windowDidMiniaturize: sender
7236 NSTRACE ("[EmacsView windowDidMiniaturize:]");
7237 if (!emacsframe->output_data.ns)
7240 SET_FRAME_ICONIFIED (emacsframe, 1);
7241 SET_FRAME_VISIBLE (emacsframe, 0);
7245 emacs_event->kind = ICONIFY_EVENT;
7246 EV_TRAILER ((id)nil);
7250 #ifdef HAVE_NATIVE_FS
7251 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7252 willUseFullScreenPresentationOptions:
7253 (NSApplicationPresentationOptions)proposedOptions
7255 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7259 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7261 NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7262 [self windowWillEnterFullScreen];
7264 - (void)windowWillEnterFullScreen /* provided for direct calls */
7266 NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7267 fs_before_fs = fs_state;
7270 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7272 NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7273 [self windowDidEnterFullScreen];
7276 - (void)windowDidEnterFullScreen /* provided for direct calls */
7278 NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7279 [self setFSValue: FULLSCREEN_BOTH];
7280 if (! [self fsIsNative])
7282 [self windowDidBecomeKey];
7283 [nonfs_window orderOut:self];
7287 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7288 #ifdef NS_IMPL_COCOA
7289 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
7290 unsigned val = (unsigned)[NSApp presentationOptions];
7292 // Mac OS X 10.7 bug fix, the menu won't appear without this.
7293 // val is non-zero on other macOS versions.
7296 NSApplicationPresentationOptions options
7297 = NSApplicationPresentationAutoHideDock
7298 | NSApplicationPresentationAutoHideMenuBar
7299 | NSApplicationPresentationFullScreen
7300 | NSApplicationPresentationAutoHideToolbar;
7302 [NSApp setPresentationOptions: options];
7306 [toolbar setVisible:tbar_visible];
7310 - (void)windowWillExitFullScreen:(NSNotification *)notification
7312 NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7313 [self windowWillExitFullScreen];
7316 - (void)windowWillExitFullScreen /* provided for direct calls */
7318 NSTRACE ("[EmacsView windowWillExitFullScreen]");
7319 if (!FRAME_LIVE_P (emacsframe))
7321 NSTRACE_MSG ("Ignored (frame dead)");
7324 if (next_maximized != -1)
7325 fs_before_fs = next_maximized;
7328 - (void)windowDidExitFullScreen:(NSNotification *)notification
7330 NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7331 [self windowDidExitFullScreen];
7334 - (void)windowDidExitFullScreen /* provided for direct calls */
7336 NSTRACE ("[EmacsView windowDidExitFullScreen]");
7337 if (!FRAME_LIVE_P (emacsframe))
7339 NSTRACE_MSG ("Ignored (frame dead)");
7342 [self setFSValue: fs_before_fs];
7344 #ifdef HAVE_NATIVE_FS
7345 [self updateCollectionBehavior];
7347 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7349 [toolbar setVisible:YES];
7350 update_frame_tool_bar (emacsframe);
7351 [self updateFrameSize:YES];
7352 [[self window] display];
7355 [toolbar setVisible:NO];
7357 if (next_maximized != -1)
7358 [[self window] performZoom:self];
7363 return fs_is_native;
7366 - (BOOL)isFullscreen
7372 res = (nonfs_window != nil);
7376 #ifdef HAVE_NATIVE_FS
7377 res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7383 NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7389 #ifdef HAVE_NATIVE_FS
7390 - (void)updateCollectionBehavior
7392 NSTRACE ("[EmacsView updateCollectionBehavior]");
7394 if (! [self isFullscreen])
7396 NSWindow *win = [self window];
7397 NSWindowCollectionBehavior b = [win collectionBehavior];
7398 if (ns_use_native_fullscreen)
7399 b |= NSWindowCollectionBehaviorFullScreenPrimary;
7401 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7403 [win setCollectionBehavior: b];
7404 fs_is_native = ns_use_native_fullscreen;
7409 - (void)toggleFullScreen: (id)sender
7417 NSTRACE ("[EmacsView toggleFullScreen:]");
7421 #ifdef HAVE_NATIVE_FS
7422 [[self window] toggleFullScreen:sender];
7428 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7431 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7432 (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7435 if (fs_state != FULLSCREEN_BOTH)
7437 NSScreen *screen = [w screen];
7439 #if defined (NS_IMPL_COCOA) && \
7440 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7441 /* Hide ghost menu bar on secondary monitor? */
7442 if (! onFirstScreen)
7443 onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7445 /* Hide dock and menubar if we are on the primary screen. */
7448 #ifdef NS_IMPL_COCOA
7449 NSApplicationPresentationOptions options
7450 = NSApplicationPresentationAutoHideDock
7451 | NSApplicationPresentationAutoHideMenuBar;
7453 [NSApp setPresentationOptions: options];
7455 [NSMenu setMenuBarVisible:NO];
7459 fw = [[EmacsFSWindow alloc]
7460 initWithContentRect:[w contentRectForFrameRect:wr]
7461 styleMask:NSWindowStyleMaskBorderless
7462 backing:NSBackingStoreBuffered
7466 [fw setContentView:[w contentView]];
7467 [fw setTitle:[w title]];
7468 [fw setDelegate:self];
7469 [fw setAcceptsMouseMovedEvents: YES];
7470 #if !defined (NS_IMPL_COCOA) || \
7471 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7472 [fw useOptimizedDrawing: YES];
7474 [fw setBackgroundColor: col];
7475 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7478 f->border_width = 0;
7482 [self windowWillEnterFullScreen];
7483 [fw makeKeyAndOrderFront:NSApp];
7484 [fw makeFirstResponder:self];
7486 r = [fw frameRectForContentRect:[screen frame]];
7487 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7488 [self windowDidEnterFullScreen];
7499 #ifdef NS_IMPL_COCOA
7500 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7502 [NSMenu setMenuBarVisible:YES];
7506 [w setContentView:[fw contentView]];
7507 [w setBackgroundColor: col];
7508 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7511 f->border_width = bwidth;
7513 // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7515 [self windowWillExitFullScreen];
7516 [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7518 [w makeKeyAndOrderFront:NSApp];
7519 [self windowDidExitFullScreen];
7520 [self updateFrameSize:YES];
7526 NSTRACE ("[EmacsView handleFS]");
7528 if (fs_state != emacsframe->want_fullscreen)
7530 if (fs_state == FULLSCREEN_BOTH)
7532 NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7533 [self toggleFullScreen:self];
7536 switch (emacsframe->want_fullscreen)
7538 case FULLSCREEN_BOTH:
7539 NSTRACE_MSG ("FULLSCREEN_BOTH");
7540 [self toggleFullScreen:self];
7542 case FULLSCREEN_WIDTH:
7543 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7544 next_maximized = FULLSCREEN_WIDTH;
7545 if (fs_state != FULLSCREEN_BOTH)
7546 [[self window] performZoom:self];
7548 case FULLSCREEN_HEIGHT:
7549 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7550 next_maximized = FULLSCREEN_HEIGHT;
7551 if (fs_state != FULLSCREEN_BOTH)
7552 [[self window] performZoom:self];
7554 case FULLSCREEN_MAXIMIZED:
7555 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7556 next_maximized = FULLSCREEN_MAXIMIZED;
7557 if (fs_state != FULLSCREEN_BOTH)
7558 [[self window] performZoom:self];
7560 case FULLSCREEN_NONE:
7561 NSTRACE_MSG ("FULLSCREEN_NONE");
7562 if (fs_state != FULLSCREEN_BOTH)
7564 next_maximized = FULLSCREEN_NONE;
7565 [[self window] performZoom:self];
7570 emacsframe->want_fullscreen = FULLSCREEN_NONE;
7575 - (void) setFSValue: (int)value
7577 NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7578 NSTRACE_ARG_FSTYPE(value));
7580 Lisp_Object lval = Qnil;
7583 case FULLSCREEN_BOTH:
7586 case FULLSCREEN_WIDTH:
7589 case FULLSCREEN_HEIGHT:
7592 case FULLSCREEN_MAXIMIZED:
7596 store_frame_param (emacsframe, Qfullscreen, lval);
7600 - (void)mouseEntered: (NSEvent *)theEvent
7602 NSTRACE ("[EmacsView mouseEntered:]");
7604 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7605 = EV_TIMESTAMP (theEvent);
7609 - (void)mouseExited: (NSEvent *)theEvent
7611 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7613 NSTRACE ("[EmacsView mouseExited:]");
7618 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7619 = EV_TIMESTAMP (theEvent);
7621 if (emacsframe == hlinfo->mouse_face_mouse_frame)
7623 clear_mouse_face (hlinfo);
7624 hlinfo->mouse_face_mouse_frame = 0;
7631 NSTRACE ("[EmacsView menuDown:]");
7632 if (context_menu_value == -1)
7633 context_menu_value = [sender tag];
7636 NSInteger tag = [sender tag];
7637 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7638 emacsframe->menu_bar_vector,
7642 ns_send_appdefined (-1);
7647 - (EmacsToolbar *)toolbar
7653 /* this gets called on toolbar button click */
7654 - toolbarClicked: (id)item
7657 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7659 NSTRACE ("[EmacsView toolbarClicked:]");
7664 /* send first event (for some reason two needed) */
7665 theEvent = [[self window] currentEvent];
7666 emacs_event->kind = TOOL_BAR_EVENT;
7667 XSETFRAME (emacs_event->arg, emacsframe);
7668 EV_TRAILER (theEvent);
7670 emacs_event->kind = TOOL_BAR_EVENT;
7671 /* XSETINT (emacs_event->code, 0); */
7672 emacs_event->arg = AREF (emacsframe->tool_bar_items,
7673 idx + TOOL_BAR_ITEM_KEY);
7674 emacs_event->modifiers = EV_MODIFIERS (theEvent);
7675 EV_TRAILER (theEvent);
7680 - toggleToolbar: (id)sender
7682 NSTRACE ("[EmacsView toggleToolbar:]");
7687 emacs_event->kind = NS_NONKEY_EVENT;
7688 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7689 EV_TRAILER ((id)nil);
7694 - (void)drawRect: (NSRect)rect
7696 int x = NSMinX (rect), y = NSMinY (rect);
7697 int width = NSWidth (rect), height = NSHeight (rect);
7699 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7700 NSTRACE_ARG_RECT(rect));
7702 if (!emacsframe || !emacsframe->output_data.ns)
7705 ns_clear_frame_area (emacsframe, x, y, width, height);
7707 expose_frame (emacsframe, x, y, width, height);
7711 drawRect: may be called (at least in Mac OS X 10.5) for invisible
7712 views as well for some reason. Thus, do not infer visibility
7715 emacsframe->async_visible = 1;
7716 emacsframe->async_iconified = 0;
7721 /* NSDraggingDestination protocol methods. Actually this is not really a
7722 protocol, but a category of Object. O well... */
7724 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7726 NSTRACE ("[EmacsView draggingEntered:]");
7727 return NSDragOperationGeneric;
7731 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7737 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7742 NSEvent *theEvent = [[self window] currentEvent];
7744 NSDragOperation op = [sender draggingSourceOperationMask];
7747 NSTRACE ("[EmacsView performDragOperation:]");
7752 position = [self convertPoint: [sender draggingLocation] fromView: nil];
7753 x = lrint (position.x); y = lrint (position.y);
7755 pb = [sender draggingPasteboard];
7756 type = [pb availableTypeFromArray: ns_drag_types];
7758 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7759 // URL drags contain all operations (0xf), don't allow all to be set.
7762 if (op & NSDragOperationLink)
7763 modifiers |= NSEventModifierFlagControl;
7764 if (op & NSDragOperationCopy)
7765 modifiers |= NSEventModifierFlagOption;
7766 if (op & NSDragOperationGeneric)
7767 modifiers |= NSEventModifierFlagCommand;
7770 modifiers = EV_MODIFIERS2 (modifiers);
7775 else if ([type isEqualToString: NSFilenamesPboardType])
7778 NSEnumerator *fenum;
7781 if (!(files = [pb propertyListForType: type]))
7784 fenum = [files objectEnumerator];
7785 while ( (file = [fenum nextObject]) )
7787 emacs_event->kind = DRAG_N_DROP_EVENT;
7788 XSETINT (emacs_event->x, x);
7789 XSETINT (emacs_event->y, y);
7790 ns_input_file = append2 (ns_input_file,
7791 build_string ([file UTF8String]));
7792 emacs_event->modifiers = modifiers;
7793 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
7794 EV_TRAILER (theEvent);
7798 else if ([type isEqualToString: NSURLPboardType])
7800 NSURL *url = [NSURL URLFromPasteboard: pb];
7801 if (url == nil) return NO;
7803 emacs_event->kind = DRAG_N_DROP_EVENT;
7804 XSETINT (emacs_event->x, x);
7805 XSETINT (emacs_event->y, y);
7806 emacs_event->modifiers = modifiers;
7807 emacs_event->arg = list2 (Qurl,
7808 build_string ([[url absoluteString]
7810 EV_TRAILER (theEvent);
7812 if ([url isFileURL] != NO)
7814 NSString *file = [url path];
7815 ns_input_file = append2 (ns_input_file,
7816 build_string ([file UTF8String]));
7820 else if ([type isEqualToString: NSStringPboardType]
7821 || [type isEqualToString: NSTabularTextPboardType])
7825 if (! (data = [pb stringForType: type]))
7828 emacs_event->kind = DRAG_N_DROP_EVENT;
7829 XSETINT (emacs_event->x, x);
7830 XSETINT (emacs_event->y, y);
7831 emacs_event->modifiers = modifiers;
7832 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
7833 EV_TRAILER (theEvent);
7838 fprintf (stderr, "Invalid data type in dragging pasteboard");
7844 - (id) validRequestorForSendType: (NSString *)typeSent
7845 returnType: (NSString *)typeReturned
7847 NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
7848 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7849 && typeReturned == nil)
7851 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7855 return [super validRequestorForSendType: typeSent
7856 returnType: typeReturned];
7860 /* The next two methods are part of NSServicesRequests informal protocol,
7861 supposedly called when a services menu item is chosen from this app.
7862 But this should not happen because we override the services menu with our
7863 own entries which call ns-perform-service.
7864 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7865 So let's at least stub them out until further investigation can be done. */
7867 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7869 /* we could call ns_string_from_pasteboard(pboard) here but then it should
7870 be written into the buffer in place of the existing selection..
7871 ordinary service calls go through functions defined in ns-win.el */
7875 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7877 NSArray *typesDeclared;
7880 NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
7882 /* We only support NSStringPboardType */
7883 if ([types containsObject:NSStringPboardType] == NO) {
7887 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7888 if (CONSP (val) && SYMBOLP (XCAR (val)))
7891 if (CONSP (val) && NILP (XCDR (val)))
7894 if (! STRINGP (val))
7897 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7898 [pb declareTypes:typesDeclared owner:nil];
7899 ns_string_to_pasteboard (pb, val);
7904 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7905 (gives a miniaturized version of the window); currently we use the latter for
7906 frames whose active buffer doesn't correspond to any file
7907 (e.g., '*scratch*') */
7908 - setMiniwindowImage: (BOOL) setMini
7910 id image = [[self window] miniwindowImage];
7911 NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
7913 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7914 about "AppleDockIconEnabled" notwithstanding, however the set message
7915 below has its effect nonetheless. */
7916 if (image != emacsframe->output_data.ns->miniimage)
7918 if (image && [image isKindOfClass: [EmacsImage class]])
7920 [[self window] setMiniwindowImage:
7921 setMini ? emacsframe->output_data.ns->miniimage : nil];
7928 - (void) setRows: (int) r andColumns: (int) c
7930 NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
7935 - (int) fullscreenState
7940 @end /* EmacsView */
7944 /* ==========================================================================
7946 EmacsWindow implementation
7948 ========================================================================== */
7950 @implementation EmacsWindow
7952 #ifdef NS_IMPL_COCOA
7953 - (id)accessibilityAttributeValue:(NSString *)attribute
7955 Lisp_Object str = Qnil;
7956 struct frame *f = SELECTED_FRAME ();
7957 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7959 NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
7961 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7962 return NSAccessibilityTextFieldRole;
7964 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7965 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7967 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7969 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7971 if (! NILP (BVAR (curbuf, mark_active)))
7972 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7976 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7977 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7978 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7980 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7981 str = make_uninit_multibyte_string (range, byte_range);
7983 str = make_uninit_string (range);
7984 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7985 Is this a problem? */
7986 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7993 if (CONSP (str) && SYMBOLP (XCAR (str)))
7996 if (CONSP (str) && NILP (XCDR (str)))
8001 const char *utfStr = SSDATA (str);
8002 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8007 return [super accessibilityAttributeValue:attribute];
8009 #endif /* NS_IMPL_COCOA */
8011 /* Constrain size and placement of a frame.
8013 By returning the original "frameRect", the frame is not
8014 constrained. This can lead to unwanted situations where, for
8015 example, the menu bar covers the frame.
8017 The default implementation (accessed using "super") constrains the
8018 frame to the visible area of SCREEN, minus the menu bar (if
8019 present) and the Dock. Note that default implementation also calls
8020 windowWillResize, with the frame it thinks should have. (This can
8021 make the frame exit maximized mode.)
8023 Note that this should work in situations where multiple monitors
8024 are present. Common configurations are side-by-side monitors and a
8025 monitor on top of another (e.g. when a laptop is placed under a
8027 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8029 NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8030 NSTRACE_ARG_RECT (frameRect));
8032 #ifdef NS_IMPL_COCOA
8033 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
8034 // If separate spaces is on, it is like each screen is independent. There is
8035 // no spanning of frames across screens.
8036 if ([NSScreen screensHaveSeparateSpaces])
8038 NSTRACE_MSG ("Screens have separate spaces");
8039 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8040 NSTRACE_RETURN_RECT (frameRect);
8046 return constrain_frame_rect(frameRect,
8047 [(EmacsView *)[self delegate] isFullscreen]);
8051 - (void)performZoom:(id)sender
8053 NSTRACE ("[EmacsWindow performZoom:]");
8055 return [super performZoom:sender];
8058 - (void)zoom:(id)sender
8060 NSTRACE ("[EmacsWindow zoom:]");
8062 ns_update_auto_hide_menu_bar();
8064 // Below are three zoom implementations. In the final commit, the
8065 // idea is that the last should be included.
8068 // Native zoom done using the standard zoom animation. Size of the
8069 // resulting frame reduced to accommodate the Dock and, if present,
8071 [super zoom:sender];
8074 // Native zoom done using the standard zoom animation, plus an
8075 // explicit resize to cover the full screen, except the menu-bar and
8076 // dock, if present.
8077 [super zoom:sender];
8079 // After the native zoom, resize the resulting frame to fill the
8080 // entire screen, except the menu-bar.
8082 // This works for all practical purposes. (The only minor oddity is
8083 // when transiting from full-height frame to a maximized, the
8084 // animation reduces the height of the frame slightly (to the 4
8085 // pixels needed to accommodate the Doc) before it snaps back into
8086 // full height. The user would need a very trained eye to spot
8088 NSScreen * screen = [self screen];
8091 int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8093 NSTRACE_FSTYPE ("fullscreenState", fs_state);
8095 NSRect sr = [screen frame];
8096 struct EmacsMargins margins
8097 = ns_screen_margins_ignoring_hidden_dock(screen);
8099 NSRect wr = [self frame];
8100 NSTRACE_RECT ("Rect after zoom", wr);
8104 if (fs_state == FULLSCREEN_MAXIMIZED
8105 || fs_state == FULLSCREEN_HEIGHT)
8107 newWr.origin.y = sr.origin.y + margins.bottom;
8108 newWr.size.height = sr.size.height - margins.top - margins.bottom;
8111 if (fs_state == FULLSCREEN_MAXIMIZED
8112 || fs_state == FULLSCREEN_WIDTH)
8114 newWr.origin.x = sr.origin.x + margins.left;
8115 newWr.size.width = sr.size.width - margins.right - margins.left;
8118 if (newWr.size.width != wr.size.width
8119 || newWr.size.height != wr.size.height
8120 || newWr.origin.x != wr.origin.x
8121 || newWr.origin.y != wr.origin.y)
8123 NSTRACE_MSG ("New frame different");
8124 [self setFrame: newWr display: NO];
8128 // Non-native zoom which is done instantaneously. The resulting
8129 // frame covers the entire screen, except the menu-bar and dock, if
8131 NSScreen * screen = [self screen];
8134 NSRect sr = [screen frame];
8135 struct EmacsMargins margins
8136 = ns_screen_margins_ignoring_hidden_dock(screen);
8138 sr.size.height -= (margins.top + margins.bottom);
8139 sr.size.width -= (margins.left + margins.right);
8140 sr.origin.x += margins.left;
8141 sr.origin.y += margins.bottom;
8143 sr = [[self delegate] windowWillUseStandardFrame:self
8145 [self setFrame: sr display: NO];
8150 - (void)setFrame:(NSRect)windowFrame
8151 display:(BOOL)displayViews
8153 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8154 NSTRACE_ARG_RECT (windowFrame), displayViews);
8156 [super setFrame:windowFrame display:displayViews];
8159 - (void)setFrame:(NSRect)windowFrame
8160 display:(BOOL)displayViews
8161 animate:(BOOL)performAnimation
8163 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8164 " display:%d performAnimation:%d]",
8165 NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8167 [super setFrame:windowFrame display:displayViews animate:performAnimation];
8170 - (void)setFrameTopLeftPoint:(NSPoint)point
8172 NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8173 NSTRACE_ARG_POINT (point));
8175 [super setFrameTopLeftPoint:point];
8178 - (BOOL)canBecomeKeyWindow
8180 return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8182 @end /* EmacsWindow */
8185 @implementation EmacsFSWindow
8187 - (BOOL)canBecomeKeyWindow
8192 - (BOOL)canBecomeMainWindow
8199 /* ==========================================================================
8201 EmacsScroller implementation
8203 ========================================================================== */
8206 @implementation EmacsScroller
8208 /* for repeat button push */
8209 #define SCROLL_BAR_FIRST_DELAY 0.5
8210 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8212 + (CGFloat) scrollerWidth
8214 /* TODO: if we want to allow variable widths, this is the place to do it,
8215 however neither GNUstep nor Cocoa support it very well */
8217 #if !defined (NS_IMPL_COCOA) || \
8218 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
8219 r = [NSScroller scrollerWidth];
8221 r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8222 scrollerStyle: NSScrollerStyleLegacy];
8227 - initFrame: (NSRect )r window: (Lisp_Object)nwin
8229 NSTRACE ("[EmacsScroller initFrame: window:]");
8231 if (r.size.width > r.size.height)
8236 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8237 [self setContinuous: YES];
8238 [self setEnabled: YES];
8240 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8241 locked against the top and bottom edges, and right edge on macOS, where
8242 scrollers are on right. */
8243 #ifdef NS_IMPL_GNUSTEP
8244 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8246 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8249 window = XWINDOW (nwin);
8252 pixel_length = NSWidth (r);
8254 pixel_length = NSHeight (r);
8255 if (pixel_length == 0) pixel_length = 1;
8256 min_portion = 20 / pixel_length;
8258 frame = XFRAME (window->frame);
8259 if (FRAME_LIVE_P (frame))
8262 EmacsView *view = FRAME_NS_VIEW (frame);
8263 NSView *sview = [[view window] contentView];
8264 NSArray *subs = [sview subviews];
8266 /* disable optimization stopping redraw of other scrollbars */
8267 view->scrollbarsNeedingUpdate = 0;
8268 for (i =[subs count]-1; i >= 0; i--)
8269 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8270 view->scrollbarsNeedingUpdate++;
8271 [sview addSubview: self];
8274 /* [self setFrame: r]; */
8280 - (void)setFrame: (NSRect)newRect
8282 NSTRACE ("[EmacsScroller setFrame:]");
8284 /* block_input (); */
8286 pixel_length = NSWidth (newRect);
8288 pixel_length = NSHeight (newRect);
8289 if (pixel_length == 0) pixel_length = 1;
8290 min_portion = 20 / pixel_length;
8291 [super setFrame: newRect];
8292 /* unblock_input (); */
8298 NSTRACE ("[EmacsScroller dealloc]");
8302 wset_horizontal_scroll_bar (window, Qnil);
8304 wset_vertical_scroll_bar (window, Qnil);
8313 NSTRACE ("[EmacsScroller condemn]");
8321 NSTRACE ("[EmacsScroller reprieve]");
8329 NSTRACE ("[EmacsScroller judge]");
8330 bool ret = condemned;
8335 /* ensure other scrollbar updates after deletion */
8336 view = (EmacsView *)FRAME_NS_VIEW (frame);
8338 view->scrollbarsNeedingUpdate++;
8342 wset_horizontal_scroll_bar (window, Qnil);
8344 wset_vertical_scroll_bar (window, Qnil);
8347 [self removeFromSuperview];
8355 - (void)resetCursorRects
8357 NSRect visible = [self visibleRect];
8358 NSTRACE ("[EmacsScroller resetCursorRects]");
8360 if (!NSIsEmptyRect (visible))
8361 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8362 [[NSCursor arrowCursor] setOnMouseEntered: YES];
8366 - (int) checkSamePosition: (int) position portion: (int) portion
8369 return em_position ==position && em_portion ==portion && em_whole ==whole
8370 && portion != whole; /* needed for resize empty buf */
8374 - setPosition: (int)position portion: (int)portion whole: (int)whole
8376 NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8378 em_position = position;
8379 em_portion = portion;
8382 if (portion >= whole)
8384 #ifdef NS_IMPL_COCOA
8385 [self setKnobProportion: 1.0];
8386 [self setDoubleValue: 1.0];
8388 [self setFloatValue: 0.0 knobProportion: 1.0];
8395 portion = max ((float)whole*min_portion/pixel_length, portion);
8396 pos = (float)position / (whole - portion);
8397 por = (CGFloat)portion/whole;
8398 #ifdef NS_IMPL_COCOA
8399 [self setKnobProportion: por];
8400 [self setDoubleValue: pos];
8402 [self setFloatValue: pos knobProportion: por];
8409 /* set up emacs_event */
8410 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8414 NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8419 emacs_event->part = last_hit_part;
8420 emacs_event->code = 0;
8421 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8422 XSETWINDOW (win, window);
8423 emacs_event->frame_or_window = win;
8424 emacs_event->timestamp = EV_TIMESTAMP (e);
8425 emacs_event->arg = Qnil;
8429 emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8430 XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8431 XSETINT (emacs_event->y, em_whole);
8435 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8436 XSETINT (emacs_event->x, loc);
8437 XSETINT (emacs_event->y, pixel_length-20);
8442 n_emacs_events_pending++;
8443 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8446 hold_event (emacs_event);
8447 EVENT_INIT (*emacs_event);
8448 ns_send_appdefined (-1);
8452 /* called manually thru timer to implement repeated button action w/hold-down */
8453 - repeatScroll: (NSTimer *)scrollEntry
8455 NSEvent *e = [[self window] currentEvent];
8456 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
8457 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8459 NSTRACE ("[EmacsScroller repeatScroll:]");
8461 /* clear timer if need be */
8462 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8464 [scroll_repeat_entry invalidate];
8465 [scroll_repeat_entry release];
8466 scroll_repeat_entry = nil;
8472 = [[NSTimer scheduledTimerWithTimeInterval:
8473 SCROLL_BAR_CONTINUOUS_DELAY
8475 selector: @selector (repeatScroll:)
8481 [self sendScrollEventAtLoc: 0 fromEvent: e];
8486 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
8487 mouseDragged events without going into a modal loop. */
8488 - (void)mouseDown: (NSEvent *)e
8491 /* hitPart is only updated AFTER event is passed on */
8492 NSScrollerPart part = [self testPart: [e locationInWindow]];
8493 CGFloat loc, kloc, pos UNINIT;
8496 NSTRACE ("[EmacsScroller mouseDown:]");
8500 case NSScrollerDecrementPage:
8501 last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
8502 case NSScrollerIncrementPage:
8503 last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
8504 case NSScrollerDecrementLine:
8505 last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
8506 case NSScrollerIncrementLine:
8507 last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
8508 case NSScrollerKnob:
8509 last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
8510 case NSScrollerKnobSlot: /* GNUstep-only */
8511 last_hit_part = scroll_bar_move_ratio; break;
8512 default: /* NSScrollerNoPart? */
8513 fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
8518 if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
8520 /* handle, or on GNUstep possibly slot */
8521 NSEvent *fake_event;
8524 /* compute float loc in slot and mouse offset on knob */
8525 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8529 length = NSWidth (sr);
8530 loc = ([e locationInWindow].x - NSMinX (sr));
8534 length = NSHeight (sr);
8535 loc = length - ([e locationInWindow].y - NSMinY (sr));
8543 else if (loc >= length)
8553 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8556 kloc = ([e locationInWindow].x - NSMinX (kr));
8558 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8560 last_mouse_offset = kloc;
8562 if (part != NSScrollerKnob)
8563 /* this is a slot click on GNUstep: go straight there */
8566 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8567 fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
8568 location: [e locationInWindow]
8569 modifierFlags: [e modifierFlags]
8570 timestamp: [e timestamp]
8571 windowNumber: [e windowNumber]
8572 context: [e context]
8573 eventNumber: [e eventNumber]
8574 clickCount: [e clickCount]
8575 pressure: [e pressure]];
8576 [super mouseUp: fake_event];
8580 pos = 0; /* ignored */
8582 /* set a timer to repeat, as we can't let superclass do this modally */
8584 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8586 selector: @selector (repeatScroll:)
8592 if (part != NSScrollerKnob)
8593 [self sendScrollEventAtLoc: pos fromEvent: e];
8597 /* Called as we manually track scroller drags, rather than superclass. */
8598 - (void)mouseDragged: (NSEvent *)e
8604 NSTRACE ("[EmacsScroller mouseDragged:]");
8606 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8611 length = NSWidth (sr);
8612 loc = ([e locationInWindow].x - NSMinX (sr));
8616 length = NSHeight (sr);
8617 loc = length - ([e locationInWindow].y - NSMinY (sr));
8624 else if (loc >= length + last_mouse_offset)
8626 loc = length + last_mouse_offset;
8629 pos = (loc - last_mouse_offset);
8630 [self sendScrollEventAtLoc: pos fromEvent: e];
8634 - (void)mouseUp: (NSEvent *)e
8636 NSTRACE ("[EmacsScroller mouseUp:]");
8638 if (scroll_repeat_entry)
8640 [scroll_repeat_entry invalidate];
8641 [scroll_repeat_entry release];
8642 scroll_repeat_entry = nil;
8644 last_hit_part = scroll_bar_above_handle;
8648 /* treat scrollwheel events in the bar as though they were in the main window */
8649 - (void) scrollWheel: (NSEvent *)theEvent
8651 NSTRACE ("[EmacsScroller scrollWheel:]");
8653 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8654 [view mouseDown: theEvent];
8657 @end /* EmacsScroller */
8660 #ifdef NS_IMPL_GNUSTEP
8661 /* Dummy class to get rid of startup warnings. */
8662 @implementation EmacsDocument
8668 /* ==========================================================================
8670 Font-related functions; these used to be in nsfaces.m
8672 ========================================================================== */
8676 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8678 struct font *font = XFONT_OBJECT (font_object);
8679 EmacsView *view = FRAME_NS_VIEW (f);
8680 int font_ascent, font_descent;
8683 fontset = fontset_from_font (font_object);
8684 FRAME_FONTSET (f) = fontset;
8686 if (FRAME_FONT (f) == font)
8687 /* This font is already set in frame F. There's nothing more to
8691 FRAME_FONT (f) = font;
8693 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8694 FRAME_COLUMN_WIDTH (f) = font->average_width;
8695 get_font_ascent_descent (font, &font_ascent, &font_descent);
8696 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8698 /* Compute the scroll bar width in character columns. */
8699 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8701 int wid = FRAME_COLUMN_WIDTH (f);
8702 FRAME_CONFIG_SCROLL_BAR_COLS (f)
8703 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8707 int wid = FRAME_COLUMN_WIDTH (f);
8708 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8711 /* Compute the scroll bar height in character lines. */
8712 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8714 int height = FRAME_LINE_HEIGHT (f);
8715 FRAME_CONFIG_SCROLL_BAR_LINES (f)
8716 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8720 int height = FRAME_LINE_HEIGHT (f);
8721 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8724 /* Now make the frame display the given font. */
8725 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8726 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8727 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8734 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8735 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8739 ns_xlfd_to_fontname (const char *xlfd)
8740 /* --------------------------------------------------------------------------
8741 Convert an X font name (XLFD) to an NS font name.
8742 Only family is used.
8743 The string returned is temporarily allocated.
8744 -------------------------------------------------------------------------- */
8746 char *name = xmalloc (180);
8750 if (!strncmp (xlfd, "--", 2))
8751 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8753 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8755 /* stopgap for malformed XLFD input */
8756 if (strlen (name) == 0)
8757 strcpy (name, "Monaco");
8759 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8760 also uppercase after '-' or ' ' */
8761 name[0] = c_toupper (name[0]);
8762 for (len =strlen (name), i =0; i<len; i++)
8768 name[i+1] = c_toupper (name[i+1]);
8770 else if (name[i] == '_')
8774 name[i+1] = c_toupper (name[i+1]);
8777 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
8778 ret = [[NSString stringWithUTF8String: name] UTF8String];
8785 syms_of_nsterm (void)
8787 NSTRACE ("syms_of_nsterm");
8789 ns_antialias_threshold = 10.0;
8791 /* from 23+ we need to tell emacs what modifiers there are.. */
8792 DEFSYM (Qmodifier_value, "modifier-value");
8793 DEFSYM (Qalt, "alt");
8794 DEFSYM (Qhyper, "hyper");
8795 DEFSYM (Qmeta, "meta");
8796 DEFSYM (Qsuper, "super");
8797 DEFSYM (Qcontrol, "control");
8798 DEFSYM (QUTF8_STRING, "UTF8_STRING");
8800 DEFSYM (Qfile, "file");
8801 DEFSYM (Qurl, "url");
8803 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8804 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8805 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8806 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8807 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8809 DEFVAR_LISP ("ns-input-file", ns_input_file,
8810 "The file specified in the last NS event.");
8811 ns_input_file =Qnil;
8813 DEFVAR_LISP ("ns-working-text", ns_working_text,
8814 "String for visualizing working composition sequence.");
8815 ns_working_text =Qnil;
8817 DEFVAR_LISP ("ns-input-font", ns_input_font,
8818 "The font specified in the last NS event.");
8819 ns_input_font =Qnil;
8821 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8822 "The fontsize specified in the last NS event.");
8823 ns_input_fontsize =Qnil;
8825 DEFVAR_LISP ("ns-input-line", ns_input_line,
8826 "The line specified in the last NS event.");
8827 ns_input_line =Qnil;
8829 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
8830 "The service name specified in the last NS event.");
8831 ns_input_spi_name =Qnil;
8833 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
8834 "The service argument specified in the last NS event.");
8835 ns_input_spi_arg =Qnil;
8837 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
8838 "This variable describes the behavior of the alternate or option key.\n\
8839 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8841 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8842 at all, allowing it to be used at a lower level for accented character entry.");
8843 ns_alternate_modifier = Qmeta;
8845 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
8846 "This variable describes the behavior of the right alternate or option key.\n\
8847 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8849 Set to left means be the same key as `ns-alternate-modifier'.\n\
8850 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8851 at all, allowing it to be used at a lower level for accented character entry.");
8852 ns_right_alternate_modifier = Qleft;
8854 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
8855 "This variable describes the behavior of the command key.\n\
8856 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8858 ns_command_modifier = Qsuper;
8860 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
8861 "This variable describes the behavior of the right command key.\n\
8862 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8864 Set to left means be the same key as `ns-command-modifier'.\n\
8865 Set to none means that the command / option key is not interpreted by Emacs\n\
8866 at all, allowing it to be used at a lower level for accented character entry.");
8867 ns_right_command_modifier = Qleft;
8869 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
8870 "This variable describes the behavior of the control key.\n\
8871 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8873 ns_control_modifier = Qcontrol;
8875 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
8876 "This variable describes the behavior of the right control key.\n\
8877 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8879 Set to left means be the same key as `ns-control-modifier'.\n\
8880 Set to none means that the control / option key is not interpreted by Emacs\n\
8881 at all, allowing it to be used at a lower level for accented character entry.");
8882 ns_right_control_modifier = Qleft;
8884 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
8885 "This variable describes the behavior of the function key (on laptops).\n\
8886 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8888 Set to none means that the function key is not interpreted by Emacs at all,\n\
8889 allowing it to be used at a lower level for accented character entry.");
8890 ns_function_modifier = Qnone;
8892 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
8893 "Non-nil (the default) means to render text antialiased.");
8894 ns_antialias_text = Qt;
8896 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
8897 "Whether to confirm application quit using dialog.");
8898 ns_confirm_quit = Qnil;
8900 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
8901 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
8902 Only works on Mac OS X 10.6 or later. */);
8903 ns_auto_hide_menu_bar = Qnil;
8905 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
8906 doc: /*Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
8907 Nil means use fullscreen the old (< 10.7) way. The old way works better with
8908 multiple monitors, but lacks tool bar. This variable is ignored on
8909 Mac OS X < 10.7. Default is t for 10.7 and later, nil otherwise. */);
8910 #ifdef HAVE_NATIVE_FS
8911 ns_use_native_fullscreen = YES;
8913 ns_use_native_fullscreen = NO;
8915 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
8917 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
8918 doc: /*Non-nil means use animation on non-native fullscreen.
8919 For native fullscreen, this does nothing.
8920 Default is nil. */);
8921 ns_use_fullscreen_animation = NO;
8923 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
8924 doc: /*Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
8925 Note that this does not apply to images.
8926 This variable is ignored on Mac OS X < 10.7 and GNUstep. */);
8927 ns_use_srgb_colorspace = YES;
8929 /* TODO: move to common code */
8930 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
8931 doc: /* Which toolkit scroll bars Emacs uses, if any.
8932 A value of nil means Emacs doesn't use toolkit scroll bars.
8933 With the X Window system, the value is a symbol describing the
8934 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
8935 With MS Windows or Nextstep, the value is t. */);
8936 Vx_toolkit_scroll_bars = Qt;
8938 DEFVAR_BOOL ("x-use-underline-position-properties",
8939 x_use_underline_position_properties,
8940 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
8941 A value of nil means ignore them. If you encounter fonts with bogus
8942 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
8943 to 4.1, set this to nil. */);
8944 x_use_underline_position_properties = 0;
8946 DEFVAR_BOOL ("x-underline-at-descent-line",
8947 x_underline_at_descent_line,
8948 doc: /* Non-nil means to draw the underline at the same place as the descent line.
8949 A value of nil means to draw the underline according to the value of the
8950 variable `x-use-underline-position-properties', which is usually at the
8951 baseline level. The default value is nil. */);
8952 x_underline_at_descent_line = 0;
8954 /* Tell Emacs about this window system. */
8955 Fprovide (Qns, Qnil);
8957 DEFSYM (Qcocoa, "cocoa");
8958 DEFSYM (Qgnustep, "gnustep");
8960 #ifdef NS_IMPL_COCOA
8961 Fprovide (Qcocoa, Qnil);
8964 Fprovide (Qgnustep, Qnil);