Fix a typo in describing input methods
[emacs.git] / src / nsterm.m
blobc8ae31abc09a0ac9473d13c84594b01194f3bc0a
1 /* NeXT/Open/GNUstep / macOS communication module.      -*- coding: utf-8 -*-
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2018 Free Software
4 Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or (at
11 your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30    interpretation of even the system includes. */
31 #include <config.h>
33 #include <fcntl.h>
34 #include <math.h>
35 #include <pthread.h>
36 #include <sys/types.h>
37 #include <time.h>
38 #include <signal.h>
39 #include <unistd.h>
41 #include <c-ctype.h>
42 #include <c-strcase.h>
43 #include <ftoastr.h>
45 #include "lisp.h"
46 #include "blockinput.h"
47 #include "sysselect.h"
48 #include "nsterm.h"
49 #include "systime.h"
50 #include "character.h"
51 #include "fontset.h"
52 #include "composite.h"
53 #include "ccl.h"
55 #include "termhooks.h"
56 #include "termchar.h"
57 #include "menu.h"
58 #include "window.h"
59 #include "keyboard.h"
60 #include "buffer.h"
61 #include "font.h"
63 #ifdef NS_IMPL_GNUSTEP
64 #include "process.h"
65 #endif
67 #ifdef NS_IMPL_COCOA
68 #include "macfont.h"
69 #endif
71 static EmacsMenu *dockMenu;
72 #ifdef NS_IMPL_COCOA
73 static EmacsMenu *mainMenu;
74 #endif
76 /* ==========================================================================
78    NSTRACE, Trace support.
80    ========================================================================== */
82 #if NSTRACE_ENABLED
84 /* The following use "volatile" since they can be accessed from
85    parallel threads. */
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)
101     {
102       --nstrace_depth;
103     }
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)
116   switch (fs_type)
117     {
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_?????";
125     }
127 #endif
130 /* ==========================================================================
132    NSColor, EmacsColor category.
134    ========================================================================== */
135 @implementation NSColor (EmacsColor)
136 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
137                          blue:(CGFloat)blue alpha:(CGFloat)alpha
139 #if defined (NS_IMPL_COCOA) \
140   && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
141   if (ns_use_srgb_colorspace
142 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
143       && [NSColor respondsToSelector:
144                     @selector(colorWithSRGBRed:green:blue:alpha:)]
145 #endif
146       )
147     return [NSColor colorWithSRGBRed: red
148                                green: green
149                                 blue: blue
150                                alpha: alpha];
151 #endif
152   return [NSColor colorWithCalibratedRed: red
153                                    green: green
154                                     blue: blue
155                                    alpha: alpha];
158 - (NSColor *)colorUsingDefaultColorSpace
160   /* FIXMES: We're checking for colorWithSRGBRed here so this will
161      only work in the same place as in the method above.  It should
162      really be a check whether we're on macOS 10.7 or above. */
163 #if defined (NS_IMPL_COCOA) \
164   && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
165   if (ns_use_srgb_colorspace
166 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
167       && [NSColor respondsToSelector:
168                     @selector(colorWithSRGBRed:green:blue:alpha:)]
169 #endif
170       )
171     return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
172 #endif
173   return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
176 @end
178 /* ==========================================================================
180     Local declarations
182    ========================================================================== */
184 /* Convert a symbol indexed with an NSxxx value to a value as defined
185    in keyboard.c (lispy_function_key). I hope this is a correct way
186    of doing things... */
187 static unsigned convert_ns_to_X_keysym[] =
189   NSHomeFunctionKey,            0x50,
190   NSLeftArrowFunctionKey,       0x51,
191   NSUpArrowFunctionKey,         0x52,
192   NSRightArrowFunctionKey,      0x53,
193   NSDownArrowFunctionKey,       0x54,
194   NSPageUpFunctionKey,          0x55,
195   NSPageDownFunctionKey,        0x56,
196   NSEndFunctionKey,             0x57,
197   NSBeginFunctionKey,           0x58,
198   NSSelectFunctionKey,          0x60,
199   NSPrintFunctionKey,           0x61,
200   NSClearLineFunctionKey,       0x0B,
201   NSExecuteFunctionKey,         0x62,
202   NSInsertFunctionKey,          0x63,
203   NSUndoFunctionKey,            0x65,
204   NSRedoFunctionKey,            0x66,
205   NSMenuFunctionKey,            0x67,
206   NSFindFunctionKey,            0x68,
207   NSHelpFunctionKey,            0x6A,
208   NSBreakFunctionKey,           0x6B,
210   NSF1FunctionKey,              0xBE,
211   NSF2FunctionKey,              0xBF,
212   NSF3FunctionKey,              0xC0,
213   NSF4FunctionKey,              0xC1,
214   NSF5FunctionKey,              0xC2,
215   NSF6FunctionKey,              0xC3,
216   NSF7FunctionKey,              0xC4,
217   NSF8FunctionKey,              0xC5,
218   NSF9FunctionKey,              0xC6,
219   NSF10FunctionKey,             0xC7,
220   NSF11FunctionKey,             0xC8,
221   NSF12FunctionKey,             0xC9,
222   NSF13FunctionKey,             0xCA,
223   NSF14FunctionKey,             0xCB,
224   NSF15FunctionKey,             0xCC,
225   NSF16FunctionKey,             0xCD,
226   NSF17FunctionKey,             0xCE,
227   NSF18FunctionKey,             0xCF,
228   NSF19FunctionKey,             0xD0,
229   NSF20FunctionKey,             0xD1,
230   NSF21FunctionKey,             0xD2,
231   NSF22FunctionKey,             0xD3,
232   NSF23FunctionKey,             0xD4,
233   NSF24FunctionKey,             0xD5,
235   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
236   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
237   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
239   NSTabCharacter,               0x09,
240   0x19,                         0x09,  /* left tab->regular since pass shift */
241   NSCarriageReturnCharacter,    0x0D,
242   NSNewlineCharacter,           0x0D,
243   NSEnterCharacter,             0x8D,
245   0x41|NSEventModifierFlagNumericPad,   0xAE,  /* KP_Decimal */
246   0x43|NSEventModifierFlagNumericPad,   0xAA,  /* KP_Multiply */
247   0x45|NSEventModifierFlagNumericPad,   0xAB,  /* KP_Add */
248   0x4B|NSEventModifierFlagNumericPad,   0xAF,  /* KP_Divide */
249   0x4E|NSEventModifierFlagNumericPad,   0xAD,  /* KP_Subtract */
250   0x51|NSEventModifierFlagNumericPad,   0xBD,  /* KP_Equal */
251   0x52|NSEventModifierFlagNumericPad,   0xB0,  /* KP_0 */
252   0x53|NSEventModifierFlagNumericPad,   0xB1,  /* KP_1 */
253   0x54|NSEventModifierFlagNumericPad,   0xB2,  /* KP_2 */
254   0x55|NSEventModifierFlagNumericPad,   0xB3,  /* KP_3 */
255   0x56|NSEventModifierFlagNumericPad,   0xB4,  /* KP_4 */
256   0x57|NSEventModifierFlagNumericPad,   0xB5,  /* KP_5 */
257   0x58|NSEventModifierFlagNumericPad,   0xB6,  /* KP_6 */
258   0x59|NSEventModifierFlagNumericPad,   0xB7,  /* KP_7 */
259   0x5B|NSEventModifierFlagNumericPad,   0xB8,  /* KP_8 */
260   0x5C|NSEventModifierFlagNumericPad,   0xB9,  /* KP_9 */
262   0x1B,                         0x1B   /* escape */
265 /* On macOS picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
266    the maximum font size to NOT antialias.  On GNUstep there is currently
267    no way to control this behavior. */
268 float ns_antialias_threshold;
270 NSArray *ns_send_types = 0, *ns_return_types = 0;
271 static NSArray *ns_drag_types = 0;
272 NSString *ns_app_name = @"Emacs";  /* default changed later */
274 /* Display variables */
275 struct ns_display_info *x_display_list; /* Chain of existing displays */
276 long context_menu_value = 0;
278 /* display update */
279 static struct frame *ns_updating_frame;
280 static NSView *focus_view = NULL;
281 static int ns_window_num = 0;
282 #ifdef NS_IMPL_GNUSTEP
283 static NSRect uRect;            // TODO: This is dead, remove it?
284 #endif
285 static BOOL gsaved = NO;
286 static BOOL ns_fake_keydown = NO;
287 #ifdef NS_IMPL_COCOA
288 static BOOL ns_menu_bar_is_hidden = NO;
289 #endif
290 /*static int debug_lock = 0; */
292 /* event loop */
293 static BOOL send_appdefined = YES;
294 #define NO_APPDEFINED_DATA (-8)
295 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
296 static NSTimer *timed_entry = 0;
297 static NSTimer *scroll_repeat_entry = nil;
298 static fd_set select_readfds, select_writefds;
299 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
300 static int select_nfds = 0, select_valid = 0;
301 static struct timespec select_timeout = { 0, 0 };
302 static int selfds[2] = { -1, -1 };
303 static pthread_mutex_t select_mutex;
304 static NSAutoreleasePool *outerpool;
305 static struct input_event *emacs_event = NULL;
306 static struct input_event *q_event_ptr = NULL;
307 static int n_emacs_events_pending = 0;
308 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
309   *ns_pending_service_args;
310 static BOOL ns_do_open_file = NO;
311 static BOOL ns_last_use_native_fullscreen;
313 /* Non-zero means that a HELP_EVENT has been generated since Emacs
314    start.  */
316 static BOOL any_help_event_p = NO;
318 static struct {
319   struct input_event *q;
320   int nr, cap;
321 } hold_event_q = {
322   NULL, 0, 0
325 static NSString *represented_filename = nil;
326 static struct frame *represented_frame = 0;
328 #ifdef NS_IMPL_COCOA
330  * State for pending menu activation:
331  * MENU_NONE     Normal state
332  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
333  *               run lisp to update the menu.
334  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
335  *               will open.
336  */
337 #define MENU_NONE 0
338 #define MENU_PENDING 1
339 #define MENU_OPENING 2
340 static int menu_will_open_state = MENU_NONE;
342 /* Saved position for menu click.  */
343 static CGPoint menu_mouse_point;
344 #endif
346 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
347 #define NS_FUNCTION_KEY_MASK 0x800000
348 #define NSLeftControlKeyMask    (0x000001 | NSEventModifierFlagControl)
349 #define NSRightControlKeyMask   (0x002000 | NSEventModifierFlagControl)
350 #define NSLeftCommandKeyMask    (0x000008 | NSEventModifierFlagCommand)
351 #define NSRightCommandKeyMask   (0x000010 | NSEventModifierFlagCommand)
352 #define NSLeftAlternateKeyMask  (0x000020 | NSEventModifierFlagOption)
353 #define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption)
354 #define EV_MODIFIERS2(flags)                          \
355     (((flags & NSEventModifierFlagHelp) ?           \
356            hyper_modifier : 0)                        \
357      | (!EQ (ns_right_alternate_modifier, Qleft) && \
358         ((flags & NSRightAlternateKeyMask) \
359          == NSRightAlternateKeyMask) ? \
360            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
361      | ((flags & NSEventModifierFlagOption) ?                 \
362            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
363      | ((flags & NSEventModifierFlagShift) ?     \
364            shift_modifier : 0)                        \
365      | (!EQ (ns_right_control_modifier, Qleft) && \
366         ((flags & NSRightControlKeyMask) \
367          == NSRightControlKeyMask) ? \
368            parse_solitary_modifier (ns_right_control_modifier) : 0) \
369      | ((flags & NSEventModifierFlagControl) ?      \
370            parse_solitary_modifier (ns_control_modifier) : 0)     \
371      | ((flags & NS_FUNCTION_KEY_MASK) ?  \
372            parse_solitary_modifier (ns_function_modifier) : 0)    \
373      | (!EQ (ns_right_command_modifier, Qleft) && \
374         ((flags & NSRightCommandKeyMask) \
375          == NSRightCommandKeyMask) ? \
376            parse_solitary_modifier (ns_right_command_modifier) : 0) \
377      | ((flags & NSEventModifierFlagCommand) ?      \
378            parse_solitary_modifier (ns_command_modifier):0))
379 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
381 #define EV_UDMODIFIERS(e)                                      \
382     ((([e type] == NSEventTypeLeftMouseDown) ? down_modifier : 0)       \
383      | (([e type] == NSEventTypeRightMouseDown) ? down_modifier : 0)    \
384      | (([e type] == NSEventTypeOtherMouseDown) ? down_modifier : 0)    \
385      | (([e type] == NSEventTypeLeftMouseDragged) ? down_modifier : 0)  \
386      | (([e type] == NSEventTypeRightMouseDragged) ? down_modifier : 0) \
387      | (([e type] == NSEventTypeOtherMouseDragged) ? down_modifier : 0) \
388      | (([e type] == NSEventTypeLeftMouseUp)   ? up_modifier   : 0)     \
389      | (([e type] == NSEventTypeRightMouseUp)   ? up_modifier   : 0)    \
390      | (([e type] == NSEventTypeOtherMouseUp)   ? up_modifier   : 0))
392 #define EV_BUTTON(e)                                                         \
393     ((([e type] == NSEventTypeLeftMouseDown) || ([e type] == NSEventTypeLeftMouseUp)) ? 0 :    \
394       (([e type] == NSEventTypeRightMouseDown) || ([e type] == NSEventTypeRightMouseUp)) ? 2 : \
395      [e buttonNumber] - 1)
397 /* Convert the time field to a timestamp in milliseconds. */
398 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
400 /* This is a piece of code which is common to all the event handling
401    methods.  Maybe it should even be a function.  */
402 #define EV_TRAILER(e)                                                   \
403   {                                                                     \
404     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
405     EV_TRAILER2 (e);                                                    \
406   }
408 #define EV_TRAILER2(e)                                                  \
409   {                                                                     \
410       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
411       if (q_event_ptr)                                                  \
412         {                                                               \
413           Lisp_Object tem = Vinhibit_quit;                              \
414           Vinhibit_quit = Qt;                                           \
415           n_emacs_events_pending++;                                     \
416           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
417           Vinhibit_quit = tem;                                          \
418         }                                                               \
419       else                                                              \
420         hold_event (emacs_event);                                       \
421       EVENT_INIT (*emacs_event);                                        \
422       ns_send_appdefined (-1);                                          \
423     }
426 /* These flags will be OR'd or XOR'd with the NSWindow's styleMask
427    property depending on what we're doing. */
428 #define FRAME_DECORATED_FLAGS (NSWindowStyleMaskTitled              \
429                                | NSWindowStyleMaskResizable         \
430                                | NSWindowStyleMaskMiniaturizable    \
431                                | NSWindowStyleMaskClosable)
432 #define FRAME_UNDECORATED_FLAGS NSWindowStyleMaskBorderless
434 /* TODO: get rid of need for these forward declarations */
435 static void ns_condemn_scroll_bars (struct frame *f);
436 static void ns_judge_scroll_bars (struct frame *f);
439 /* ==========================================================================
441     Utilities
443    ========================================================================== */
445 void
446 ns_set_represented_filename (NSString *fstr, struct frame *f)
448   represented_filename = [fstr retain];
449   represented_frame = f;
452 void
453 ns_init_events (struct input_event *ev)
455   EVENT_INIT (*ev);
456   emacs_event = ev;
459 void
460 ns_finish_events (void)
462   emacs_event = NULL;
465 static void
466 hold_event (struct input_event *event)
468   if (hold_event_q.nr == hold_event_q.cap)
469     {
470       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
471       else hold_event_q.cap *= 2;
472       hold_event_q.q =
473         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
474     }
476   hold_event_q.q[hold_event_q.nr++] = *event;
477   /* Make sure ns_read_socket is called, i.e. we have input.  */
478   raise (SIGIO);
479   send_appdefined = YES;
482 static Lisp_Object
483 append2 (Lisp_Object list, Lisp_Object item)
484 /* --------------------------------------------------------------------------
485    Utility to append to a list
486    -------------------------------------------------------------------------- */
488   return CALLN (Fnconc, list, list1 (item));
492 const char *
493 ns_etc_directory (void)
494 /* If running as a self-contained app bundle, return as a string the
495    filename of the etc directory, if present; else nil.  */
497   NSBundle *bundle = [NSBundle mainBundle];
498   NSString *resourceDir = [bundle resourcePath];
499   NSString *resourcePath;
500   NSFileManager *fileManager = [NSFileManager defaultManager];
501   BOOL isDir;
503   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
504   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
505     {
506       if (isDir) return [resourcePath UTF8String];
507     }
508   return NULL;
512 const char *
513 ns_exec_path (void)
514 /* If running as a self-contained app bundle, return as a path string
515    the filenames of the libexec and bin directories, ie libexec:bin.
516    Otherwise, return nil.
517    Normally, Emacs does not add its own bin/ directory to the PATH.
518    However, a self-contained NS build has a different layout, with
519    bin/ and libexec/ subdirectories in the directory that contains
520    Emacs.app itself.
521    We put libexec first, because init_callproc_1 uses the first
522    element to initialize exec-directory.  An alternative would be
523    for init_callproc to check for invocation-directory/libexec.
526   NSBundle *bundle = [NSBundle mainBundle];
527   NSString *resourceDir = [bundle resourcePath];
528   NSString *binDir = [bundle bundlePath];
529   NSString *resourcePath, *resourcePaths;
530   NSRange range;
531   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
532   NSFileManager *fileManager = [NSFileManager defaultManager];
533   NSArray *paths;
534   NSEnumerator *pathEnum;
535   BOOL isDir;
537   range = [resourceDir rangeOfString: @"Contents"];
538   if (range.location != NSNotFound)
539     {
540       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
541 #ifdef NS_IMPL_COCOA
542       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
543 #endif
544     }
546   paths = [binDir stringsByAppendingPaths:
547                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
548   pathEnum = [paths objectEnumerator];
549   resourcePaths = @"";
551   while ((resourcePath = [pathEnum nextObject]))
552     {
553       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
554         if (isDir)
555           {
556             if ([resourcePaths length] > 0)
557               resourcePaths
558                 = [resourcePaths stringByAppendingString: pathSeparator];
559             resourcePaths
560               = [resourcePaths stringByAppendingString: resourcePath];
561           }
562     }
563   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
565   return NULL;
569 const char *
570 ns_load_path (void)
571 /* If running as a self-contained app bundle, return as a path string
572    the filenames of the site-lisp and lisp directories.
573    Ie, site-lisp:lisp.  Otherwise, return nil.  */
575   NSBundle *bundle = [NSBundle mainBundle];
576   NSString *resourceDir = [bundle resourcePath];
577   NSString *resourcePath, *resourcePaths;
578   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
579   NSFileManager *fileManager = [NSFileManager defaultManager];
580   BOOL isDir;
581   NSArray *paths = [resourceDir stringsByAppendingPaths:
582                               [NSArray arrayWithObjects:
583                                          @"site-lisp", @"lisp", nil]];
584   NSEnumerator *pathEnum = [paths objectEnumerator];
585   resourcePaths = @"";
587   /* Hack to skip site-lisp.  */
588   if (no_site_lisp) resourcePath = [pathEnum nextObject];
590   while ((resourcePath = [pathEnum nextObject]))
591     {
592       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
593         if (isDir)
594           {
595             if ([resourcePaths length] > 0)
596               resourcePaths
597                 = [resourcePaths stringByAppendingString: pathSeparator];
598             resourcePaths
599               = [resourcePaths stringByAppendingString: resourcePath];
600           }
601     }
602   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
604   return NULL;
608 void
609 ns_init_locale (void)
610 /* macOS doesn't set any environment variables for the locale when run
611    from the GUI. Get the locale from the OS and set LANG. */
613   NSLocale *locale = [NSLocale currentLocale];
615   NSTRACE ("ns_init_locale");
617   @try
618     {
619       /* It seems macOS should probably use UTF-8 everywhere.
620          'localeIdentifier' does not specify the encoding, and I can't
621          find any way to get the OS to tell us which encoding to use,
622          so hard-code '.UTF-8'. */
623       NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
624                                      [locale localeIdentifier]];
626       /* Set LANG to locale, but not if LANG is already set. */
627       setenv("LANG", [localeID UTF8String], 0);
628     }
629   @catch (NSException *e)
630     {
631       NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
632     }
636 void
637 ns_release_object (void *obj)
638 /* --------------------------------------------------------------------------
639     Release an object (callable from C)
640    -------------------------------------------------------------------------- */
642     [(id)obj release];
646 void
647 ns_retain_object (void *obj)
648 /* --------------------------------------------------------------------------
649     Retain an object (callable from C)
650    -------------------------------------------------------------------------- */
652     [(id)obj retain];
656 void *
657 ns_alloc_autorelease_pool (void)
658 /* --------------------------------------------------------------------------
659      Allocate a pool for temporary objects (callable from C)
660    -------------------------------------------------------------------------- */
662   return [[NSAutoreleasePool alloc] init];
666 void
667 ns_release_autorelease_pool (void *pool)
668 /* --------------------------------------------------------------------------
669      Free a pool and temporary objects it refers to (callable from C)
670    -------------------------------------------------------------------------- */
672   ns_release_object (pool);
676 static BOOL
677 ns_menu_bar_should_be_hidden (void)
678 /* True, if the menu bar should be hidden.  */
680   return !NILP (ns_auto_hide_menu_bar)
681     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
685 struct EmacsMargins
687   CGFloat top;
688   CGFloat bottom;
689   CGFloat left;
690   CGFloat right;
694 static struct EmacsMargins
695 ns_screen_margins (NSScreen *screen)
696 /* The parts of SCREEN used by the operating system.  */
698   NSTRACE ("ns_screen_margins");
700   struct EmacsMargins margins;
702   NSRect screenFrame = [screen frame];
703   NSRect screenVisibleFrame = [screen visibleFrame];
705   /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
706      menu bar, check this explicitly.  */
707   if (ns_menu_bar_should_be_hidden())
708     {
709       margins.top = 0;
710     }
711   else
712     {
713       CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
714       CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
715                                  + screenVisibleFrame.size.height);
717       margins.top = frameTop - visibleFrameTop;
718     }
720   {
721     CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
722     CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
723                                  + screenVisibleFrame.size.width);
724     margins.right = frameRight - visibleFrameRight;
725   }
727   margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
728   margins.left   = screenVisibleFrame.origin.x - screenFrame.origin.x;
730   NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
731                margins.left,
732                margins.right,
733                margins.top,
734                margins.bottom);
736   return margins;
740 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
741    assumed to contain a hidden dock.  macOS currently use 4 pixels for
742    this, however, to be future compatible, a larger value is used.  */
743 #define DOCK_IGNORE_LIMIT 6
745 static struct EmacsMargins
746 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
747 /* The parts of SCREEN used by the operating system, excluding the parts
748 reserved for an hidden dock.  */
750   NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
752   struct EmacsMargins margins = ns_screen_margins(screen);
754   /* macOS (currently) reserved 4 pixels along the edge where a hidden
755      dock is located.  Unfortunately, it's not possible to find the
756      location and information about if the dock is hidden.  Instead,
757      it is assumed that if the margin of an edge is less than
758      DOCK_IGNORE_LIMIT, it contains a hidden dock.  */
759   if (margins.left <= DOCK_IGNORE_LIMIT)
760     {
761       margins.left = 0;
762     }
763   if (margins.right <= DOCK_IGNORE_LIMIT)
764     {
765       margins.right = 0;
766     }
767   if (margins.top <= DOCK_IGNORE_LIMIT)
768     {
769       margins.top = 0;
770     }
771   /* Note: This doesn't occur in current versions of macOS, but
772      included for completeness and future compatibility.  */
773   if (margins.bottom <= DOCK_IGNORE_LIMIT)
774     {
775       margins.bottom = 0;
776     }
778   NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
779                margins.left,
780                margins.right,
781                margins.top,
782                margins.bottom);
784   return margins;
788 static CGFloat
789 ns_menu_bar_height (NSScreen *screen)
790 /* The height of the menu bar, if visible.
792    Note: Don't use this when fullscreen is enabled -- the screen
793    sometimes includes, sometimes excludes the menu bar area.  */
795   struct EmacsMargins margins = ns_screen_margins(screen);
797   CGFloat res = margins.top;
799   NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
801   return res;
805 /* ==========================================================================
807     Focus (clipping) and screen update
809    ========================================================================== */
812 // Window constraining
813 // -------------------
815 // To ensure that the windows are not placed under the menu bar, they
816 // are typically moved by the call-back constrainFrameRect. However,
817 // by overriding it, it's possible to inhibit this, leaving the window
818 // in it's original position.
820 // It's possible to hide the menu bar. However, technically, it's only
821 // possible to hide it when the application is active. To ensure that
822 // this work properly, the menu bar and window constraining are
823 // deferred until the application becomes active.
825 // Even though it's not possible to manually move a window above the
826 // top of the screen, it is allowed if it's done programmatically,
827 // when the menu is hidden. This allows the editable area to cover the
828 // full screen height.
830 // Test cases
831 // ----------
833 // Use the following extra files:
835 //    init.el:
836 //       ;; Hide menu and place frame slightly above the top of the screen.
837 //       (setq ns-auto-hide-menu-bar t)
838 //       (set-frame-position (selected-frame) 0 -20)
840 // Test 1:
842 //    emacs -Q -l init.el
844 //    Result: No menu bar, and the title bar should be above the screen.
846 // Test 2:
848 //    emacs -Q
850 //    Result: Menu bar visible, frame placed immediately below the menu.
853 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
855   NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
856              NSTRACE_ARG_RECT (frameRect));
858   // --------------------
859   // Collect information about the screen the frame is covering.
860   //
862   NSArray *screens = [NSScreen screens];
863   NSUInteger nr_screens = [screens count];
865   int i;
867   // The height of the menu bar, if present in any screen the frame is
868   // displayed in.
869   int menu_bar_height = 0;
871   // A rectangle covering all the screen the frame is displayed in.
872   NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
873   for (i = 0; i < nr_screens; ++i )
874     {
875       NSScreen *s = [screens objectAtIndex: i];
876       NSRect scrRect = [s frame];
878       NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
879                    i, NSTRACE_ARG_RECT (scrRect));
881       if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
882         {
883           multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
885           if (!isFullscreen)
886             {
887               CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
888               menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
889             }
890         }
891     }
893   NSTRACE_RECT ("multiscreenRect", multiscreenRect);
895   NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
897   if (multiscreenRect.size.width == 0
898       || multiscreenRect.size.height == 0)
899     {
900       // Failed to find any monitor, give up.
901       NSTRACE_MSG ("multiscreenRect empty");
902       NSTRACE_RETURN_RECT (frameRect);
903       return frameRect;
904     }
907   // --------------------
908   // Find a suitable placement.
909   //
911   if (ns_menu_bar_should_be_hidden())
912     {
913       // When the menu bar is hidden, the user may place part of the
914       // frame above the top of the screen, for example to hide the
915       // title bar.
916       //
917       // Hence, keep the original position.
918     }
919   else
920     {
921       // Ensure that the frame is below the menu bar, or below the top
922       // of the screen.
923       //
924       // This assume that the menu bar is placed at the top in the
925       // rectangle that covers the monitors.  (It doesn't have to be,
926       // but if it's not it's hard to do anything useful.)
927       CGFloat topOfWorkArea = (multiscreenRect.origin.y
928                                + multiscreenRect.size.height
929                                - menu_bar_height);
931       CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
932       if (topOfFrame > topOfWorkArea)
933         {
934           frameRect.origin.y -= topOfFrame - topOfWorkArea;
935           NSTRACE_RECT ("After placement adjust", frameRect);
936         }
937     }
939   // Include the following section to restrict frame to the screens.
940   // (If so, update it to allow the frame to stretch down below the
941   // screen.)
942 #if 0
943   // --------------------
944   // Ensure frame doesn't stretch below the screens.
945   //
947   CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
949   if (diff > 0)
950     {
951       frameRect.origin.y = multiscreenRect.origin.y;
952       frameRect.size.height -= diff;
953     }
954 #endif
956   NSTRACE_RETURN_RECT (frameRect);
957   return frameRect;
961 static void
962 ns_constrain_all_frames (void)
963 /* --------------------------------------------------------------------------
964      Ensure that the menu bar doesn't cover any frames.
965    -------------------------------------------------------------------------- */
967   Lisp_Object tail, frame;
969   NSTRACE ("ns_constrain_all_frames");
971   block_input ();
973   FOR_EACH_FRAME (tail, frame)
974     {
975       struct frame *f = XFRAME (frame);
976       if (FRAME_NS_P (f))
977         {
978           EmacsView *view = FRAME_NS_VIEW (f);
980           if (![view isFullscreen])
981             {
982               [[view window]
983                 setFrame:constrain_frame_rect([[view window] frame], false)
984                  display:NO];
985             }
986         }
987     }
989   unblock_input ();
993 static void
994 ns_update_auto_hide_menu_bar (void)
995 /* --------------------------------------------------------------------------
996      Show or hide the menu bar, based on user setting.
997    -------------------------------------------------------------------------- */
999 #ifdef NS_IMPL_COCOA
1000   NSTRACE ("ns_update_auto_hide_menu_bar");
1002   block_input ();
1004   if (NSApp != nil && [NSApp isActive])
1005     {
1006       // Note, "setPresentationOptions" triggers an error unless the
1007       // application is active.
1008       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
1010       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
1011         {
1012           NSApplicationPresentationOptions options
1013             = NSApplicationPresentationDefault;
1015           if (menu_bar_should_be_hidden)
1016             options |= NSApplicationPresentationAutoHideMenuBar
1017               | NSApplicationPresentationAutoHideDock;
1019           [NSApp setPresentationOptions: options];
1021           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
1023           if (!ns_menu_bar_is_hidden)
1024             {
1025               ns_constrain_all_frames ();
1026             }
1027         }
1028     }
1030   unblock_input ();
1031 #endif
1035 static void
1036 ns_update_begin (struct frame *f)
1037 /* --------------------------------------------------------------------------
1038    Prepare for a grouped sequence of drawing calls
1039    external (RIF) call; whole frame, called before update_window_begin
1040    -------------------------------------------------------------------------- */
1042   EmacsView *view = FRAME_NS_VIEW (f);
1043   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1045   ns_update_auto_hide_menu_bar ();
1047 #ifdef NS_IMPL_COCOA
1048   if ([view isFullscreen] && [view fsIsNative])
1049   {
1050     // Fix reappearing tool bar in fullscreen for Mac OS X 10.7
1051     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1052     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1053     if (! tbar_visible != ! [toolbar isVisible])
1054       [toolbar setVisible: tbar_visible];
1055   }
1056 #endif
1058   ns_updating_frame = f;
1059   [view lockFocus];
1061   /* drawRect may have been called for say the minibuffer, and then clip path
1062      is for the minibuffer.  But the display engine may draw more because
1063      we have set the frame as garbaged.  So reset clip path to the whole
1064      view.  */
1065 #ifdef NS_IMPL_COCOA
1066   {
1067     NSBezierPath *bp;
1068     NSRect r = [view frame];
1069     NSRect cr = [[view window] frame];
1070     /* If a large frame size is set, r may be larger than the window frame
1071        before constrained.  In that case don't change the clip path, as we
1072        will clear in to the tool bar and title bar.  */
1073     if (r.size.height
1074         + FRAME_NS_TITLEBAR_HEIGHT (f)
1075         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1076       {
1077         bp = [[NSBezierPath bezierPathWithRect: r] retain];
1078         [bp setClip];
1079         [bp release];
1080       }
1081   }
1082 #endif
1084 #ifdef NS_IMPL_GNUSTEP
1085   uRect = NSMakeRect (0, 0, 0, 0);
1086 #endif
1090 static void
1091 ns_update_window_begin (struct window *w)
1092 /* --------------------------------------------------------------------------
1093    Prepare for a grouped sequence of drawing calls
1094    external (RIF) call; for one window, called after update_begin
1095    -------------------------------------------------------------------------- */
1097   struct frame *f = XFRAME (WINDOW_FRAME (w));
1098   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1100   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1101   w->output_cursor = w->cursor;
1103   block_input ();
1105   if (f == hlinfo->mouse_face_mouse_frame)
1106     {
1107       /* Don't do highlighting for mouse motion during the update.  */
1108       hlinfo->mouse_face_defer = 1;
1110         /* If the frame needs to be redrawn,
1111            simply forget about any prior mouse highlighting.  */
1112       if (FRAME_GARBAGED_P (f))
1113         hlinfo->mouse_face_window = Qnil;
1115       /* (further code for mouse faces ifdef'd out in other terms elided) */
1116     }
1118   unblock_input ();
1122 static void
1123 ns_update_window_end (struct window *w, bool cursor_on_p,
1124                       bool mouse_face_overwritten_p)
1125 /* --------------------------------------------------------------------------
1126    Finished a grouped sequence of drawing calls
1127    external (RIF) call; for one window called before update_end
1128    -------------------------------------------------------------------------- */
1130   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1132   /* note: this fn is nearly identical in all terms */
1133   if (!w->pseudo_window_p)
1134     {
1135       block_input ();
1137       if (cursor_on_p)
1138         display_and_set_cursor (w, 1,
1139                                 w->output_cursor.hpos, w->output_cursor.vpos,
1140                                 w->output_cursor.x, w->output_cursor.y);
1142       if (draw_window_fringes (w, 1))
1143         {
1144           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1145             x_draw_right_divider (w);
1146           else
1147             x_draw_vertical_border (w);
1148         }
1150       unblock_input ();
1151     }
1153   /* If a row with mouse-face was overwritten, arrange for
1154      frame_up_to_date to redisplay the mouse highlight.  */
1155   if (mouse_face_overwritten_p)
1156     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1160 static void
1161 ns_update_end (struct frame *f)
1162 /* --------------------------------------------------------------------------
1163    Finished a grouped sequence of drawing calls
1164    external (RIF) call; for whole frame, called after update_window_end
1165    -------------------------------------------------------------------------- */
1167   EmacsView *view = FRAME_NS_VIEW (f);
1169   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1171 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1172   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1174   block_input ();
1176   [view unlockFocus];
1177   [[view window] flushWindow];
1179   unblock_input ();
1180   ns_updating_frame = NULL;
1183 static void
1184 ns_focus (struct frame *f, NSRect *r, int n)
1185 /* --------------------------------------------------------------------------
1186    Internal: Focus on given frame.  During small local updates this is used to
1187      draw, however during large updates, ns_update_begin and ns_update_end are
1188      called to wrap the whole thing, in which case these calls are stubbed out.
1189      Except, on GNUstep, we accumulate the rectangle being drawn into, because
1190      the back end won't do this automatically, and will just end up flushing
1191      the entire window.
1192    -------------------------------------------------------------------------- */
1194   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1195   if (r != NULL)
1196     {
1197       NSTRACE_RECT ("r", *r);
1198     }
1200   if (f != ns_updating_frame)
1201     {
1202       NSView *view = FRAME_NS_VIEW (f);
1203       if (view != focus_view)
1204         {
1205           if (focus_view != NULL)
1206             {
1207               [focus_view unlockFocus];
1208               [[focus_view window] flushWindow];
1209 /*debug_lock--; */
1210             }
1212           if (view)
1213             [view lockFocus];
1214           focus_view = view;
1215 /*if (view) debug_lock++; */
1216         }
1217     }
1219   /* clipping */
1220   if (r)
1221     {
1222       [[NSGraphicsContext currentContext] saveGraphicsState];
1223       if (n == 2)
1224         NSRectClipList (r, 2);
1225       else
1226         NSRectClip (*r);
1227       gsaved = YES;
1228     }
1232 static void
1233 ns_unfocus (struct frame *f)
1234 /* --------------------------------------------------------------------------
1235      Internal: Remove focus on given frame
1236    -------------------------------------------------------------------------- */
1238   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1240   if (gsaved)
1241     {
1242       [[NSGraphicsContext currentContext] restoreGraphicsState];
1243       gsaved = NO;
1244     }
1246   if (f != ns_updating_frame)
1247     {
1248       if (focus_view != NULL)
1249         {
1250           [focus_view unlockFocus];
1251           [[focus_view window] flushWindow];
1252           focus_view = NULL;
1253 /*debug_lock--; */
1254         }
1255     }
1259 static void
1260 ns_clip_to_row (struct window *w, struct glyph_row *row,
1261                 enum glyph_row_area area, BOOL gc)
1262 /* --------------------------------------------------------------------------
1263      Internal (but parallels other terms): Focus drawing on given row
1264    -------------------------------------------------------------------------- */
1266   struct frame *f = XFRAME (WINDOW_FRAME (w));
1267   NSRect clip_rect;
1268   int window_x, window_y, window_width;
1270   window_box (w, area, &window_x, &window_y, &window_width, 0);
1272   clip_rect.origin.x = window_x;
1273   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1274   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1275   clip_rect.size.width = window_width;
1276   clip_rect.size.height = row->visible_height;
1278   ns_focus (f, &clip_rect, 1);
1282 /* ==========================================================================
1284     Visible bell and beep.
1286    ========================================================================== */
1289 // This bell implementation shows the visual bell image asynchronously
1290 // from the rest of Emacs. This is done by adding a NSView to the
1291 // superview of the Emacs window and removing it using a timer.
1293 // Unfortunately, some Emacs operations, like scrolling, is done using
1294 // low-level primitives that copy the content of the window, including
1295 // the bell image. To some extent, this is handled by removing the
1296 // image prior to scrolling and marking that the window is in need for
1297 // redisplay.
1299 // To test this code, make sure that there is no artifacts of the bell
1300 // image in the following situations. Use a non-empty buffer (like the
1301 // tutorial) to ensure that a scroll is performed:
1303 // * Single-window: C-g C-v
1305 // * Side-by-windows: C-x 3 C-g C-v
1307 // * Windows above each other: C-x 2 C-g C-v
1309 @interface EmacsBell : NSImageView
1311   // Number of currently active bell:s.
1312   unsigned int nestCount;
1313   NSView * mView;
1314   bool isAttached;
1316 - (void)show:(NSView *)view;
1317 - (void)hide;
1318 - (void)remove;
1319 @end
1321 @implementation EmacsBell
1323 - (id)init
1325   NSTRACE ("[EmacsBell init]");
1326   if ((self = [super init]))
1327     {
1328       nestCount = 0;
1329       isAttached = false;
1330 #ifdef NS_IMPL_GNUSTEP
1331       // GNUstep doesn't provide named images.  This was reported in
1332       // 2011, see https://savannah.gnu.org/bugs/?33396
1333       //
1334       // As a drop in replacement, a semitransparent gray square is used.
1335       self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1336       [self.image lockFocus];
1337       [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1338       NSRectFill(NSMakeRect(0, 0, 32, 32));
1339       [self.image unlockFocus];
1340 #else
1341       self.image = [NSImage imageNamed:NSImageNameCaution];
1342       [self.image setSize:NSMakeSize(self.image.size.width * 5,
1343                                      self.image.size.height * 5)];
1344 #endif
1345     }
1346   return self;
1349 - (void)show:(NSView *)view
1351   NSTRACE ("[EmacsBell show:]");
1352   NSTRACE_MSG ("nestCount: %u", nestCount);
1354   // Show the image, unless it's already shown.
1355   if (nestCount == 0)
1356     {
1357       NSRect rect = [view bounds];
1358       NSPoint pos;
1359       pos.x = rect.origin.x + (rect.size.width  - self.image.size.width )/2;
1360       pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1362       [self setFrameOrigin:pos];
1363       [self setFrameSize:self.image.size];
1365       isAttached = true;
1366       mView = view;
1367       [[[view window] contentView] addSubview:self
1368                                    positioned:NSWindowAbove
1369                                    relativeTo:nil];
1370     }
1372   ++nestCount;
1374   [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1378 - (void)hide
1380   // Note: Trace output from this method isn't shown, reason unknown.
1381   // NSTRACE ("[EmacsBell hide]");
1383   if (nestCount > 0)
1384     --nestCount;
1386   // Remove the image once the last bell became inactive.
1387   if (nestCount == 0)
1388     {
1389       [self remove];
1390     }
1394 -(void)remove
1396   NSTRACE ("[EmacsBell remove]");
1397   if (isAttached)
1398     {
1399       NSTRACE_MSG ("removeFromSuperview");
1400       [self removeFromSuperview];
1401       mView.needsDisplay = YES;
1402       isAttached = false;
1403     }
1406 @end
1409 static EmacsBell * bell_view = nil;
1411 static void
1412 ns_ring_bell (struct frame *f)
1413 /* --------------------------------------------------------------------------
1414      "Beep" routine
1415    -------------------------------------------------------------------------- */
1417   NSTRACE ("ns_ring_bell");
1418   if (visible_bell)
1419     {
1420       struct frame *frame = SELECTED_FRAME ();
1421       NSView *view;
1423       if (bell_view == nil)
1424         {
1425           bell_view = [[EmacsBell alloc] init];
1426           [bell_view retain];
1427         }
1429       block_input ();
1431       view = FRAME_NS_VIEW (frame);
1432       if (view != nil)
1433         {
1434           [bell_view show:view];
1435         }
1437       unblock_input ();
1438     }
1439   else
1440     {
1441       NSBeep ();
1442     }
1446 static void
1447 hide_bell (void)
1448 /* --------------------------------------------------------------------------
1449      Ensure the bell is hidden.
1450    -------------------------------------------------------------------------- */
1452   NSTRACE ("hide_bell");
1454   if (bell_view != nil)
1455     {
1456       [bell_view remove];
1457     }
1461 /* ==========================================================================
1463     Frame / window manager related functions
1465    ========================================================================== */
1468 static void
1469 ns_raise_frame (struct frame *f, BOOL make_key)
1470 /* --------------------------------------------------------------------------
1471      Bring window to foreground and if make_key is YES, give it focus.
1472    -------------------------------------------------------------------------- */
1474   NSView *view;
1476   check_window_system (f);
1477   view = FRAME_NS_VIEW (f);
1478   block_input ();
1479   if (FRAME_VISIBLE_P (f))
1480     {
1481       if (make_key)
1482         [[view window] makeKeyAndOrderFront: NSApp];
1483       else
1484         [[view window] orderFront: NSApp];
1485     }
1486   unblock_input ();
1490 static void
1491 ns_lower_frame (struct frame *f)
1492 /* --------------------------------------------------------------------------
1493      Send window to back
1494    -------------------------------------------------------------------------- */
1496   NSView *view;
1498   check_window_system (f);
1499   view = FRAME_NS_VIEW (f);
1500   block_input ();
1501   [[view window] orderBack: NSApp];
1502   unblock_input ();
1506 static void
1507 ns_frame_raise_lower (struct frame *f, bool raise)
1508 /* --------------------------------------------------------------------------
1509      External (hook)
1510    -------------------------------------------------------------------------- */
1512   NSTRACE ("ns_frame_raise_lower");
1514   if (raise)
1515     ns_raise_frame (f, YES);
1516   else
1517     ns_lower_frame (f);
1521 static void
1522 ns_frame_rehighlight (struct frame *frame)
1523 /* --------------------------------------------------------------------------
1524      External (hook): called on things like window switching within frame
1525    -------------------------------------------------------------------------- */
1527   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1528   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1530   NSTRACE ("ns_frame_rehighlight");
1531   if (dpyinfo->x_focus_frame)
1532     {
1533       dpyinfo->x_highlight_frame
1534         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1535            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1536            : dpyinfo->x_focus_frame);
1537       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1538         {
1539           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1540           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1541         }
1542     }
1543   else
1544       dpyinfo->x_highlight_frame = 0;
1546   if (dpyinfo->x_highlight_frame &&
1547          dpyinfo->x_highlight_frame != old_highlight)
1548     {
1549       if (old_highlight)
1550         {
1551           x_update_cursor (old_highlight, 1);
1552           x_set_frame_alpha (old_highlight);
1553         }
1554       if (dpyinfo->x_highlight_frame)
1555         {
1556           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1557           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1558         }
1559     }
1563 void
1564 x_make_frame_visible (struct frame *f)
1565 /* --------------------------------------------------------------------------
1566      External: Show the window (X11 semantics)
1567    -------------------------------------------------------------------------- */
1569   NSTRACE ("x_make_frame_visible");
1570   /* XXX: at some points in past this was not needed, as the only place that
1571      called this (frame.c:Fraise_frame ()) also called raise_lower;
1572      if this ends up the case again, comment this out again. */
1573   if (!FRAME_VISIBLE_P (f))
1574     {
1575       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1576       NSWindow *window = [view window];
1578       SET_FRAME_VISIBLE (f, 1);
1579       ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f));
1581       /* Making a new frame from a fullscreen frame will make the new frame
1582          fullscreen also.  So skip handleFS as this will print an error.  */
1583       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1584           && [view isFullscreen])
1585         return;
1587       if (f->want_fullscreen != FULLSCREEN_NONE)
1588         {
1589           block_input ();
1590           [view handleFS];
1591           unblock_input ();
1592         }
1594       /* Making a frame invisible seems to break the parent->child
1595          relationship, so reinstate it. */
1596       if ([window parentWindow] == nil && FRAME_PARENT_FRAME (f) != NULL)
1597         {
1598           NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1600           block_input ();
1601           [parent addChildWindow: window
1602                          ordered: NSWindowAbove];
1603           unblock_input ();
1605           /* If the parent frame moved while the child frame was
1606              invisible, the child frame's position won't have been
1607              updated.  Make sure it's in the right place now. */
1608           x_set_offset(f, f->left_pos, f->top_pos, 0);
1609         }
1610     }
1614 void
1615 x_make_frame_invisible (struct frame *f)
1616 /* --------------------------------------------------------------------------
1617      External: Hide the window (X11 semantics)
1618    -------------------------------------------------------------------------- */
1620   NSView *view;
1621   NSTRACE ("x_make_frame_invisible");
1622   check_window_system (f);
1623   view = FRAME_NS_VIEW (f);
1624   [[view window] orderOut: NSApp];
1625   SET_FRAME_VISIBLE (f, 0);
1626   SET_FRAME_ICONIFIED (f, 0);
1630 void
1631 x_iconify_frame (struct frame *f)
1632 /* --------------------------------------------------------------------------
1633      External: Iconify window
1634    -------------------------------------------------------------------------- */
1636   NSView *view;
1637   struct ns_display_info *dpyinfo;
1639   NSTRACE ("x_iconify_frame");
1640   check_window_system (f);
1641   view = FRAME_NS_VIEW (f);
1642   dpyinfo = FRAME_DISPLAY_INFO (f);
1644   if (dpyinfo->x_highlight_frame == f)
1645     dpyinfo->x_highlight_frame = 0;
1647   if ([[view window] windowNumber] <= 0)
1648     {
1649       /* the window is still deferred.  Make it very small, bring it
1650          on screen and order it out. */
1651       NSRect s = { { 100, 100}, {0, 0} };
1652       NSRect t;
1653       t = [[view window] frame];
1654       [[view window] setFrame: s display: NO];
1655       [[view window] orderBack: NSApp];
1656       [[view window] orderOut: NSApp];
1657       [[view window] setFrame: t display: NO];
1658     }
1660   /* Processing input while Emacs is being minimized can cause a
1661      crash, so block it for the duration. */
1662   block_input();
1663   [[view window] miniaturize: NSApp];
1664   unblock_input();
1667 /* Free X resources of frame F.  */
1669 void
1670 x_free_frame_resources (struct frame *f)
1672   NSView *view;
1673   struct ns_display_info *dpyinfo;
1674   Mouse_HLInfo *hlinfo;
1676   NSTRACE ("x_free_frame_resources");
1677   check_window_system (f);
1678   view = FRAME_NS_VIEW (f);
1679   dpyinfo = FRAME_DISPLAY_INFO (f);
1680   hlinfo = MOUSE_HL_INFO (f);
1682   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1684   block_input ();
1686   free_frame_menubar (f);
1687   free_frame_faces (f);
1689   if (f == dpyinfo->x_focus_frame)
1690     dpyinfo->x_focus_frame = 0;
1691   if (f == dpyinfo->x_highlight_frame)
1692     dpyinfo->x_highlight_frame = 0;
1693   if (f == hlinfo->mouse_face_mouse_frame)
1694     reset_mouse_highlight (hlinfo);
1695   /* Ensure that sendEvent does not attempt to dereference a freed
1696      frame. (bug#30800) */
1697   if (represented_frame == f)
1698     represented_frame = NULL;
1700   if (f->output_data.ns->miniimage != nil)
1701     [f->output_data.ns->miniimage release];
1703   [[view window] close];
1704   [view release];
1706   xfree (f->output_data.ns);
1708   unblock_input ();
1711 void
1712 x_destroy_window (struct frame *f)
1713 /* --------------------------------------------------------------------------
1714      External: Delete the window
1715    -------------------------------------------------------------------------- */
1717   NSTRACE ("x_destroy_window");
1719   /* If this frame has a parent window, detach it as not doing so can
1720      cause a crash in GNUStep. */
1721   if (FRAME_PARENT_FRAME (f) != NULL)
1722     {
1723       NSWindow *child = [FRAME_NS_VIEW (f) window];
1724       NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1726       [parent removeChildWindow: child];
1727     }
1729   check_window_system (f);
1730   x_free_frame_resources (f);
1731   ns_window_num--;
1735 void
1736 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1737 /* --------------------------------------------------------------------------
1738      External: Position the window
1739    -------------------------------------------------------------------------- */
1741   NSView *view = FRAME_NS_VIEW (f);
1742   NSArray *screens = [NSScreen screens];
1743   NSScreen *screen = [[view window] screen];
1745   NSTRACE ("x_set_offset");
1747   block_input ();
1749   f->left_pos = xoff;
1750   f->top_pos = yoff;
1752   if (view != nil)
1753     {
1754       if (FRAME_PARENT_FRAME (f) == NULL && screen)
1755         {
1756           f->left_pos = f->size_hint_flags & XNegative
1757             ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1758             : f->left_pos;
1759           /* We use visibleFrame here to take menu bar into account.
1760              Ideally we should also adjust left/top with visibleFrame.origin.  */
1762           f->top_pos = f->size_hint_flags & YNegative
1763             ? ([screen visibleFrame].size.height + f->top_pos
1764                - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1765                - FRAME_TOOLBAR_HEIGHT (f))
1766             : f->top_pos;
1767 #ifdef NS_IMPL_GNUSTEP
1768           if (f->left_pos < 100)
1769             f->left_pos = 100;  /* don't overlap menu */
1770 #endif
1771         }
1772       else if (FRAME_PARENT_FRAME (f) != NULL)
1773         {
1774           struct frame *parent = FRAME_PARENT_FRAME (f);
1776           /* On X negative values for child frames always result in
1777              positioning relative to the bottom right corner of the
1778              parent frame.  */
1779           if (f->left_pos < 0)
1780             f->left_pos = FRAME_PIXEL_WIDTH (parent) - FRAME_PIXEL_WIDTH (f) + f->left_pos;
1782           if (f->top_pos < 0)
1783             f->top_pos = FRAME_PIXEL_HEIGHT (parent) + FRAME_TOOLBAR_HEIGHT (parent)
1784               - FRAME_PIXEL_HEIGHT (f) + f->top_pos;
1785         }
1787       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1788          menu bar.  */
1789       NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
1790                                                 + NS_PARENT_WINDOW_LEFT_POS (f)),
1791                                 SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
1792                                                 - f->top_pos));
1793       NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1794       [[view window] setFrameTopLeftPoint: pt];
1795       f->size_hint_flags &= ~(XNegative|YNegative);
1796     }
1798   unblock_input ();
1802 void
1803 x_set_window_size (struct frame *f,
1804                    bool change_gravity,
1805                    int width,
1806                    int height,
1807                    bool pixelwise)
1808 /* --------------------------------------------------------------------------
1809      Adjust window pixel size based on given character grid size
1810      Impl is a bit more complex than other terms, need to do some
1811      internal clipping.
1812    -------------------------------------------------------------------------- */
1814   EmacsView *view = FRAME_NS_VIEW (f);
1815   NSWindow *window = [view window];
1816   NSRect wr = [window frame];
1817   int pixelwidth, pixelheight;
1818   int orig_height = wr.size.height;
1820   NSTRACE ("x_set_window_size");
1822   if (view == nil)
1823     return;
1825   NSTRACE_RECT ("current", wr);
1826   NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1827   NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1829   block_input ();
1831   if (pixelwise)
1832     {
1833       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1834       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1835     }
1836   else
1837     {
1838       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1839       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1840     }
1842   wr.size.width = pixelwidth + f->border_width;
1843   wr.size.height = pixelheight;
1844   if (! [view isFullscreen])
1845     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1846       + FRAME_TOOLBAR_HEIGHT (f);
1848   /* Do not try to constrain to this screen.  We may have multiple
1849      screens, and want Emacs to span those.  Constraining to screen
1850      prevents that, and that is not nice to the user.  */
1851  if (f->output_data.ns->zooming)
1852    f->output_data.ns->zooming = 0;
1853  else
1854    wr.origin.y += orig_height - wr.size.height;
1856  frame_size_history_add
1857    (f, Qx_set_window_size_1, width, height,
1858     list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1859            Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1860            make_number (f->border_width),
1861            make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1862            make_number (FRAME_TOOLBAR_HEIGHT (f))));
1864   [window setFrame: wr display: YES];
1866   [view updateFrameSize: NO];
1867   unblock_input ();
1870 #ifdef NS_IMPL_COCOA
1871 void
1872 x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1873 /* --------------------------------------------------------------------------
1874      Set frame F's `undecorated' parameter.  If non-nil, F's window-system
1875      window is drawn without decorations, title, minimize/maximize boxes
1876      and external borders.  This usually means that the window cannot be
1877      dragged, resized, iconified, maximized or deleted with the mouse.  If
1878      nil, draw the frame with all the elements listed above unless these
1879      have been suspended via window manager settings.
1881      GNUStep cannot change an existing window's style.
1882    -------------------------------------------------------------------------- */
1884   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1885   NSWindow *window = [view window];
1887   NSTRACE ("x_set_undecorated");
1889   if (!EQ (new_value, old_value))
1890     {
1891       block_input ();
1893       if (NILP (new_value))
1894         {
1895           FRAME_UNDECORATED (f) = false;
1896           [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
1897                                   ^ FRAME_UNDECORATED_FLAGS)];
1899           [view createToolbar: f];
1900         }
1901       else
1902         {
1903           [window setToolbar: nil];
1904           /* Do I need to release the toolbar here? */
1906           FRAME_UNDECORATED (f) = true;
1907           [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS)
1908                                  ^ FRAME_DECORATED_FLAGS)];
1909         }
1911       /* At this point it seems we don't have an active NSResponder,
1912          so some key presses (TAB) are swallowed by the system. */
1913       [window makeFirstResponder: view];
1915       [view updateFrameSize: NO];
1916       unblock_input ();
1917     }
1919 #endif /* NS_IMPL_COCOA */
1921 void
1922 x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1923 /* --------------------------------------------------------------------------
1924      Set frame F's `parent-frame' parameter.  If non-nil, make F a child
1925      frame of the frame specified by that parameter.  Technically, this
1926      makes F's window-system window a child window of the parent frame's
1927      window-system window.  If nil, make F's window-system window a
1928      top-level window--a child of its display's root window.
1930      A child frame's `left' and `top' parameters specify positions
1931      relative to the top-left corner of its parent frame's native
1932      rectangle.  On macOS moving a parent frame moves all its child
1933      frames too, keeping their position relative to the parent
1934      unaltered.  When a parent frame is iconified or made invisible, its
1935      child frames are made invisible.  When a parent frame is deleted,
1936      its child frames are deleted too.
1938      Whether a child frame has a tool bar may be window-system or window
1939      manager dependent.  It's advisable to disable it via the frame
1940      parameter settings.
1942      Some window managers may not honor this parameter.
1943    -------------------------------------------------------------------------- */
1945   struct frame *p = NULL;
1946   NSWindow *parent, *child;
1948   NSTRACE ("x_set_parent_frame");
1950   if (!NILP (new_value)
1951       && (!FRAMEP (new_value)
1952           || !FRAME_LIVE_P (p = XFRAME (new_value))
1953           || !FRAME_NS_P (p)))
1954     {
1955       store_frame_param (f, Qparent_frame, old_value);
1956       error ("Invalid specification of `parent-frame'");
1957     }
1959   if (p != FRAME_PARENT_FRAME (f))
1960     {
1961       parent = [FRAME_NS_VIEW (p) window];
1962       child = [FRAME_NS_VIEW (f) window];
1964       block_input ();
1965       [parent addChildWindow: child
1966                      ordered: NSWindowAbove];
1967       unblock_input ();
1969       fset_parent_frame (f, new_value);
1970     }
1973 void
1974 x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1975 /* Set frame F's `no-focus-on-map' parameter which, if non-nil, means
1976  * that F's window-system window does not want to receive input focus
1977  * when it is mapped.  (A frame's window is mapped when the frame is
1978  * displayed for the first time and when the frame changes its state
1979  * from `iconified' or `invisible' to `visible'.)
1981  * Some window managers may not honor this parameter. */
1983   NSTRACE ("x_set_no_focus_on_map");
1985   if (!EQ (new_value, old_value))
1986     {
1987       FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
1988     }
1991 void
1992 x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1993 /*  Set frame F's `no-accept-focus' parameter which, if non-nil, hints
1994  * that F's window-system window does not want to receive input focus
1995  * via mouse clicks or by moving the mouse into it.
1997  * If non-nil, this may have the unwanted side-effect that a user cannot
1998  * scroll a non-selected frame with the mouse.
2000  * Some window managers may not honor this parameter. */
2002   NSTRACE ("x_set_no_accept_focus");
2004   if (!EQ (new_value, old_value))
2005     FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
2008 void
2009 x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2010 /* Set frame F's `z-group' parameter.  If `above', F's window-system
2011    window is displayed above all windows that do not have the `above'
2012    property set.  If nil, F's window is shown below all windows that
2013    have the `above' property set and above all windows that have the
2014    `below' property set.  If `below', F's window is displayed below
2015    all windows that do.
2017    Some window managers may not honor this parameter. */
2019   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2020   NSWindow *window = [view window];
2022   NSTRACE ("x_set_z_group");
2024   if (NILP (new_value))
2025     {
2026       window.level = NSNormalWindowLevel;
2027       FRAME_Z_GROUP (f) = z_group_none;
2028     }
2029   else if (EQ (new_value, Qabove))
2030     {
2031       window.level = NSNormalWindowLevel + 1;
2032       FRAME_Z_GROUP (f) = z_group_above;
2033     }
2034   else if (EQ (new_value, Qabove_suspended))
2035     {
2036       /* Not sure what level this should be. */
2037       window.level = NSNormalWindowLevel + 1;
2038       FRAME_Z_GROUP (f) = z_group_above_suspended;
2039     }
2040   else if (EQ (new_value, Qbelow))
2041     {
2042       window.level = NSNormalWindowLevel - 1;
2043       FRAME_Z_GROUP (f) = z_group_below;
2044     }
2045   else
2046     error ("Invalid z-group specification");
2049 #ifdef NS_IMPL_COCOA
2050 void
2051 ns_set_appearance (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2053 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
2054   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2055   NSWindow *window = [view window];
2057   NSTRACE ("ns_set_appearance");
2059 #ifndef NSAppKitVersionNumber10_10
2060 #define NSAppKitVersionNumber10_10 1343
2061 #endif
2063   if (NSAppKitVersionNumber < NSAppKitVersionNumber10_10)
2064     return;
2066   if (EQ (new_value, Qdark))
2067     {
2068       window.appearance = [NSAppearance
2069                             appearanceNamed: NSAppearanceNameVibrantDark];
2070       FRAME_NS_APPEARANCE (f) = ns_appearance_vibrant_dark;
2071     }
2072   else
2073     {
2074       window.appearance = [NSAppearance
2075                             appearanceNamed: NSAppearanceNameAqua];
2076       FRAME_NS_APPEARANCE (f) = ns_appearance_aqua;
2077     }
2078 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
2081 void
2082 ns_set_transparent_titlebar (struct frame *f, Lisp_Object new_value,
2083                              Lisp_Object old_value)
2085 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
2086   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2087   NSWindow *window = [view window];
2089   NSTRACE ("ns_set_transparent_titlebar");
2091   if ([window respondsToSelector: @selector(titlebarAppearsTransparent)]
2092       && !EQ (new_value, old_value))
2093     {
2094       window.titlebarAppearsTransparent = !NILP (new_value);
2095       FRAME_NS_TRANSPARENT_TITLEBAR (f) = !NILP (new_value);
2096     }
2097 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
2099 #endif /* NS_IMPL_COCOA */
2101 static void
2102 ns_fullscreen_hook (struct frame *f)
2104   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2106   NSTRACE ("ns_fullscreen_hook");
2108   if (!FRAME_VISIBLE_P (f))
2109     return;
2111    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
2112     {
2113       /* Old style fs don't initiate correctly if created from
2114          init/default-frame alist, so use a timer (not nice...).
2115       */
2116       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
2117                                      selector: @selector (handleFS)
2118                                      userInfo: nil repeats: NO];
2119       return;
2120     }
2122   block_input ();
2123   [view handleFS];
2124   unblock_input ();
2127 /* ==========================================================================
2129     Color management
2131    ========================================================================== */
2134 NSColor *
2135 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
2137   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2138   if (idx < 1 || idx >= color_table->avail)
2139     return nil;
2140   return color_table->colors[idx];
2144 unsigned long
2145 ns_index_color (NSColor *color, struct frame *f)
2147   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2148   ptrdiff_t idx;
2149   ptrdiff_t i;
2151   if (!color_table->colors)
2152     {
2153       color_table->size = NS_COLOR_CAPACITY;
2154       color_table->avail = 1; /* skip idx=0 as marker */
2155       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
2156       color_table->colors[0] = nil;
2157       color_table->empty_indices = [[NSMutableSet alloc] init];
2158     }
2160   /* Do we already have this color?  */
2161   for (i = 1; i < color_table->avail; i++)
2162     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
2163       return i;
2165   if ([color_table->empty_indices count] > 0)
2166     {
2167       NSNumber *index = [color_table->empty_indices anyObject];
2168       [color_table->empty_indices removeObject: index];
2169       idx = [index unsignedLongValue];
2170     }
2171   else
2172     {
2173       if (color_table->avail == color_table->size)
2174         color_table->colors =
2175           xpalloc (color_table->colors, &color_table->size, 1,
2176                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
2177       idx = color_table->avail++;
2178     }
2180   color_table->colors[idx] = color;
2181   [color retain];
2182 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
2183   return idx;
2187 static int
2188 ns_get_color (const char *name, NSColor **col)
2189 /* --------------------------------------------------------------------------
2190      Parse a color name
2191    -------------------------------------------------------------------------- */
2192 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
2193    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
2194    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
2196   NSColor *new = nil;
2197   static char hex[20];
2198   int scaling = 0;
2199   float r = -1.0, g, b;
2200   NSString *nsname = [NSString stringWithUTF8String: name];
2202   NSTRACE ("ns_get_color(%s, **)", name);
2204   block_input ();
2206   if ([nsname isEqualToString: @"ns_selection_bg_color"])
2207     {
2208 #ifdef NS_IMPL_COCOA
2209       NSString *defname = [[NSUserDefaults standardUserDefaults]
2210                             stringForKey: @"AppleHighlightColor"];
2211       if (defname != nil)
2212         nsname = defname;
2213       else
2214 #endif
2215       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
2216         {
2217           *col = [new colorUsingDefaultColorSpace];
2218           unblock_input ();
2219           return 0;
2220         }
2221       else
2222         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
2224       name = [nsname UTF8String];
2225     }
2226   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
2227     {
2228       /* NOTE: macOS applications normally don't set foreground
2229          selection, but text may be unreadable if we don't.
2230       */
2231       if ((new = [NSColor selectedTextColor]) != nil)
2232         {
2233           *col = [new colorUsingDefaultColorSpace];
2234           unblock_input ();
2235           return 0;
2236         }
2238       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
2239       name = [nsname UTF8String];
2240     }
2242   /* First, check for some sort of numeric specification. */
2243   hex[0] = '\0';
2245   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
2246     {
2247       NSScanner *scanner = [NSScanner scannerWithString: nsname];
2248       [scanner scanFloat: &r];
2249       [scanner scanFloat: &g];
2250       [scanner scanFloat: &b];
2251     }
2252   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
2253     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2254   else if (name[0] == '#')        /* An old X11 format; convert to newer */
2255     {
2256       int len = (strlen(name) - 1);
2257       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2258       int i;
2259       scaling = strlen(name+start) / 3;
2260       for (i = 0; i < 3; i++)
2261         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2262                  name + start + i * scaling);
2263       hex[3 * (scaling + 1) - 1] = '\0';
2264     }
2266   if (hex[0])
2267     {
2268       unsigned int rr, gg, bb;
2269       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2270       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2271         {
2272           r = rr / fscale;
2273           g = gg / fscale;
2274           b = bb / fscale;
2275         }
2276     }
2278   if (r >= 0.0F)
2279     {
2280       *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2281       unblock_input ();
2282       return 0;
2283     }
2285   /* Otherwise, color is expected to be from a list */
2286   {
2287     NSEnumerator *lenum, *cenum;
2288     NSString *name;
2289     NSColorList *clist;
2291 #ifdef NS_IMPL_GNUSTEP
2292     /* XXX: who is wrong, the requestor or the implementation? */
2293     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2294         == NSOrderedSame)
2295       nsname = @"highlightColor";
2296 #endif
2298     lenum = [[NSColorList availableColorLists] objectEnumerator];
2299     while ( (clist = [lenum nextObject]) && new == nil)
2300       {
2301         cenum = [[clist allKeys] objectEnumerator];
2302         while ( (name = [cenum nextObject]) && new == nil )
2303           {
2304             if ([name compare: nsname
2305                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
2306               new = [clist colorWithKey: name];
2307           }
2308       }
2309   }
2311   if (new)
2312     *col = [new colorUsingDefaultColorSpace];
2313   unblock_input ();
2314   return new ? 0 : 1;
2319 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2320 /* --------------------------------------------------------------------------
2321      Convert a Lisp string object to a NS color
2322    -------------------------------------------------------------------------- */
2324   NSTRACE ("ns_lisp_to_color");
2325   if (STRINGP (color))
2326     return ns_get_color (SSDATA (color), col);
2327   else if (SYMBOLP (color))
2328     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2329   return 1;
2333 void
2334 ns_query_color(void *col, XColor *color_def, int setPixel)
2335 /* --------------------------------------------------------------------------
2336          Get ARGB values out of NSColor col and put them into color_def.
2337          If setPixel, set the pixel to a concatenated version.
2338          and set color_def pixel to the resulting index.
2339    -------------------------------------------------------------------------- */
2341   EmacsCGFloat r, g, b, a;
2343   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2344   color_def->red   = r * 65535;
2345   color_def->green = g * 65535;
2346   color_def->blue  = b * 65535;
2348   if (setPixel == YES)
2349     color_def->pixel
2350       = ARGB_TO_ULONG((int)(a*255),
2351                       (int)(r*255), (int)(g*255), (int)(b*255));
2355 bool
2356 ns_defined_color (struct frame *f,
2357                   const char *name,
2358                   XColor *color_def,
2359                   bool alloc,
2360                   bool makeIndex)
2361 /* --------------------------------------------------------------------------
2362          Return true if named color found, and set color_def rgb accordingly.
2363          If makeIndex and alloc are nonzero put the color in the color_table,
2364          and set color_def pixel to the resulting index.
2365          If makeIndex is zero, set color_def pixel to ARGB.
2366          Return false if not found
2367    -------------------------------------------------------------------------- */
2369   NSColor *col;
2370   NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2372   block_input ();
2373   if (ns_get_color (name, &col) != 0) /* Color not found  */
2374     {
2375       unblock_input ();
2376       return 0;
2377     }
2378   if (makeIndex && alloc)
2379     color_def->pixel = ns_index_color (col, f);
2380   ns_query_color (col, color_def, !makeIndex);
2381   unblock_input ();
2382   return 1;
2386 void
2387 x_set_frame_alpha (struct frame *f)
2388 /* --------------------------------------------------------------------------
2389      change the entire-frame transparency
2390    -------------------------------------------------------------------------- */
2392   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2393   double alpha = 1.0;
2394   double alpha_min = 1.0;
2396   NSTRACE ("x_set_frame_alpha");
2398   if (dpyinfo->x_highlight_frame == f)
2399     alpha = f->alpha[0];
2400   else
2401     alpha = f->alpha[1];
2403   if (FLOATP (Vframe_alpha_lower_limit))
2404     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2405   else if (INTEGERP (Vframe_alpha_lower_limit))
2406     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2408   if (alpha < 0.0)
2409     return;
2410   else if (1.0 < alpha)
2411     alpha = 1.0;
2412   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2413     alpha = alpha_min;
2415 #ifdef NS_IMPL_COCOA
2416   {
2417     EmacsView *view = FRAME_NS_VIEW (f);
2418   [[view window] setAlphaValue: alpha];
2419   }
2420 #endif
2424 /* ==========================================================================
2426     Mouse handling
2428    ========================================================================== */
2431 void
2432 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2433 /* --------------------------------------------------------------------------
2434      Programmatically reposition mouse pointer in pixel coordinates
2435    -------------------------------------------------------------------------- */
2437   NSTRACE ("frame_set_mouse_pixel_position");
2439   /* FIXME: what about GNUstep? */
2440 #ifdef NS_IMPL_COCOA
2441   CGPoint mouse_pos =
2442     CGPointMake(f->left_pos + pix_x,
2443                 f->top_pos + pix_y +
2444                 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
2445   CGWarpMouseCursorPosition (mouse_pos);
2446 #endif
2449 static int
2450 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2451 /*   ------------------------------------------------------------------------
2452      Called by EmacsView on mouseMovement events.  Passes on
2453      to emacs mainstream code if we moved off of a rect of interest
2454      known as last_mouse_glyph.
2455      ------------------------------------------------------------------------ */
2457   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2458   NSRect *r;
2460 //  NSTRACE ("note_mouse_movement");
2462   dpyinfo->last_mouse_motion_frame = frame;
2463   r = &dpyinfo->last_mouse_glyph;
2465   /* Note, this doesn't get called for enter/leave, since we don't have a
2466      position.  Those are taken care of in the corresponding NSView methods. */
2468   /* has movement gone beyond last rect we were tracking? */
2469   if (x < r->origin.x || x >= r->origin.x + r->size.width
2470       || y < r->origin.y || y >= r->origin.y + r->size.height)
2471     {
2472       ns_update_begin (frame);
2473       frame->mouse_moved = 1;
2474       note_mouse_highlight (frame, x, y);
2475       remember_mouse_glyph (frame, x, y, r);
2476       ns_update_end (frame);
2477       return 1;
2478     }
2480   return 0;
2484 static void
2485 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2486                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2487                    Time *time)
2488 /* --------------------------------------------------------------------------
2489     External (hook): inform emacs about mouse position and hit parts.
2490     If a scrollbar is being dragged, set bar_window, part, x, y, time.
2491     x & y should be position in the scrollbar (the whole bar, not the handle)
2492     and length of scrollbar respectively
2493    -------------------------------------------------------------------------- */
2495   id view;
2496   NSPoint position;
2497   Lisp_Object frame, tail;
2498   struct frame *f;
2499   struct ns_display_info *dpyinfo;
2501   NSTRACE ("ns_mouse_position");
2503   if (*fp == NULL)
2504     {
2505       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2506       return;
2507     }
2509   dpyinfo = FRAME_DISPLAY_INFO (*fp);
2511   block_input ();
2513   /* Clear the mouse-moved flag for every frame on this display.  */
2514   FOR_EACH_FRAME (tail, frame)
2515     if (FRAME_NS_P (XFRAME (frame))
2516         && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2517       XFRAME (frame)->mouse_moved = 0;
2519   dpyinfo->last_mouse_scroll_bar = nil;
2520   if (dpyinfo->last_mouse_frame
2521       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2522     f = dpyinfo->last_mouse_frame;
2523   else
2524     f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2526   if (f && FRAME_NS_P (f))
2527     {
2528       view = FRAME_NS_VIEW (*fp);
2530       position = [[view window] mouseLocationOutsideOfEventStream];
2531       position = [view convertPoint: position fromView: nil];
2532       remember_mouse_glyph (f, position.x, position.y,
2533                             &dpyinfo->last_mouse_glyph);
2534       NSTRACE_POINT ("position", position);
2536       if (bar_window) *bar_window = Qnil;
2537       if (part) *part = scroll_bar_above_handle;
2539       if (x) XSETINT (*x, lrint (position.x));
2540       if (y) XSETINT (*y, lrint (position.y));
2541       if (time)
2542         *time = dpyinfo->last_mouse_movement_time;
2543       *fp = f;
2544     }
2546   unblock_input ();
2550 static void
2551 ns_frame_up_to_date (struct frame *f)
2552 /* --------------------------------------------------------------------------
2553     External (hook): Fix up mouse highlighting right after a full update.
2554     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2555    -------------------------------------------------------------------------- */
2557   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2559   if (FRAME_NS_P (f))
2560     {
2561       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2562       if (f == hlinfo->mouse_face_mouse_frame)
2563         {
2564           block_input ();
2565           ns_update_begin(f);
2566           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2567                                 hlinfo->mouse_face_mouse_x,
2568                                 hlinfo->mouse_face_mouse_y);
2569           ns_update_end(f);
2570           unblock_input ();
2571         }
2572     }
2576 static void
2577 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2578 /* --------------------------------------------------------------------------
2579     External (RIF): set frame mouse pointer type.
2580    -------------------------------------------------------------------------- */
2582   NSTRACE ("ns_define_frame_cursor");
2583   if (FRAME_POINTER_TYPE (f) != cursor)
2584     {
2585       EmacsView *view = FRAME_NS_VIEW (f);
2586       FRAME_POINTER_TYPE (f) = cursor;
2587       [[view window] invalidateCursorRectsForView: view];
2588       /* Redisplay assumes this function also draws the changed frame
2589          cursor, but this function doesn't, so do it explicitly.  */
2590       x_update_cursor (f, 1);
2591     }
2596 /* ==========================================================================
2598     Keyboard handling
2600    ========================================================================== */
2603 static unsigned
2604 ns_convert_key (unsigned code)
2605 /* --------------------------------------------------------------------------
2606     Internal call used by NSView-keyDown.
2607    -------------------------------------------------------------------------- */
2609   const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2610   unsigned keysym;
2611   /* An array would be faster, but less easy to read. */
2612   for (keysym = 0; keysym < last_keysym; keysym += 2)
2613     if (code == convert_ns_to_X_keysym[keysym])
2614       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2615   return 0;
2616 /* if decide to use keyCode and Carbon table, use this line:
2617      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2621 char *
2622 x_get_keysym_name (int keysym)
2623 /* --------------------------------------------------------------------------
2624     Called by keyboard.c.  Not sure if the return val is important, except
2625     that it be unique.
2626    -------------------------------------------------------------------------- */
2628   static char value[16];
2629   NSTRACE ("x_get_keysym_name");
2630   sprintf (value, "%d", keysym);
2631   return value;
2636 /* ==========================================================================
2638     Block drawing operations
2640    ========================================================================== */
2643 static void
2644 ns_redraw_scroll_bars (struct frame *f)
2646   int i;
2647   id view;
2648   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2649   NSTRACE ("ns_redraw_scroll_bars");
2650   for (i =[subviews count]-1; i >= 0; i--)
2651     {
2652       view = [subviews objectAtIndex: i];
2653       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2654       [view display];
2655     }
2659 void
2660 ns_clear_frame (struct frame *f)
2661 /* --------------------------------------------------------------------------
2662       External (hook): Erase the entire frame
2663    -------------------------------------------------------------------------- */
2665   NSView *view = FRAME_NS_VIEW (f);
2666   NSRect r;
2668   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2670  /* comes on initial frame because we have
2671     after-make-frame-functions = select-frame */
2672  if (!FRAME_DEFAULT_FACE (f))
2673    return;
2675   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2677   r = [view bounds];
2679   block_input ();
2680   ns_focus (f, &r, 1);
2681   [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2682                             (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
2683   NSRectFill (r);
2684   ns_unfocus (f);
2686   /* as of 2006/11 or so this is now needed */
2687   ns_redraw_scroll_bars (f);
2688   unblock_input ();
2692 static void
2693 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2694 /* --------------------------------------------------------------------------
2695     External (RIF):  Clear section of frame
2696    -------------------------------------------------------------------------- */
2698   NSRect r = NSMakeRect (x, y, width, height);
2699   NSView *view = FRAME_NS_VIEW (f);
2700   struct face *face = FRAME_DEFAULT_FACE (f);
2702   if (!view || !face)
2703     return;
2705   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2707   r = NSIntersectionRect (r, [view frame]);
2708   ns_focus (f, &r, 1);
2709   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2711   NSRectFill (r);
2713   ns_unfocus (f);
2714   return;
2717 static void
2718 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2720   NSTRACE ("ns_copy_bits");
2722   if (FRAME_NS_VIEW (f))
2723     {
2724       hide_bell();              // Ensure the bell image isn't scrolled.
2726       ns_focus (f, &dest, 1);
2727       [FRAME_NS_VIEW (f) scrollRect: src
2728                                  by: NSMakeSize (dest.origin.x - src.origin.x,
2729                                                  dest.origin.y - src.origin.y)];
2730       ns_unfocus (f);
2731     }
2734 static void
2735 ns_scroll_run (struct window *w, struct run *run)
2736 /* --------------------------------------------------------------------------
2737     External (RIF):  Insert or delete n lines at line vpos
2738    -------------------------------------------------------------------------- */
2740   struct frame *f = XFRAME (w->frame);
2741   int x, y, width, height, from_y, to_y, bottom_y;
2743   NSTRACE ("ns_scroll_run");
2745   /* begin copy from other terms */
2746   /* Get frame-relative bounding box of the text display area of W,
2747      without mode lines.  Include in this box the left and right
2748      fringe of W.  */
2749   window_box (w, ANY_AREA, &x, &y, &width, &height);
2751   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2752   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2753   bottom_y = y + height;
2755   if (to_y < from_y)
2756     {
2757       /* Scrolling up.  Make sure we don't copy part of the mode
2758          line at the bottom.  */
2759       if (from_y + run->height > bottom_y)
2760         height = bottom_y - from_y;
2761       else
2762         height = run->height;
2763     }
2764   else
2765     {
2766       /* Scrolling down.  Make sure we don't copy over the mode line.
2767          at the bottom.  */
2768       if (to_y + run->height > bottom_y)
2769         height = bottom_y - to_y;
2770       else
2771         height = run->height;
2772     }
2773   /* end copy from other terms */
2775   if (height == 0)
2776       return;
2778   block_input ();
2780   x_clear_cursor (w);
2782   {
2783     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2784     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2786     ns_copy_bits (f, srcRect , dstRect);
2787   }
2789   unblock_input ();
2793 static void
2794 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2795 /* --------------------------------------------------------------------------
2796     External (RIF): preparatory to fringe update after text was updated
2797    -------------------------------------------------------------------------- */
2799   struct frame *f;
2800   int width, height;
2802   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2804   /* begin copy from other terms */
2805   eassert (w);
2807   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2808     desired_row->redraw_fringe_bitmaps_p = 1;
2810   /* When a window has disappeared, make sure that no rest of
2811      full-width rows stays visible in the internal border.  */
2812   if (windows_or_buffers_changed
2813       && desired_row->full_width_p
2814       && (f = XFRAME (w->frame),
2815           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2816           width != 0)
2817       && (height = desired_row->visible_height,
2818           height > 0))
2819     {
2820       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2822       block_input ();
2823       ns_clear_frame_area (f, 0, y, width, height);
2824       ns_clear_frame_area (f,
2825                            FRAME_PIXEL_WIDTH (f) - width,
2826                            y, width, height);
2827       unblock_input ();
2828     }
2832 static void
2833 ns_shift_glyphs_for_insert (struct frame *f,
2834                            int x, int y, int width, int height,
2835                            int shift_by)
2836 /* --------------------------------------------------------------------------
2837     External (RIF): copy an area horizontally, don't worry about clearing src
2838    -------------------------------------------------------------------------- */
2840   NSRect srcRect = NSMakeRect (x, y, width, height);
2841   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2843   NSTRACE ("ns_shift_glyphs_for_insert");
2845   ns_copy_bits (f, srcRect, dstRect);
2850 /* ==========================================================================
2852     Character encoding and metrics
2854    ========================================================================== */
2857 static void
2858 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2859 /* --------------------------------------------------------------------------
2860      External (RIF); compute left/right overhang of whole string and set in s
2861    -------------------------------------------------------------------------- */
2863   struct font *font = s->font;
2865   if (s->char2b)
2866     {
2867       struct font_metrics metrics;
2868       unsigned int codes[2];
2869       codes[0] = *(s->char2b);
2870       codes[1] = *(s->char2b + s->nchars - 1);
2872       font->driver->text_extents (font, codes, 2, &metrics);
2873       s->left_overhang = -metrics.lbearing;
2874       s->right_overhang
2875         = metrics.rbearing > metrics.width
2876         ? metrics.rbearing - metrics.width : 0;
2877     }
2878   else
2879     {
2880       s->left_overhang = 0;
2881       if (EQ (font->driver->type, Qns))
2882         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2883           FONT_HEIGHT (font) * 0.2 : 0;
2884       else
2885         s->right_overhang = 0;
2886     }
2891 /* ==========================================================================
2893     Fringe and cursor drawing
2895    ========================================================================== */
2898 extern int max_used_fringe_bitmap;
2899 static void
2900 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2901                       struct draw_fringe_bitmap_params *p)
2902 /* --------------------------------------------------------------------------
2903     External (RIF); fringe-related
2904    -------------------------------------------------------------------------- */
2906   /* Fringe bitmaps comes in two variants, normal and periodic.  A
2907      periodic bitmap is used to create a continuous pattern.  Since a
2908      bitmap is rendered one text line at a time, the start offset (dh)
2909      of the bitmap varies.  Concretely, this is used for the empty
2910      line indicator.
2912      For a bitmap, "h + dh" is the full height and is always
2913      invariant.  For a normal bitmap "dh" is zero.
2915      For example, when the period is three and the full height is 72
2916      the following combinations exists:
2918        h=72 dh=0
2919        h=71 dh=1
2920        h=70 dh=2 */
2922   struct frame *f = XFRAME (WINDOW_FRAME (w));
2923   struct face *face = p->face;
2924   static EmacsImage **bimgs = NULL;
2925   static int nBimgs = 0;
2927   NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2928   NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2929                p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2931   /* grow bimgs if needed */
2932   if (nBimgs < max_used_fringe_bitmap)
2933     {
2934       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2935       memset (bimgs + nBimgs, 0,
2936               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2937       nBimgs = max_used_fringe_bitmap;
2938     }
2940   /* Must clip because of partially visible lines.  */
2941   ns_clip_to_row (w, row, ANY_AREA, YES);
2943   if (!p->overlay_p)
2944     {
2945       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2947       if (bx >= 0 && nx > 0)
2948         {
2949           NSRect r = NSMakeRect (bx, by, nx, ny);
2950           NSRectClip (r);
2951           [ns_lookup_indexed_color (face->background, f) set];
2952           NSRectFill (r);
2953         }
2954     }
2956   if (p->which)
2957     {
2958       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2959       EmacsImage *img = bimgs[p->which - 1];
2961       if (!img)
2962         {
2963           // Note: For "periodic" images, allocate one EmacsImage for
2964           // the base image, and use it for all dh:s.
2965           unsigned short *bits = p->bits;
2966           int full_height = p->h + p->dh;
2967           int i;
2968           unsigned char *cbits = xmalloc (full_height);
2970           for (i = 0; i < full_height; i++)
2971             cbits[i] = bits[i];
2972           img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2973                                          height: full_height
2974                                              fg: 0 bg: 0];
2975           bimgs[p->which - 1] = img;
2976           xfree (cbits);
2977         }
2979       NSTRACE_RECT ("r", r);
2981       NSRectClip (r);
2982       /* Since we composite the bitmap instead of just blitting it, we need
2983          to erase the whole background. */
2984       [ns_lookup_indexed_color(face->background, f) set];
2985       NSRectFill (r);
2987       {
2988         NSColor *bm_color;
2989         if (!p->cursor_p)
2990           bm_color = ns_lookup_indexed_color(face->foreground, f);
2991         else if (p->overlay_p)
2992           bm_color = ns_lookup_indexed_color(face->background, f);
2993         else
2994           bm_color = f->output_data.ns->cursor_color;
2995         [img setXBMColor: bm_color];
2996       }
2998 #ifdef NS_IMPL_COCOA
2999       // Note: For periodic images, the full image height is "h + hd".
3000       // By using the height h, a suitable part of the image is used.
3001       NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
3003       NSTRACE_RECT ("fromRect", fromRect);
3005       [img drawInRect: r
3006               fromRect: fromRect
3007              operation: NSCompositingOperationSourceOver
3008               fraction: 1.0
3009            respectFlipped: YES
3010                 hints: nil];
3011 #else
3012       {
3013         NSPoint pt = r.origin;
3014         pt.y += p->h;
3015         [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
3016       }
3017 #endif
3018     }
3019   ns_unfocus (f);
3023 static void
3024 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3025                        int x, int y, enum text_cursor_kinds cursor_type,
3026                        int cursor_width, bool on_p, bool active_p)
3027 /* --------------------------------------------------------------------------
3028      External call (RIF): draw cursor.
3029      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
3030    -------------------------------------------------------------------------- */
3032   NSRect r, s;
3033   int fx, fy, h, cursor_height;
3034   struct frame *f = WINDOW_XFRAME (w);
3035   struct glyph *phys_cursor_glyph;
3036   struct glyph *cursor_glyph;
3037   struct face *face;
3038   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
3040   /* If cursor is out of bounds, don't draw garbage.  This can happen
3041      in mini-buffer windows when switching between echo area glyphs
3042      and mini-buffer.  */
3044   NSTRACE ("ns_draw_window_cursor");
3046   if (!on_p)
3047     return;
3049   w->phys_cursor_type = cursor_type;
3050   w->phys_cursor_on_p = on_p;
3052   if (cursor_type == NO_CURSOR)
3053     {
3054       w->phys_cursor_width = 0;
3055       return;
3056     }
3058   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
3059     {
3060       if (glyph_row->exact_window_width_line_p
3061           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
3062         {
3063           glyph_row->cursor_in_fringe_p = 1;
3064           draw_fringe_bitmap (w, glyph_row, 0);
3065         }
3066       return;
3067     }
3069   /* We draw the cursor (with NSRectFill), then draw the glyph on top
3070      (other terminals do it the other way round).  We must set
3071      w->phys_cursor_width to the cursor width.  For bar cursors, that
3072      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
3073   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
3075   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
3076      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
3077   if (cursor_type == BAR_CURSOR)
3078     {
3079       if (cursor_width < 1)
3080         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
3082       /* The bar cursor should never be wider than the glyph. */
3083       if (cursor_width < w->phys_cursor_width)
3084         w->phys_cursor_width = cursor_width;
3085     }
3086   /* If we have an HBAR, "cursor_width" MAY specify height. */
3087   else if (cursor_type == HBAR_CURSOR)
3088     {
3089       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
3090       if (cursor_height > glyph_row->height)
3091         cursor_height = glyph_row->height;
3092       if (h > cursor_height) // Cursor smaller than line height, move down
3093         fy += h - cursor_height;
3094       h = cursor_height;
3095     }
3097   r.origin.x = fx, r.origin.y = fy;
3098   r.size.height = h;
3099   r.size.width = w->phys_cursor_width;
3101   /* Prevent the cursor from being drawn outside the text area. */
3102   ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
3105   face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
3106   if (face && NS_FACE_BACKGROUND (face)
3107       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
3108     {
3109       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
3110       hollow_color = FRAME_CURSOR_COLOR (f);
3111     }
3112   else
3113     [FRAME_CURSOR_COLOR (f) set];
3115 #ifdef NS_IMPL_COCOA
3116   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
3117            atomic.  Cleaner ways of doing this should be investigated.
3118            One way would be to set a global variable DRAWING_CURSOR
3119            when making the call to draw_phys..(), don't focus in that
3120            case, then move the ns_unfocus() here after that call. */
3121   NSDisableScreenUpdates ();
3122 #endif
3124   switch (cursor_type)
3125     {
3126     case DEFAULT_CURSOR:
3127     case NO_CURSOR:
3128       break;
3129     case FILLED_BOX_CURSOR:
3130       NSRectFill (r);
3131       break;
3132     case HOLLOW_BOX_CURSOR:
3133       NSRectFill (r);
3134       [hollow_color set];
3135       NSRectFill (NSInsetRect (r, 1, 1));
3136       [FRAME_CURSOR_COLOR (f) set];
3137       break;
3138     case HBAR_CURSOR:
3139       NSRectFill (r);
3140       break;
3141     case BAR_CURSOR:
3142       s = r;
3143       /* If the character under cursor is R2L, draw the bar cursor
3144          on the right of its glyph, rather than on the left.  */
3145       cursor_glyph = get_phys_cursor_glyph (w);
3146       if ((cursor_glyph->resolved_level & 1) != 0)
3147         s.origin.x += cursor_glyph->pixel_width - s.size.width;
3149       NSRectFill (s);
3150       break;
3151     }
3152   ns_unfocus (f);
3154   /* draw the character under the cursor */
3155   if (cursor_type != NO_CURSOR)
3156     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3158 #ifdef NS_IMPL_COCOA
3159   NSEnableScreenUpdates ();
3160 #endif
3165 static void
3166 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
3167 /* --------------------------------------------------------------------------
3168      External (RIF): Draw a vertical line.
3169    -------------------------------------------------------------------------- */
3171   struct frame *f = XFRAME (WINDOW_FRAME (w));
3172   struct face *face;
3173   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
3175   NSTRACE ("ns_draw_vertical_window_border");
3177   face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
3179   ns_focus (f, &r, 1);
3180   if (face)
3181     [ns_lookup_indexed_color(face->foreground, f) set];
3183   NSRectFill(r);
3184   ns_unfocus (f);
3188 static void
3189 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3190 /* --------------------------------------------------------------------------
3191      External (RIF): Draw a window divider.
3192    -------------------------------------------------------------------------- */
3194   struct frame *f = XFRAME (WINDOW_FRAME (w));
3195   struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
3196   struct face *face_first
3197     = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID);
3198   struct face *face_last
3199     = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID);
3200   unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f);
3201   unsigned long color_first = (face_first
3202                                ? face_first->foreground
3203                                : FRAME_FOREGROUND_PIXEL (f));
3204   unsigned long color_last = (face_last
3205                               ? face_last->foreground
3206                               : FRAME_FOREGROUND_PIXEL (f));
3207   NSRect divider = NSMakeRect (x0, y0, x1-x0, y1-y0);
3209   NSTRACE ("ns_draw_window_divider");
3211   ns_focus (f, &divider, 1);
3213   if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3))
3214     /* A vertical divider, at least three pixels wide: Draw first and
3215        last pixels differently.  */
3216     {
3217       [ns_lookup_indexed_color(color_first, f) set];
3218       NSRectFill(NSMakeRect (x0, y0, 1, y1 - y0));
3219       [ns_lookup_indexed_color(color, f) set];
3220       NSRectFill(NSMakeRect (x0 + 1, y0, x1 - x0 - 2, y1 - y0));
3221       [ns_lookup_indexed_color(color_last, f) set];
3222       NSRectFill(NSMakeRect (x1 - 1, y0, 1, y1 - y0));
3223     }
3224   else if ((x1 - x0 > y1 - y0) && (y1 - y0 >= 3))
3225     /* A horizontal divider, at least three pixels high: Draw first and
3226        last pixels differently.  */
3227     {
3228       [ns_lookup_indexed_color(color_first, f) set];
3229       NSRectFill(NSMakeRect (x0, y0, x1 - x0, 1));
3230       [ns_lookup_indexed_color(color, f) set];
3231       NSRectFill(NSMakeRect (x0, y0 + 1, x1 - x0, y1 - y0 - 2));
3232       [ns_lookup_indexed_color(color_last, f) set];
3233       NSRectFill(NSMakeRect (x0, y1 - 1, x1 - x0, 1));
3234     }
3235   else
3236     {
3237       /* In any other case do not draw the first and last pixels
3238          differently.  */
3239       [ns_lookup_indexed_color(color, f) set];
3240       NSRectFill(divider);
3241     }
3243   ns_unfocus (f);
3246 static void
3247 ns_show_hourglass (struct frame *f)
3249   /* TODO: add NSProgressIndicator to all frames.  */
3252 static void
3253 ns_hide_hourglass (struct frame *f)
3255   /* TODO: remove NSProgressIndicator from all frames.  */
3258 /* ==========================================================================
3260     Glyph drawing operations
3262    ========================================================================== */
3264 static int
3265 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3266 /* --------------------------------------------------------------------------
3267     Wrapper utility to account for internal border width on full-width lines,
3268     and allow top full-width rows to hit the frame top.  nr should be pointer
3269     to two successive NSRects.  Number of rects actually used is returned.
3270    -------------------------------------------------------------------------- */
3272   int n = get_glyph_string_clip_rects (s, nr, 2);
3273   return n;
3276 /* --------------------------------------------------------------------
3277    Draw a wavy line under glyph string s. The wave fills wave_height
3278    pixels from y.
3280                     x          wave_length = 2
3281                                  --
3282                 y    *   *   *   *   *
3283                      |* * * * * * * * *
3284     wave_height = 3  | *   *   *   *
3285   --------------------------------------------------------------------- */
3287 static void
3288 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3290   int wave_height = 3, wave_length = 2;
3291   int y, dx, dy, odd, xmax;
3292   NSPoint a, b;
3293   NSRect waveClip;
3295   dx = wave_length;
3296   dy = wave_height - 1;
3297   y =  s->ybase - wave_height + 3;
3298   xmax = x + width;
3300   /* Find and set clipping rectangle */
3301   waveClip = NSMakeRect (x, y, width, wave_height);
3302   [[NSGraphicsContext currentContext] saveGraphicsState];
3303   NSRectClip (waveClip);
3305   /* Draw the waves */
3306   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3307   b.x = a.x + dx;
3308   odd = (int)(a.x/dx) % 2;
3309   a.y = b.y = y + 0.5;
3311   if (odd)
3312     a.y += dy;
3313   else
3314     b.y += dy;
3316   while (a.x <= xmax)
3317     {
3318       [NSBezierPath strokeLineFromPoint:a toPoint:b];
3319       a.x = b.x, a.y = b.y;
3320       b.x += dx, b.y = y + 0.5 + odd*dy;
3321       odd = !odd;
3322     }
3324   /* Restore previous clipping rectangle(s) */
3325   [[NSGraphicsContext currentContext] restoreGraphicsState];
3330 static void
3331 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3332                          NSColor *defaultCol, CGFloat width, CGFloat x)
3333 /* --------------------------------------------------------------------------
3334    Draw underline, overline, and strike-through on glyph string s.
3335    -------------------------------------------------------------------------- */
3337   if (s->for_overlaps)
3338     return;
3340   /* Do underline. */
3341   if (face->underline_p)
3342     {
3343       if (s->face->underline_type == FACE_UNDER_WAVE)
3344         {
3345           if (face->underline_defaulted_p)
3346             [defaultCol set];
3347           else
3348             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3350           ns_draw_underwave (s, width, x);
3351         }
3352       else if (s->face->underline_type == FACE_UNDER_LINE)
3353         {
3355           NSRect r;
3356           unsigned long thickness, position;
3358           /* If the prev was underlined, match its appearance. */
3359           if (s->prev && s->prev->face->underline_p
3360               && s->prev->face->underline_type == FACE_UNDER_LINE
3361               && s->prev->underline_thickness > 0)
3362             {
3363               thickness = s->prev->underline_thickness;
3364               position = s->prev->underline_position;
3365             }
3366           else
3367             {
3368               struct font *font = font_for_underline_metrics (s);
3369               unsigned long descent = s->y + s->height - s->ybase;
3371               /* Use underline thickness of font, defaulting to 1. */
3372               thickness = (font && font->underline_thickness > 0)
3373                 ? font->underline_thickness : 1;
3375               /* Determine the offset of underlining from the baseline. */
3376               if (x_underline_at_descent_line)
3377                 position = descent - thickness;
3378               else if (x_use_underline_position_properties
3379                        && font && font->underline_position >= 0)
3380                 position = font->underline_position;
3381               else if (font)
3382                 position = lround (font->descent / 2);
3383               else
3384                 position = underline_minimum_offset;
3386               position = max (position, underline_minimum_offset);
3388               /* Ensure underlining is not cropped. */
3389               if (descent <= position)
3390                 {
3391                   position = descent - 1;
3392                   thickness = 1;
3393                 }
3394               else if (descent < position + thickness)
3395                 thickness = 1;
3396             }
3398           s->underline_thickness = thickness;
3399           s->underline_position = position;
3401           r = NSMakeRect (x, s->ybase + position, width, thickness);
3403           if (face->underline_defaulted_p)
3404             [defaultCol set];
3405           else
3406             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3407           NSRectFill (r);
3408         }
3409     }
3410   /* Do overline. We follow other terms in using a thickness of 1
3411      and ignoring overline_margin. */
3412   if (face->overline_p)
3413     {
3414       NSRect r;
3415       r = NSMakeRect (x, s->y, width, 1);
3417       if (face->overline_color_defaulted_p)
3418         [defaultCol set];
3419       else
3420         [ns_lookup_indexed_color (face->overline_color, s->f) set];
3421       NSRectFill (r);
3422     }
3424   /* Do strike-through.  We follow other terms for thickness and
3425      vertical position.*/
3426   if (face->strike_through_p)
3427     {
3428       NSRect r;
3429       /* Y-coordinate and height of the glyph string's first glyph.
3430          We cannot use s->y and s->height because those could be
3431          larger if there are taller display elements (e.g., characters
3432          displayed with a larger font) in the same glyph row.  */
3433       int glyph_y = s->ybase - s->first_glyph->ascent;
3434       int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
3435       /* Strike-through width and offset from the glyph string's
3436          top edge.  */
3437       unsigned long h = 1;
3438       unsigned long dy;
3440       dy = lrint ((glyph_height - h) / 2);
3441       r = NSMakeRect (x, glyph_y + dy, width, 1);
3443       if (face->strike_through_color_defaulted_p)
3444         [defaultCol set];
3445       else
3446         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3447       NSRectFill (r);
3448     }
3451 static void
3452 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3453              char left_p, char right_p)
3454 /* --------------------------------------------------------------------------
3455     Draw an unfilled rect inside r, optionally leaving left and/or right open.
3456     Note we can't just use an NSDrawRect command, because of the possibility
3457     of some sides not being drawn, and because the rect will be filled.
3458    -------------------------------------------------------------------------- */
3460   NSRect s = r;
3461   [col set];
3463   /* top, bottom */
3464   s.size.height = thickness;
3465   NSRectFill (s);
3466   s.origin.y += r.size.height - thickness;
3467   NSRectFill (s);
3469   s.size.height = r.size.height;
3470   s.origin.y = r.origin.y;
3472   /* left, right (optional) */
3473   s.size.width = thickness;
3474   if (left_p)
3475     NSRectFill (s);
3476   if (right_p)
3477     {
3478       s.origin.x += r.size.width - thickness;
3479       NSRectFill (s);
3480     }
3484 static void
3485 ns_draw_relief (NSRect r, int thickness, char raised_p,
3486                char top_p, char bottom_p, char left_p, char right_p,
3487                struct glyph_string *s)
3488 /* --------------------------------------------------------------------------
3489     Draw a relief rect inside r, optionally leaving some sides open.
3490     Note we can't just use an NSDrawBezel command, because of the possibility
3491     of some sides not being drawn, and because the rect will be filled.
3492    -------------------------------------------------------------------------- */
3494   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3495   NSColor *newBaseCol = nil;
3496   NSRect sr = r;
3498   NSTRACE ("ns_draw_relief");
3500   /* set up colors */
3502   if (s->face->use_box_color_for_shadows_p)
3503     {
3504       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3505     }
3506 /*     else if (s->first_glyph->type == IMAGE_GLYPH
3507            && s->img->pixmap
3508            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3509        {
3510          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
3511        } */
3512   else
3513     {
3514       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3515     }
3517   if (newBaseCol == nil)
3518     newBaseCol = [NSColor grayColor];
3520   if (newBaseCol != baseCol)  /* TODO: better check */
3521     {
3522       [baseCol release];
3523       baseCol = [newBaseCol retain];
3524       [lightCol release];
3525       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3526       [darkCol release];
3527       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3528     }
3530   [(raised_p ? lightCol : darkCol) set];
3532   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3534   /* top */
3535   sr.size.height = thickness;
3536   if (top_p) NSRectFill (sr);
3538   /* left */
3539   sr.size.height = r.size.height;
3540   sr.size.width = thickness;
3541   if (left_p) NSRectFill (sr);
3543   [(raised_p ? darkCol : lightCol) set];
3545   /* bottom */
3546   sr.size.width = r.size.width;
3547   sr.size.height = thickness;
3548   sr.origin.y += r.size.height - thickness;
3549   if (bottom_p) NSRectFill (sr);
3551   /* right */
3552   sr.size.height = r.size.height;
3553   sr.origin.y = r.origin.y;
3554   sr.size.width = thickness;
3555   sr.origin.x += r.size.width - thickness;
3556   if (right_p) NSRectFill (sr);
3560 static void
3561 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3562 /* --------------------------------------------------------------------------
3563       Function modeled after x_draw_glyph_string_box ().
3564       Sets up parameters for drawing.
3565    -------------------------------------------------------------------------- */
3567   int right_x, last_x;
3568   char left_p, right_p;
3569   struct glyph *last_glyph;
3570   NSRect r;
3571   int thickness;
3572   struct face *face;
3574   if (s->hl == DRAW_MOUSE_FACE)
3575     {
3576       face = FACE_FROM_ID_OR_NULL (s->f,
3577                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3578       if (!face)
3579         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3580     }
3581   else
3582     face = s->face;
3584   thickness = face->box_line_width;
3586   NSTRACE ("ns_dumpglyphs_box_or_relief");
3588   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3589             ? WINDOW_RIGHT_EDGE_X (s->w)
3590             : window_box_right (s->w, s->area));
3591   last_glyph = (s->cmp || s->img
3592                 ? s->first_glyph : s->first_glyph + s->nchars-1);
3594   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3595               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3597   left_p = (s->first_glyph->left_box_line_p
3598             || (s->hl == DRAW_MOUSE_FACE
3599                 && (s->prev == NULL || s->prev->hl != s->hl)));
3600   right_p = (last_glyph->right_box_line_p
3601              || (s->hl == DRAW_MOUSE_FACE
3602                  && (s->next == NULL || s->next->hl != s->hl)));
3604   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3606   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3607   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3608     {
3609       ns_draw_box (r, abs (thickness),
3610                    ns_lookup_indexed_color (face->box_color, s->f),
3611                   left_p, right_p);
3612     }
3613   else
3614     {
3615       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3616                      1, 1, left_p, right_p, s);
3617     }
3621 static void
3622 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3623 /* --------------------------------------------------------------------------
3624       Modeled after x_draw_glyph_string_background, which draws BG in
3625       certain cases.  Others are left to the text rendering routine.
3626    -------------------------------------------------------------------------- */
3628   NSTRACE ("ns_maybe_dumpglyphs_background");
3630   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3631     {
3632       int box_line_width = max (s->face->box_line_width, 0);
3633       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3634           /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3635              dimensions, since the actual glyphs might be much
3636              smaller.  So in that case we always clear the rectangle
3637              with background color.  */
3638           || FONT_TOO_HIGH (s->font)
3639           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3640         {
3641           struct face *face;
3642           if (s->hl == DRAW_MOUSE_FACE)
3643             {
3644               face
3645                 = FACE_FROM_ID_OR_NULL (s->f,
3646                                         MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3647               if (!face)
3648                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3649             }
3650           else
3651             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3652           if (!face->stipple)
3653             [(NS_FACE_BACKGROUND (face) != 0
3654               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3655               : FRAME_BACKGROUND_COLOR (s->f)) set];
3656           else
3657             {
3658               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3659               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3660             }
3662           if (s->hl != DRAW_CURSOR)
3663             {
3664               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3665                                     s->background_width,
3666                                     s->height-2*box_line_width);
3667               NSRectFill (r);
3668             }
3670           s->background_filled_p = 1;
3671         }
3672     }
3676 static void
3677 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3678 /* --------------------------------------------------------------------------
3679       Renders an image and associated borders.
3680    -------------------------------------------------------------------------- */
3682   EmacsImage *img = s->img->pixmap;
3683   int box_line_vwidth = max (s->face->box_line_width, 0);
3684   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3685   int bg_x, bg_y, bg_height;
3686   int th;
3687   char raised_p;
3688   NSRect br;
3689   struct face *face;
3690   NSColor *tdCol;
3692   NSTRACE ("ns_dumpglyphs_image");
3694   if (s->face->box != FACE_NO_BOX
3695       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3696     x += abs (s->face->box_line_width);
3698   bg_x = x;
3699   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3700   bg_height = s->height;
3701   /* other terms have this, but was causing problems w/tabbar mode */
3702   /* - 2 * box_line_vwidth; */
3704   if (s->slice.x == 0) x += s->img->hmargin;
3705   if (s->slice.y == 0) y += s->img->vmargin;
3707   /* Draw BG: if we need larger area than image itself cleared, do that,
3708      otherwise, since we composite the image under NS (instead of mucking
3709      with its background color), we must clear just the image area. */
3710   if (s->hl == DRAW_MOUSE_FACE)
3711     {
3712       face = FACE_FROM_ID_OR_NULL (s->f,
3713                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3714       if (!face)
3715        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3716     }
3717   else
3718     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3720   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3722   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3723       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3724     {
3725       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3726       s->background_filled_p = 1;
3727     }
3728   else
3729     {
3730       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3731     }
3733   NSRectFill (br);
3735   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3736   if (img != nil)
3737     {
3738 #ifdef NS_IMPL_COCOA
3739       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3740       NSRect ir = NSMakeRect (s->slice.x,
3741                               s->img->height - s->slice.y - s->slice.height,
3742                               s->slice.width, s->slice.height);
3743       [img drawInRect: dr
3744              fromRect: ir
3745              operation: NSCompositingOperationSourceOver
3746               fraction: 1.0
3747            respectFlipped: YES
3748                 hints: nil];
3749 #else
3750       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3751                   operation: NSCompositingOperationSourceOver];
3752 #endif
3753     }
3755   if (s->hl == DRAW_CURSOR)
3756     {
3757     [FRAME_CURSOR_COLOR (s->f) set];
3758     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3759       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3760     else
3761       /* Currently on NS img->mask is always 0. Since
3762          get_window_cursor_type specifies a hollow box cursor when on
3763          a non-masked image we never reach this clause. But we put it
3764          in, in anticipation of better support for image masks on
3765          NS. */
3766       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3767     }
3768   else
3769     {
3770       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3771     }
3773   /* Draw underline, overline, strike-through. */
3774   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3776   /* Draw relief, if requested */
3777   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3778     {
3779       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3780         {
3781           th = tool_bar_button_relief >= 0 ?
3782             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3783           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3784         }
3785       else
3786         {
3787           th = abs (s->img->relief);
3788           raised_p = (s->img->relief > 0);
3789         }
3791       r.origin.x = x - th;
3792       r.origin.y = y - th;
3793       r.size.width = s->slice.width + 2*th-1;
3794       r.size.height = s->slice.height + 2*th-1;
3795       ns_draw_relief (r, th, raised_p,
3796                       s->slice.y == 0,
3797                       s->slice.y + s->slice.height == s->img->height,
3798                       s->slice.x == 0,
3799                       s->slice.x + s->slice.width == s->img->width, s);
3800     }
3802   /* If there is no mask, the background won't be seen,
3803      so draw a rectangle on the image for the cursor.
3804      Do this for all images, getting transparency right is not reliable.  */
3805   if (s->hl == DRAW_CURSOR)
3806     {
3807       int thickness = abs (s->img->relief);
3808       if (thickness == 0) thickness = 1;
3809       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3810     }
3814 static void
3815 ns_dumpglyphs_stretch (struct glyph_string *s)
3817   NSRect r[2];
3818   int n, i;
3819   struct face *face;
3820   NSColor *fgCol, *bgCol;
3822   if (!s->background_filled_p)
3823     {
3824       n = ns_get_glyph_string_clip_rect (s, r);
3825       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3827       ns_focus (s->f, r, n);
3829       if (s->hl == DRAW_MOUSE_FACE)
3830        {
3831          face = FACE_FROM_ID_OR_NULL (s->f,
3832                                       MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3833          if (!face)
3834            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3835        }
3836       else
3837        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3839       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3840       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3842       for (i = 0; i < n; ++i)
3843         {
3844           if (!s->row->full_width_p)
3845             {
3846               int overrun, leftoverrun;
3848               /* truncate to avoid overwriting fringe and/or scrollbar */
3849               overrun = max (0, (s->x + s->background_width)
3850                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3851                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3852               r[i].size.width -= overrun;
3854               /* truncate to avoid overwriting to left of the window box */
3855               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3856                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3858               if (leftoverrun > 0)
3859                 {
3860                   r[i].origin.x += leftoverrun;
3861                   r[i].size.width -= leftoverrun;
3862                 }
3864               /* XXX: Try to work between problem where a stretch glyph on
3865                  a partially-visible bottom row will clear part of the
3866                  modeline, and another where list-buffers headers and similar
3867                  rows erroneously have visible_height set to 0.  Not sure
3868                  where this is coming from as other terms seem not to show. */
3869               r[i].size.height = min (s->height, s->row->visible_height);
3870             }
3872           [bgCol set];
3874           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3875              overwriting cursor (usually when cursor on a tab) */
3876           if (s->hl == DRAW_CURSOR)
3877             {
3878               CGFloat x, width;
3880               x = r[i].origin.x;
3881               width = s->w->phys_cursor_width;
3882               r[i].size.width -= width;
3883               r[i].origin.x += width;
3885               NSRectFill (r[i]);
3887               /* Draw overlining, etc. on the cursor. */
3888               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3889                 ns_draw_text_decoration (s, face, bgCol, width, x);
3890               else
3891                 ns_draw_text_decoration (s, face, fgCol, width, x);
3892             }
3893           else
3894             {
3895               NSRectFill (r[i]);
3896             }
3898           /* Draw overlining, etc. on the stretch glyph (or the part
3899              of the stretch glyph after the cursor). */
3900           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3901                                    r[i].origin.x);
3902         }
3903       ns_unfocus (s->f);
3904       s->background_filled_p = 1;
3905     }
3909 static void
3910 ns_draw_glyph_string_foreground (struct glyph_string *s)
3912   int x, flags;
3913   struct font *font = s->font;
3915   /* If first glyph of S has a left box line, start drawing the text
3916      of S to the right of that box line.  */
3917   if (s->face && s->face->box != FACE_NO_BOX
3918       && s->first_glyph->left_box_line_p)
3919     x = s->x + eabs (s->face->box_line_width);
3920   else
3921     x = s->x;
3923   flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3924     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3925      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3926       NS_DUMPGLYPH_NORMAL));
3928   font->driver->draw
3929     (s, s->cmp_from, s->nchars, x, s->ybase,
3930      (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3931      || flags == NS_DUMPGLYPH_MOUSEFACE);
3935 static void
3936 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3938   int i, j, x;
3939   struct font *font = s->font;
3941   /* If first glyph of S has a left box line, start drawing the text
3942      of S to the right of that box line.  */
3943   if (s->face && s->face->box != FACE_NO_BOX
3944       && s->first_glyph->left_box_line_p)
3945     x = s->x + eabs (s->face->box_line_width);
3946   else
3947     x = s->x;
3949   /* S is a glyph string for a composition.  S->cmp_from is the index
3950      of the first character drawn for glyphs of this composition.
3951      S->cmp_from == 0 means we are drawing the very first character of
3952      this composition.  */
3954   /* Draw a rectangle for the composition if the font for the very
3955      first character of the composition could not be loaded.  */
3956   if (s->font_not_found_p)
3957     {
3958       if (s->cmp_from == 0)
3959         {
3960           NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3961           ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3962         }
3963     }
3964   else if (! s->first_glyph->u.cmp.automatic)
3965     {
3966       int y = s->ybase;
3968       for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3969         /* TAB in a composition means display glyphs with padding
3970            space on the left or right.  */
3971         if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3972           {
3973             int xx = x + s->cmp->offsets[j * 2];
3974             int yy = y - s->cmp->offsets[j * 2 + 1];
3976             font->driver->draw (s, j, j + 1, xx, yy, false);
3977             if (s->face->overstrike)
3978               font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3979           }
3980     }
3981   else
3982     {
3983       Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3984       Lisp_Object glyph;
3985       int y = s->ybase;
3986       int width = 0;
3988       for (i = j = s->cmp_from; i < s->cmp_to; i++)
3989         {
3990           glyph = LGSTRING_GLYPH (gstring, i);
3991           if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3992             width += LGLYPH_WIDTH (glyph);
3993           else
3994             {
3995               int xoff, yoff, wadjust;
3997               if (j < i)
3998                 {
3999                   font->driver->draw (s, j, i, x, y, false);
4000                   if (s->face->overstrike)
4001                     font->driver->draw (s, j, i, x + 1, y, false);
4002                   x += width;
4003                 }
4004               xoff = LGLYPH_XOFF (glyph);
4005               yoff = LGLYPH_YOFF (glyph);
4006               wadjust = LGLYPH_WADJUST (glyph);
4007               font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
4008               if (s->face->overstrike)
4009                 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
4010                                     false);
4011               x += wadjust;
4012               j = i + 1;
4013               width = 0;
4014             }
4015         }
4016       if (j < i)
4017         {
4018           font->driver->draw (s, j, i, x, y, false);
4019           if (s->face->overstrike)
4020             font->driver->draw (s, j, i, x + 1, y, false);
4021         }
4022     }
4025 static void
4026 ns_draw_glyph_string (struct glyph_string *s)
4027 /* --------------------------------------------------------------------------
4028       External (RIF): Main draw-text call.
4029    -------------------------------------------------------------------------- */
4031   /* TODO (optimize): focus for box and contents draw */
4032   NSRect r[2];
4033   int n;
4034   char box_drawn_p = 0;
4035   struct font *font = s->face->font;
4036   if (! font) font = FRAME_FONT (s->f);
4038   NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
4040   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
4041     {
4042       int width;
4043       struct glyph_string *next;
4045       for (width = 0, next = s->next;
4046            next && width < s->right_overhang;
4047            width += next->width, next = next->next)
4048         if (next->first_glyph->type != IMAGE_GLYPH)
4049           {
4050             if (next->first_glyph->type != STRETCH_GLYPH)
4051               {
4052                 n = ns_get_glyph_string_clip_rect (s->next, r);
4053                 ns_focus (s->f, r, n);
4054                 ns_maybe_dumpglyphs_background (s->next, 1);
4055                 ns_unfocus (s->f);
4056               }
4057             else
4058               {
4059                 ns_dumpglyphs_stretch (s->next);
4060               }
4061             next->num_clips = 0;
4062           }
4063     }
4065   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
4066         && (s->first_glyph->type == CHAR_GLYPH
4067             || s->first_glyph->type == COMPOSITE_GLYPH))
4068     {
4069       n = ns_get_glyph_string_clip_rect (s, r);
4070       ns_focus (s->f, r, n);
4071       ns_maybe_dumpglyphs_background (s, 1);
4072       ns_dumpglyphs_box_or_relief (s);
4073       ns_unfocus (s->f);
4074       box_drawn_p = 1;
4075     }
4077   switch (s->first_glyph->type)
4078     {
4080     case IMAGE_GLYPH:
4081       n = ns_get_glyph_string_clip_rect (s, r);
4082       ns_focus (s->f, r, n);
4083       ns_dumpglyphs_image (s, r[0]);
4084       ns_unfocus (s->f);
4085       break;
4087     case STRETCH_GLYPH:
4088       ns_dumpglyphs_stretch (s);
4089       break;
4091     case CHAR_GLYPH:
4092     case COMPOSITE_GLYPH:
4093       n = ns_get_glyph_string_clip_rect (s, r);
4094       ns_focus (s->f, r, n);
4096       if (s->for_overlaps || (s->cmp_from > 0
4097                               && ! s->first_glyph->u.cmp.automatic))
4098         s->background_filled_p = 1;
4099       else
4100         ns_maybe_dumpglyphs_background
4101           (s, s->first_glyph->type == COMPOSITE_GLYPH);
4103       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4104         {
4105           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4106           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4107           NS_FACE_FOREGROUND (s->face) = tmp;
4108         }
4110       {
4111         BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
4113         if (isComposite)
4114           ns_draw_composite_glyph_string_foreground (s);
4115         else
4116           ns_draw_glyph_string_foreground (s);
4117       }
4119       {
4120         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
4121                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
4122                                                    s->f)
4123                         : FRAME_FOREGROUND_COLOR (s->f));
4124         [col set];
4126         /* Draw underline, overline, strike-through. */
4127         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
4128       }
4130       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4131         {
4132           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4133           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4134           NS_FACE_FOREGROUND (s->face) = tmp;
4135         }
4137       ns_unfocus (s->f);
4138       break;
4140     case GLYPHLESS_GLYPH:
4141       n = ns_get_glyph_string_clip_rect (s, r);
4142       ns_focus (s->f, r, n);
4144       if (s->for_overlaps || (s->cmp_from > 0
4145                               && ! s->first_glyph->u.cmp.automatic))
4146         s->background_filled_p = 1;
4147       else
4148         ns_maybe_dumpglyphs_background
4149           (s, s->first_glyph->type == COMPOSITE_GLYPH);
4150       /* ... */
4151       /* Not yet implemented.  */
4152       /* ... */
4153       ns_unfocus (s->f);
4154       break;
4156     default:
4157       emacs_abort ();
4158     }
4160   /* Draw box if not done already. */
4161   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
4162     {
4163       n = ns_get_glyph_string_clip_rect (s, r);
4164       ns_focus (s->f, r, n);
4165       ns_dumpglyphs_box_or_relief (s);
4166       ns_unfocus (s->f);
4167     }
4169   s->num_clips = 0;
4174 /* ==========================================================================
4176     Event loop
4178    ========================================================================== */
4181 static void
4182 ns_send_appdefined (int value)
4183 /* --------------------------------------------------------------------------
4184     Internal: post an appdefined event which EmacsApp-sendEvent will
4185               recognize and take as a command to halt the event loop.
4186    -------------------------------------------------------------------------- */
4188   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
4190   // GNUstep needs postEvent to happen on the main thread.
4191   // Cocoa needs nextEventMatchingMask to happen on the main thread too.
4192   if (! [[NSThread currentThread] isMainThread])
4193     {
4194       EmacsApp *app = (EmacsApp *)NSApp;
4195       app->nextappdefined = value;
4196       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
4197                             withObject:nil
4198                          waitUntilDone:NO];
4199       return;
4200     }
4202   /* Only post this event if we haven't already posted one.  This will end
4203        the [NXApp run] main loop after having processed all events queued at
4204        this moment.  */
4206 #ifdef NS_IMPL_COCOA
4207   if (! send_appdefined)
4208     {
4209       /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves
4210          in certain situations (rapid incoming events).
4211          So check if we have one, if not add one.  */
4212       NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
4213                                           untilDate:[NSDate distantPast]
4214                                              inMode:NSDefaultRunLoopMode
4215                                             dequeue:NO];
4216       if (! appev) send_appdefined = YES;
4217     }
4218 #endif
4220   if (send_appdefined)
4221     {
4222       NSEvent *nxev;
4224       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
4225       send_appdefined = NO;
4227       /* Don't need wakeup timer any more */
4228       if (timed_entry)
4229         {
4230           [timed_entry invalidate];
4231           [timed_entry release];
4232           timed_entry = nil;
4233         }
4235       nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
4236                                 location: NSMakePoint (0, 0)
4237                            modifierFlags: 0
4238                                timestamp: 0
4239                             windowNumber: [[NSApp mainWindow] windowNumber]
4240                                  context: [NSApp context]
4241                                  subtype: 0
4242                                    data1: value
4243                                    data2: 0];
4245       /* Post an application defined event on the event queue.  When this is
4246          received the [NXApp run] will return, thus having processed all
4247          events which are currently queued.  */
4248       [NSApp postEvent: nxev atStart: NO];
4249     }
4252 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4253 static void
4254 check_native_fs ()
4256   Lisp_Object frame, tail;
4258   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
4259     return;
4261   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
4263   FOR_EACH_FRAME (tail, frame)
4264     {
4265       struct frame *f = XFRAME (frame);
4266       if (FRAME_NS_P (f))
4267         {
4268           EmacsView *view = FRAME_NS_VIEW (f);
4269           [view updateCollectionBehavior];
4270         }
4271     }
4273 #endif
4275 /* GNUstep does not have cancelTracking.  */
4276 #ifdef NS_IMPL_COCOA
4277 /* Check if menu open should be canceled or continued as normal.  */
4278 void
4279 ns_check_menu_open (NSMenu *menu)
4281   /* Click in menu bar? */
4282   NSArray *a = [[NSApp mainMenu] itemArray];
4283   int i;
4284   BOOL found = NO;
4286   if (menu == nil) // Menu tracking ended.
4287     {
4288       if (menu_will_open_state == MENU_OPENING)
4289         menu_will_open_state = MENU_NONE;
4290       return;
4291     }
4293   for (i = 0; ! found && i < [a count]; i++)
4294     found = menu == [[a objectAtIndex:i] submenu];
4295   if (found)
4296     {
4297       if (menu_will_open_state == MENU_NONE && emacs_event)
4298         {
4299           NSEvent *theEvent = [NSApp currentEvent];
4300           struct frame *emacsframe = SELECTED_FRAME ();
4302           [menu cancelTracking];
4303           menu_will_open_state = MENU_PENDING;
4304           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4305           EV_TRAILER (theEvent);
4307           CGEventRef ourEvent = CGEventCreate (NULL);
4308           menu_mouse_point = CGEventGetLocation (ourEvent);
4309           CFRelease (ourEvent);
4310         }
4311       else if (menu_will_open_state == MENU_OPENING)
4312         {
4313           menu_will_open_state = MENU_NONE;
4314         }
4315     }
4318 /* Redo saved menu click if state is MENU_PENDING.  */
4319 void
4320 ns_check_pending_open_menu ()
4322   if (menu_will_open_state == MENU_PENDING)
4323     {
4324       CGEventSourceRef source
4325         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4327       CGEventRef event = CGEventCreateMouseEvent (source,
4328                                                   kCGEventLeftMouseDown,
4329                                                   menu_mouse_point,
4330                                                   kCGMouseButtonLeft);
4331       CGEventSetType (event, kCGEventLeftMouseDown);
4332       CGEventPost (kCGHIDEventTap, event);
4333       CFRelease (event);
4334       CFRelease (source);
4336       menu_will_open_state = MENU_OPENING;
4337     }
4339 #endif /* NS_IMPL_COCOA */
4341 static int
4342 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4343 /* --------------------------------------------------------------------------
4344      External (hook): Post an event to ourself and keep reading events until
4345      we read it back again.  In effect process all events which were waiting.
4346      From 21+ we have to manage the event buffer ourselves.
4347    -------------------------------------------------------------------------- */
4349   struct input_event ev;
4350   int nevents;
4352   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4354 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4355   check_native_fs ();
4356 #endif
4358   if ([NSApp modalWindow] != nil)
4359     return -1;
4361   if (hold_event_q.nr > 0)
4362     {
4363       int i;
4364       for (i = 0; i < hold_event_q.nr; ++i)
4365         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4366       hold_event_q.nr = 0;
4367       return i;
4368     }
4370   if ([NSThread isMainThread])
4371     {
4372       block_input ();
4373       n_emacs_events_pending = 0;
4374       ns_init_events (&ev);
4375       q_event_ptr = hold_quit;
4377       /* we manage autorelease pools by allocate/reallocate each time around
4378          the loop; strict nesting is occasionally violated but seems not to
4379          matter.. earlier methods using full nesting caused major memory leaks */
4380       [outerpool release];
4381       outerpool = [[NSAutoreleasePool alloc] init];
4383       /* If have pending open-file requests, attend to the next one of those. */
4384       if (ns_pending_files && [ns_pending_files count] != 0
4385           && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4386         {
4387           [ns_pending_files removeObjectAtIndex: 0];
4388         }
4389       /* Deal with pending service requests. */
4390       else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4391                && [(EmacsApp *)
4392                     NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4393                                  withArg: [ns_pending_service_args objectAtIndex: 0]])
4394         {
4395           [ns_pending_service_names removeObjectAtIndex: 0];
4396           [ns_pending_service_args removeObjectAtIndex: 0];
4397         }
4398       else
4399         {
4400           /* Run and wait for events.  We must always send one NX_APPDEFINED event
4401              to ourself, otherwise [NXApp run] will never exit.  */
4402           send_appdefined = YES;
4403           ns_send_appdefined (-1);
4405           [NSApp run];
4406         }
4408       nevents = n_emacs_events_pending;
4409       n_emacs_events_pending = 0;
4410       ns_finish_events ();
4411       q_event_ptr = NULL;
4412       unblock_input ();
4413     }
4414   else
4415     return -1;
4417   return nevents;
4422 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4423            fd_set *exceptfds, struct timespec *timeout,
4424            sigset_t *sigmask)
4425 /* --------------------------------------------------------------------------
4426      Replacement for select, checking for events
4427    -------------------------------------------------------------------------- */
4429   int result;
4430   int t, k, nr = 0;
4431   struct input_event event;
4432   char c;
4434   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4436 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4437   check_native_fs ();
4438 #endif
4440   if (hold_event_q.nr > 0)
4441     {
4442       /* We already have events pending. */
4443       raise (SIGIO);
4444       errno = EINTR;
4445       return -1;
4446     }
4448   for (k = 0; k < nfds+1; k++)
4449     {
4450       if (readfds && FD_ISSET(k, readfds)) ++nr;
4451       if (writefds && FD_ISSET(k, writefds)) ++nr;
4452     }
4454   if (NSApp == nil
4455       || ![NSThread isMainThread]
4456       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4457     return thread_select(pselect, nfds, readfds, writefds,
4458                          exceptfds, timeout, sigmask);
4459   else
4460     {
4461       struct timespec t = {0, 0};
4462       thread_select(pselect, 0, NULL, NULL, NULL, &t, sigmask);
4463     }
4465   [outerpool release];
4466   outerpool = [[NSAutoreleasePool alloc] init];
4469   send_appdefined = YES;
4470   if (nr > 0)
4471     {
4472       pthread_mutex_lock (&select_mutex);
4473       select_nfds = nfds;
4474       select_valid = 0;
4475       if (readfds)
4476         {
4477           select_readfds = *readfds;
4478           select_valid += SELECT_HAVE_READ;
4479         }
4480       if (writefds)
4481         {
4482           select_writefds = *writefds;
4483           select_valid += SELECT_HAVE_WRITE;
4484         }
4486       if (timeout)
4487         {
4488           select_timeout = *timeout;
4489           select_valid += SELECT_HAVE_TMO;
4490         }
4492       pthread_mutex_unlock (&select_mutex);
4494       /* Inform fd_handler that select should be called */
4495       c = 'g';
4496       emacs_write_sig (selfds[1], &c, 1);
4497     }
4498   else if (nr == 0 && timeout)
4499     {
4500       /* No file descriptor, just a timeout, no need to wake fd_handler  */
4501       double time = timespectod (*timeout);
4502       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4503                                                       target: NSApp
4504                                                     selector:
4505                                   @selector (timeout_handler:)
4506                                                     userInfo: 0
4507                                                      repeats: NO]
4508                       retain];
4509     }
4510   else /* No timeout and no file descriptors, can this happen?  */
4511     {
4512       /* Send appdefined so we exit from the loop */
4513       ns_send_appdefined (-1);
4514     }
4516   block_input ();
4517   ns_init_events (&event);
4519   [NSApp run];
4521   ns_finish_events ();
4522   if (nr > 0 && readfds)
4523     {
4524       c = 's';
4525       emacs_write_sig (selfds[1], &c, 1);
4526     }
4527   unblock_input ();
4529   t = last_appdefined_event_data;
4531   if (t != NO_APPDEFINED_DATA)
4532     {
4533       last_appdefined_event_data = NO_APPDEFINED_DATA;
4535       if (t == -2)
4536         {
4537           /* The NX_APPDEFINED event we received was a timeout. */
4538           result = 0;
4539         }
4540       else if (t == -1)
4541         {
4542           /* The NX_APPDEFINED event we received was the result of
4543              at least one real input event arriving.  */
4544           errno = EINTR;
4545           result = -1;
4546         }
4547       else
4548         {
4549           /* Received back from select () in fd_handler; copy the results */
4550           pthread_mutex_lock (&select_mutex);
4551           if (readfds) *readfds = select_readfds;
4552           if (writefds) *writefds = select_writefds;
4553           pthread_mutex_unlock (&select_mutex);
4554           result = t;
4555         }
4556     }
4557   else
4558     {
4559       errno = EINTR;
4560       result = -1;
4561     }
4563   return result;
4566 #ifdef HAVE_PTHREAD
4567 void
4568 ns_run_loop_break ()
4569 /* Break out of the NS run loop in ns_select or ns_read_socket. */
4571   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_run_loop_break");
4573   /* If we don't have a GUI, don't send the event. */
4574   if (NSApp != NULL)
4575     ns_send_appdefined(-1);
4577 #endif
4580 /* ==========================================================================
4582     Scrollbar handling
4584    ========================================================================== */
4587 static void
4588 ns_set_vertical_scroll_bar (struct window *window,
4589                            int portion, int whole, int position)
4590 /* --------------------------------------------------------------------------
4591       External (hook): Update or add scrollbar
4592    -------------------------------------------------------------------------- */
4594   Lisp_Object win;
4595   NSRect r, v;
4596   struct frame *f = XFRAME (WINDOW_FRAME (window));
4597   EmacsView *view = FRAME_NS_VIEW (f);
4598   EmacsScroller *bar;
4599   int window_y, window_height;
4600   int top, left, height, width;
4601   BOOL update_p = YES;
4603   /* optimization; display engine sends WAY too many of these.. */
4604   if (!NILP (window->vertical_scroll_bar))
4605     {
4606       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4607       if ([bar checkSamePosition: position portion: portion whole: whole])
4608         {
4609           if (view->scrollbarsNeedingUpdate == 0)
4610             {
4611               if (!windows_or_buffers_changed)
4612                   return;
4613             }
4614           else
4615             view->scrollbarsNeedingUpdate--;
4616           update_p = NO;
4617         }
4618     }
4620   NSTRACE ("ns_set_vertical_scroll_bar");
4622   /* Get dimensions.  */
4623   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4624   top = window_y;
4625   height = window_height;
4626   width = NS_SCROLL_BAR_WIDTH (f);
4627   left = WINDOW_SCROLL_BAR_AREA_X (window);
4629   r = NSMakeRect (left, top, width, height);
4630   /* the parent view is flipped, so we need to flip y value */
4631   v = [view frame];
4632   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4634   XSETWINDOW (win, window);
4635   block_input ();
4637   /* we want at least 5 lines to display a scrollbar */
4638   if (WINDOW_TOTAL_LINES (window) < 5)
4639     {
4640       if (!NILP (window->vertical_scroll_bar))
4641         {
4642           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4643           [bar removeFromSuperview];
4644           wset_vertical_scroll_bar (window, Qnil);
4645           [bar release];
4646         }
4647       ns_clear_frame_area (f, left, top, width, height);
4648       unblock_input ();
4649       return;
4650     }
4652   if (NILP (window->vertical_scroll_bar))
4653     {
4654       if (width > 0 && height > 0)
4655         ns_clear_frame_area (f, left, top, width, height);
4657       bar = [[EmacsScroller alloc] initFrame: r window: win];
4658       wset_vertical_scroll_bar (window, make_save_ptr (bar));
4659       update_p = YES;
4660     }
4661   else
4662     {
4663       NSRect oldRect;
4664       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4665       oldRect = [bar frame];
4666       r.size.width = oldRect.size.width;
4667       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4668         {
4669           if (oldRect.origin.x != r.origin.x)
4670               ns_clear_frame_area (f, left, top, width, height);
4671           [bar setFrame: r];
4672         }
4673     }
4675   if (update_p)
4676     [bar setPosition: position portion: portion whole: whole];
4677   unblock_input ();
4681 static void
4682 ns_set_horizontal_scroll_bar (struct window *window,
4683                               int portion, int whole, int position)
4684 /* --------------------------------------------------------------------------
4685       External (hook): Update or add scrollbar
4686    -------------------------------------------------------------------------- */
4688   Lisp_Object win;
4689   NSRect r, v;
4690   struct frame *f = XFRAME (WINDOW_FRAME (window));
4691   EmacsView *view = FRAME_NS_VIEW (f);
4692   EmacsScroller *bar;
4693   int top, height, left, width;
4694   int window_x, window_width;
4695   BOOL update_p = YES;
4697   /* optimization; display engine sends WAY too many of these.. */
4698   if (!NILP (window->horizontal_scroll_bar))
4699     {
4700       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4701       if ([bar checkSamePosition: position portion: portion whole: whole])
4702         {
4703           if (view->scrollbarsNeedingUpdate == 0)
4704             {
4705               if (!windows_or_buffers_changed)
4706                   return;
4707             }
4708           else
4709             view->scrollbarsNeedingUpdate--;
4710           update_p = NO;
4711         }
4712     }
4714   NSTRACE ("ns_set_horizontal_scroll_bar");
4716   /* Get dimensions.  */
4717   window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4718   left = window_x;
4719   width = window_width;
4720   height = NS_SCROLL_BAR_HEIGHT (f);
4721   top = WINDOW_SCROLL_BAR_AREA_Y (window);
4723   r = NSMakeRect (left, top, width, height);
4724   /* the parent view is flipped, so we need to flip y value */
4725   v = [view frame];
4726   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4728   XSETWINDOW (win, window);
4729   block_input ();
4731   if (NILP (window->horizontal_scroll_bar))
4732     {
4733       if (width > 0 && height > 0)
4734         ns_clear_frame_area (f, left, top, width, height);
4736       bar = [[EmacsScroller alloc] initFrame: r window: win];
4737       wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4738       update_p = YES;
4739     }
4740   else
4741     {
4742       NSRect oldRect;
4743       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4744       oldRect = [bar frame];
4745       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4746         {
4747           if (oldRect.origin.y != r.origin.y)
4748             ns_clear_frame_area (f, left, top, width, height);
4749           [bar setFrame: r];
4750           update_p = YES;
4751         }
4752     }
4754   /* If there are both horizontal and vertical scroll-bars they leave
4755      a square that belongs to neither. We need to clear it otherwise
4756      it fills with junk. */
4757   if (!NILP (window->vertical_scroll_bar))
4758     ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4759                          NS_SCROLL_BAR_HEIGHT (f), height);
4761   if (update_p)
4762     [bar setPosition: position portion: portion whole: whole];
4763   unblock_input ();
4767 static void
4768 ns_condemn_scroll_bars (struct frame *f)
4769 /* --------------------------------------------------------------------------
4770      External (hook): arrange for all frame's scrollbars to be removed
4771      at next call to judge_scroll_bars, except for those redeemed.
4772    -------------------------------------------------------------------------- */
4774   int i;
4775   id view;
4776   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4778   NSTRACE ("ns_condemn_scroll_bars");
4780   for (i =[subviews count]-1; i >= 0; i--)
4781     {
4782       view = [subviews objectAtIndex: i];
4783       if ([view isKindOfClass: [EmacsScroller class]])
4784         [view condemn];
4785     }
4789 static void
4790 ns_redeem_scroll_bar (struct window *window)
4791 /* --------------------------------------------------------------------------
4792      External (hook): arrange to spare this window's scrollbar
4793      at next call to judge_scroll_bars.
4794    -------------------------------------------------------------------------- */
4796   id bar;
4797   NSTRACE ("ns_redeem_scroll_bar");
4798   if (!NILP (window->vertical_scroll_bar)
4799       && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4800     {
4801       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4802       [bar reprieve];
4803     }
4805   if (!NILP (window->horizontal_scroll_bar)
4806       && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4807     {
4808       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4809       [bar reprieve];
4810     }
4814 static void
4815 ns_judge_scroll_bars (struct frame *f)
4816 /* --------------------------------------------------------------------------
4817      External (hook): destroy all scrollbars on frame that weren't
4818      redeemed after call to condemn_scroll_bars.
4819    -------------------------------------------------------------------------- */
4821   int i;
4822   id view;
4823   EmacsView *eview = FRAME_NS_VIEW (f);
4824   NSArray *subviews = [[eview superview] subviews];
4825   BOOL removed = NO;
4827   NSTRACE ("ns_judge_scroll_bars");
4828   for (i = [subviews count]-1; i >= 0; --i)
4829     {
4830       view = [subviews objectAtIndex: i];
4831       if (![view isKindOfClass: [EmacsScroller class]]) continue;
4832       if ([view judge])
4833         removed = YES;
4834     }
4836   if (removed)
4837     [eview updateFrameSize: NO];
4840 /* ==========================================================================
4842     Initialization
4844    ========================================================================== */
4847 x_display_pixel_height (struct ns_display_info *dpyinfo)
4849   NSArray *screens = [NSScreen screens];
4850   NSEnumerator *enumerator = [screens objectEnumerator];
4851   NSScreen *screen;
4852   NSRect frame;
4854   frame = NSZeroRect;
4855   while ((screen = [enumerator nextObject]) != nil)
4856     frame = NSUnionRect (frame, [screen frame]);
4858   return NSHeight (frame);
4862 x_display_pixel_width (struct ns_display_info *dpyinfo)
4864   NSArray *screens = [NSScreen screens];
4865   NSEnumerator *enumerator = [screens objectEnumerator];
4866   NSScreen *screen;
4867   NSRect frame;
4869   frame = NSZeroRect;
4870   while ((screen = [enumerator nextObject]) != nil)
4871     frame = NSUnionRect (frame, [screen frame]);
4873   return NSWidth (frame);
4877 static Lisp_Object ns_string_to_lispmod (const char *s)
4878 /* --------------------------------------------------------------------------
4879      Convert modifier name to lisp symbol
4880    -------------------------------------------------------------------------- */
4882   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4883     return Qmeta;
4884   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4885     return Qsuper;
4886   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4887     return Qcontrol;
4888   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4889     return Qalt;
4890   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4891     return Qhyper;
4892   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4893     return Qnone;
4894   else
4895     return Qnil;
4899 static void
4900 ns_default (const char *parameter, Lisp_Object *result,
4901            Lisp_Object yesval, Lisp_Object noval,
4902            BOOL is_float, BOOL is_modstring)
4903 /* --------------------------------------------------------------------------
4904       Check a parameter value in user's preferences
4905    -------------------------------------------------------------------------- */
4907   const char *value = ns_get_defaults_value (parameter);
4909   if (value)
4910     {
4911       double f;
4912       char *pos;
4913       if (c_strcasecmp (value, "YES") == 0)
4914         *result = yesval;
4915       else if (c_strcasecmp (value, "NO") == 0)
4916         *result = noval;
4917       else if (is_float && (f = strtod (value, &pos), pos != value))
4918         *result = make_float (f);
4919       else if (is_modstring && value)
4920         *result = ns_string_to_lispmod (value);
4921       else fprintf (stderr,
4922                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4923     }
4927 static void
4928 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4929 /* --------------------------------------------------------------------------
4930       Initialize global info and storage for display.
4931    -------------------------------------------------------------------------- */
4933     NSScreen *screen = [NSScreen mainScreen];
4934     NSWindowDepth depth = [screen depth];
4936     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4937     dpyinfo->resy = 72.27;
4938     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4939                                                   NSColorSpaceFromDepth (depth)]
4940                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4941                                                  NSColorSpaceFromDepth (depth)];
4942     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4943     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4944     dpyinfo->color_table->colors = NULL;
4945     dpyinfo->root_window = 42; /* a placeholder.. */
4946     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4947     dpyinfo->n_fonts = 0;
4948     dpyinfo->smallest_font_height = 1;
4949     dpyinfo->smallest_char_width = 1;
4951     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4955 /* This and next define (many of the) public functions in this file. */
4956 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4957          with using despite presence in the "system dependent" redisplay
4958          interface.  In addition, many of the ns_ methods have code that is
4959          shared with all terms, indicating need for further refactoring. */
4960 extern frame_parm_handler ns_frame_parm_handlers[];
4961 static struct redisplay_interface ns_redisplay_interface =
4963   ns_frame_parm_handlers,
4964   x_produce_glyphs,
4965   x_write_glyphs,
4966   x_insert_glyphs,
4967   x_clear_end_of_line,
4968   ns_scroll_run,
4969   ns_after_update_window_line,
4970   ns_update_window_begin,
4971   ns_update_window_end,
4972   0, /* flush_display */
4973   x_clear_window_mouse_face,
4974   x_get_glyph_overhangs,
4975   x_fix_overlapping_area,
4976   ns_draw_fringe_bitmap,
4977   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4978   0, /* destroy_fringe_bitmap */
4979   ns_compute_glyph_string_overhangs,
4980   ns_draw_glyph_string,
4981   ns_define_frame_cursor,
4982   ns_clear_frame_area,
4983   ns_draw_window_cursor,
4984   ns_draw_vertical_window_border,
4985   ns_draw_window_divider,
4986   ns_shift_glyphs_for_insert,
4987   ns_show_hourglass,
4988   ns_hide_hourglass
4992 static void
4993 ns_delete_display (struct ns_display_info *dpyinfo)
4995   /* TODO... */
4999 /* This function is called when the last frame on a display is deleted. */
5000 static void
5001 ns_delete_terminal (struct terminal *terminal)
5003   struct ns_display_info *dpyinfo = terminal->display_info.ns;
5005   NSTRACE ("ns_delete_terminal");
5007   /* Protect against recursive calls.  delete_frame in
5008      delete_terminal calls us back when it deletes our last frame.  */
5009   if (!terminal->name)
5010     return;
5012   block_input ();
5014   x_destroy_all_bitmaps (dpyinfo);
5015   ns_delete_display (dpyinfo);
5016   unblock_input ();
5020 static struct terminal *
5021 ns_create_terminal (struct ns_display_info *dpyinfo)
5022 /* --------------------------------------------------------------------------
5023       Set up use of NS before we make the first connection.
5024    -------------------------------------------------------------------------- */
5026   struct terminal *terminal;
5028   NSTRACE ("ns_create_terminal");
5030   terminal = create_terminal (output_ns, &ns_redisplay_interface);
5032   terminal->display_info.ns = dpyinfo;
5033   dpyinfo->terminal = terminal;
5035   terminal->clear_frame_hook = ns_clear_frame;
5036   terminal->ring_bell_hook = ns_ring_bell;
5037   terminal->update_begin_hook = ns_update_begin;
5038   terminal->update_end_hook = ns_update_end;
5039   terminal->read_socket_hook = ns_read_socket;
5040   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
5041   terminal->mouse_position_hook = ns_mouse_position;
5042   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
5043   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
5044   terminal->fullscreen_hook = ns_fullscreen_hook;
5045   terminal->menu_show_hook = ns_menu_show;
5046   terminal->popup_dialog_hook = ns_popup_dialog;
5047   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
5048   terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
5049   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
5050   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
5051   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
5052   terminal->delete_frame_hook = x_destroy_window;
5053   terminal->delete_terminal_hook = ns_delete_terminal;
5054   /* Other hooks are NULL by default.  */
5056   return terminal;
5060 struct ns_display_info *
5061 ns_term_init (Lisp_Object display_name)
5062 /* --------------------------------------------------------------------------
5063      Start the Application and get things rolling.
5064    -------------------------------------------------------------------------- */
5066   struct terminal *terminal;
5067   struct ns_display_info *dpyinfo;
5068   static int ns_initialized = 0;
5069   Lisp_Object tmp;
5071   if (ns_initialized) return x_display_list;
5072   ns_initialized = 1;
5074   block_input ();
5076   NSTRACE ("ns_term_init");
5078   [outerpool release];
5079   outerpool = [[NSAutoreleasePool alloc] init];
5081   /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */
5082   /*GSDebugAllocationActive (YES); */
5083   block_input ();
5085   baud_rate = 38400;
5086   Fset_input_interrupt_mode (Qnil);
5088   if (selfds[0] == -1)
5089     {
5090       if (emacs_pipe (selfds) != 0)
5091         {
5092           fprintf (stderr, "Failed to create pipe: %s\n",
5093                    emacs_strerror (errno));
5094           emacs_abort ();
5095         }
5097       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
5098       FD_ZERO (&select_readfds);
5099       FD_ZERO (&select_writefds);
5100       pthread_mutex_init (&select_mutex, NULL);
5101     }
5103   ns_pending_files = [[NSMutableArray alloc] init];
5104   ns_pending_service_names = [[NSMutableArray alloc] init];
5105   ns_pending_service_args = [[NSMutableArray alloc] init];
5107 /* Start app and create the main menu, window, view.
5108      Needs to be here because ns_initialize_display_info () uses AppKit classes.
5109      The view will then ask the NSApp to stop and return to Emacs. */
5110   [EmacsApp sharedApplication];
5111   if (NSApp == nil)
5112     return NULL;
5113   [NSApp setDelegate: NSApp];
5115   /* Start the select thread.  */
5116   [NSThread detachNewThreadSelector:@selector (fd_handler:)
5117                            toTarget:NSApp
5118                          withObject:nil];
5120   /* debugging: log all notifications */
5121   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
5122                                          selector: @selector (logNotification:)
5123                                              name: nil object: nil]; */
5125   dpyinfo = xzalloc (sizeof *dpyinfo);
5127   ns_initialize_display_info (dpyinfo);
5128   terminal = ns_create_terminal (dpyinfo);
5130   terminal->kboard = allocate_kboard (Qns);
5131   /* Don't let the initial kboard remain current longer than necessary.
5132      That would cause problems if a file loaded on startup tries to
5133      prompt in the mini-buffer.  */
5134   if (current_kboard == initial_kboard)
5135     current_kboard = terminal->kboard;
5136   terminal->kboard->reference_count++;
5138   dpyinfo->next = x_display_list;
5139   x_display_list = dpyinfo;
5141   dpyinfo->name_list_element = Fcons (display_name, Qnil);
5143   terminal->name = xlispstrdup (display_name);
5145   unblock_input ();
5147   if (!inhibit_x_resources)
5148     {
5149       ns_default ("GSFontAntiAlias", &ns_antialias_text,
5150                  Qt, Qnil, NO, NO);
5151       tmp = Qnil;
5152       /* this is a standard variable */
5153       ns_default ("AppleAntiAliasingThreshold", &tmp,
5154                  make_float (10.0), make_float (6.0), YES, NO);
5155       ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp);
5156     }
5158   NSTRACE_MSG ("Colors");
5160   {
5161     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
5163     if ( cl == nil )
5164       {
5165         Lisp_Object color_file, color_map, color;
5166         unsigned long c;
5167         char *name;
5169         color_file = Fexpand_file_name (build_string ("rgb.txt"),
5170                          Fsymbol_value (intern ("data-directory")));
5172         color_map = Fx_load_color_file (color_file);
5173         if (NILP (color_map))
5174           fatal ("Could not read %s.\n", SDATA (color_file));
5176         cl = [[NSColorList alloc] initWithName: @"Emacs"];
5177         for ( ; CONSP (color_map); color_map = XCDR (color_map))
5178           {
5179             color = XCAR (color_map);
5180             name = SSDATA (XCAR (color));
5181             c = XINT (XCDR (color));
5182             [cl setColor:
5183                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
5184                                       green: GREEN_FROM_ULONG (c) / 255.0
5185                                        blue: BLUE_FROM_ULONG (c) / 255.0
5186                                       alpha: 1.0]
5187                   forKey: [NSString stringWithUTF8String: name]];
5188           }
5189         [cl writeToFile: nil];
5190       }
5191   }
5193   NSTRACE_MSG ("Versions");
5195   {
5196 #ifdef NS_IMPL_GNUSTEP
5197     Vwindow_system_version = build_string (gnustep_base_version);
5198 #else
5199     /*PSnextrelease (128, c); */
5200     char c[DBL_BUFSIZE_BOUND];
5201     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
5202     Vwindow_system_version = make_unibyte_string (c, len);
5203 #endif
5204   }
5206   delete_keyboard_wait_descriptor (0);
5208   ns_app_name = [[NSProcessInfo processInfo] processName];
5210   /* Set up macOS app menu */
5212   NSTRACE_MSG ("Menu init");
5214 #ifdef NS_IMPL_COCOA
5215   {
5216     NSMenu *appMenu;
5217     NSMenuItem *item;
5218     /* set up the application menu */
5219     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
5220     [svcsMenu setAutoenablesItems: NO];
5221     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
5222     [appMenu setAutoenablesItems: NO];
5223     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
5224     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
5226     [appMenu insertItemWithTitle: @"About Emacs"
5227                           action: @selector (orderFrontStandardAboutPanel:)
5228                    keyEquivalent: @""
5229                          atIndex: 0];
5230     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
5231     [appMenu insertItemWithTitle: @"Preferences..."
5232                           action: @selector (showPreferencesWindow:)
5233                    keyEquivalent: @","
5234                          atIndex: 2];
5235     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
5236     item = [appMenu insertItemWithTitle: @"Services"
5237                                  action: @selector (menuDown:)
5238                           keyEquivalent: @""
5239                                 atIndex: 4];
5240     [appMenu setSubmenu: svcsMenu forItem: item];
5241     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
5242     [appMenu insertItemWithTitle: @"Hide Emacs"
5243                           action: @selector (hide:)
5244                    keyEquivalent: @"h"
5245                          atIndex: 6];
5246     item =  [appMenu insertItemWithTitle: @"Hide Others"
5247                           action: @selector (hideOtherApplications:)
5248                    keyEquivalent: @"h"
5249                          atIndex: 7];
5250     [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption];
5251     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
5252     [appMenu insertItemWithTitle: @"Quit Emacs"
5253                           action: @selector (terminate:)
5254                    keyEquivalent: @"q"
5255                          atIndex: 9];
5257     item = [mainMenu insertItemWithTitle: ns_app_name
5258                                   action: @selector (menuDown:)
5259                            keyEquivalent: @""
5260                                  atIndex: 0];
5261     [mainMenu setSubmenu: appMenu forItem: item];
5262     [dockMenu insertItemWithTitle: @"New Frame"
5263                            action: @selector (newFrame:)
5264                     keyEquivalent: @""
5265                           atIndex: 0];
5267     [NSApp setMainMenu: mainMenu];
5268     [NSApp setAppleMenu: appMenu];
5269     [NSApp setServicesMenu: svcsMenu];
5270     /* Needed at least on Cocoa, to get dock menu to show windows */
5271     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5273     [[NSNotificationCenter defaultCenter]
5274       addObserver: mainMenu
5275          selector: @selector (trackingNotification:)
5276              name: NSMenuDidBeginTrackingNotification object: mainMenu];
5277     [[NSNotificationCenter defaultCenter]
5278       addObserver: mainMenu
5279          selector: @selector (trackingNotification:)
5280              name: NSMenuDidEndTrackingNotification object: mainMenu];
5281   }
5282 #endif /* macOS menu setup */
5284   /* Register our external input/output types, used for determining
5285      applicable services and also drag/drop eligibility. */
5287   NSTRACE_MSG ("Input/output types");
5289   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5290   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5291                       retain];
5292   ns_drag_types = [[NSArray arrayWithObjects:
5293                             NSStringPboardType,
5294                             NSTabularTextPboardType,
5295                             NSFilenamesPboardType,
5296                             NSURLPboardType, nil] retain];
5298   /* If fullscreen is in init/default-frame-alist, focus isn't set
5299      right for fullscreen windows, so set this.  */
5300   [NSApp activateIgnoringOtherApps:YES];
5302   NSTRACE_MSG ("Call NSApp run");
5304   [NSApp run];
5305   ns_do_open_file = YES;
5307 #ifdef NS_IMPL_GNUSTEP
5308   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5309      We must re-catch it so subprocess works.  */
5310   catch_child_signal ();
5311 #endif
5313   NSTRACE_MSG ("ns_term_init done");
5315   unblock_input ();
5317   return dpyinfo;
5321 void
5322 ns_term_shutdown (int sig)
5324   [[NSUserDefaults standardUserDefaults] synchronize];
5326   /* code not reached in emacs.c after this is called by shut_down_emacs: */
5327   if (STRINGP (Vauto_save_list_file_name))
5328     unlink (SSDATA (Vauto_save_list_file_name));
5330   if (sig == 0 || sig == SIGTERM)
5331     {
5332       [NSApp terminate: NSApp];
5333     }
5334   else // force a stack trace to happen
5335     {
5336       emacs_abort ();
5337     }
5341 /* ==========================================================================
5343     EmacsApp implementation
5345    ========================================================================== */
5348 @implementation EmacsApp
5350 - (id)init
5352   NSTRACE ("[EmacsApp init]");
5354   if ((self = [super init]))
5355     {
5356 #ifdef NS_IMPL_COCOA
5357       self->isFirst = YES;
5358 #endif
5359 #ifdef NS_IMPL_GNUSTEP
5360       self->applicationDidFinishLaunchingCalled = NO;
5361 #endif
5362     }
5364   return self;
5367 #ifdef NS_IMPL_COCOA
5368 - (void)run
5370   NSTRACE ("[EmacsApp run]");
5372 #ifndef NSAppKitVersionNumber10_9
5373 #define NSAppKitVersionNumber10_9 1265
5374 #endif
5376     if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5377       {
5378         [super run];
5379         return;
5380       }
5382   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5384   if (isFirst) [self finishLaunching];
5385   isFirst = NO;
5387   shouldKeepRunning = YES;
5388   do
5389     {
5390       [pool release];
5391       pool = [[NSAutoreleasePool alloc] init];
5393       NSEvent *event =
5394         [self nextEventMatchingMask:NSEventMaskAny
5395                           untilDate:[NSDate distantFuture]
5396                              inMode:NSDefaultRunLoopMode
5397                             dequeue:YES];
5399       [self sendEvent:event];
5400       [self updateWindows];
5401     } while (shouldKeepRunning);
5403   [pool release];
5406 - (void)stop: (id)sender
5408   NSTRACE ("[EmacsApp stop:]");
5410     shouldKeepRunning = NO;
5411     // Stop possible dialog also.  Noop if no dialog present.
5412     // The file dialog still leaks 7k - 10k on 10.9 though.
5413     [super stop:sender];
5415 #endif /* NS_IMPL_COCOA */
5417 - (void)logNotification: (NSNotification *)notification
5419   NSTRACE ("[EmacsApp logNotification:]");
5421   const char *name = [[notification name] UTF8String];
5422   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5423       && !strstr (name, "WindowNumber"))
5424     NSLog (@"notification: '%@'", [notification name]);
5428 - (void)sendEvent: (NSEvent *)theEvent
5429 /* --------------------------------------------------------------------------
5430      Called when NSApp is running for each event received.  Used to stop
5431      the loop when we choose, since there's no way to just run one iteration.
5432    -------------------------------------------------------------------------- */
5434   int type = [theEvent type];
5435   NSWindow *window = [theEvent window];
5437   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5438   NSTRACE_MSG ("Type: %d", type);
5440 #ifdef NS_IMPL_GNUSTEP
5441   // Keyboard events aren't propagated to file dialogs for some reason.
5442   if ([NSApp modalWindow] != nil &&
5443       (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged))
5444     {
5445       [[NSApp modalWindow] sendEvent: theEvent];
5446       return;
5447     }
5448 #endif
5450   if (represented_filename != nil && represented_frame)
5451     {
5452       NSString *fstr = represented_filename;
5453       NSView *view = FRAME_NS_VIEW (represented_frame);
5454 #ifdef NS_IMPL_COCOA
5455       /* work around a bug observed on 10.3 and later where
5456          setTitleWithRepresentedFilename does not clear out previous state
5457          if given filename does not exist */
5458       if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5459         [[view window] setRepresentedFilename: @""];
5460 #endif
5461       [[view window] setRepresentedFilename: fstr];
5462       [represented_filename release];
5463       represented_filename = nil;
5464       represented_frame = NULL;
5465     }
5467   if (type == NSEventTypeApplicationDefined)
5468     {
5469       switch ([theEvent data2])
5470         {
5471 #ifdef NS_IMPL_COCOA
5472         case NSAPP_DATA2_RUNASSCRIPT:
5473           ns_run_ascript ();
5474           [self stop: self];
5475           return;
5476 #endif
5477         case NSAPP_DATA2_RUNFILEDIALOG:
5478           ns_run_file_dialog ();
5479           [self stop: self];
5480           return;
5481         }
5482     }
5484   if (type == NSEventTypeCursorUpdate && window == nil)
5485     {
5486       fprintf (stderr, "Dropping external cursor update event.\n");
5487       return;
5488     }
5490   if (type == NSEventTypeApplicationDefined)
5491     {
5492       /* Events posted by ns_send_appdefined interrupt the run loop here.
5493          But, if a modal window is up, an appdefined can still come through,
5494          (e.g., from a makeKeyWindow event) but stopping self also stops the
5495          modal loop. Just defer it until later. */
5496       if ([NSApp modalWindow] == nil)
5497         {
5498           last_appdefined_event_data = [theEvent data1];
5499           [self stop: self];
5500         }
5501       else
5502         {
5503           send_appdefined = YES;
5504         }
5505     }
5508 #ifdef NS_IMPL_COCOA
5509   /* If no dialog and none of our frames have focus and it is a move, skip it.
5510      It is a mouse move in an auxiliary menu, i.e. on the top right on macOS,
5511      such as Wifi, sound, date or similar.
5512      This prevents "spooky" highlighting in the frame under the menu.  */
5513   if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil)
5514     {
5515       struct ns_display_info *di;
5516       BOOL has_focus = NO;
5517       for (di = x_display_list; ! has_focus && di; di = di->next)
5518         has_focus = di->x_focus_frame != 0;
5519       if (! has_focus)
5520         return;
5521     }
5522 #endif
5524   NSTRACE_UNSILENCE();
5526   [super sendEvent: theEvent];
5530 - (void)showPreferencesWindow: (id)sender
5532   struct frame *emacsframe = SELECTED_FRAME ();
5533   NSEvent *theEvent = [NSApp currentEvent];
5535   if (!emacs_event)
5536     return;
5537   emacs_event->kind = NS_NONKEY_EVENT;
5538   emacs_event->code = KEY_NS_SHOW_PREFS;
5539   emacs_event->modifiers = 0;
5540   EV_TRAILER (theEvent);
5544 - (void)newFrame: (id)sender
5546   NSTRACE ("[EmacsApp newFrame:]");
5548   struct frame *emacsframe = SELECTED_FRAME ();
5549   NSEvent *theEvent = [NSApp currentEvent];
5551   if (!emacs_event)
5552     return;
5553   emacs_event->kind = NS_NONKEY_EVENT;
5554   emacs_event->code = KEY_NS_NEW_FRAME;
5555   emacs_event->modifiers = 0;
5556   EV_TRAILER (theEvent);
5560 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5561 - (BOOL) openFile: (NSString *)fileName
5563   NSTRACE ("[EmacsApp openFile:]");
5565   struct frame *emacsframe = SELECTED_FRAME ();
5566   NSEvent *theEvent = [NSApp currentEvent];
5568   if (!emacs_event)
5569     return NO;
5571   emacs_event->kind = NS_NONKEY_EVENT;
5572   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5573   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5574   ns_input_line = Qnil; /* can be start or cons start,end */
5575   emacs_event->modifiers =0;
5576   EV_TRAILER (theEvent);
5578   return YES;
5582 /* **************************************************************************
5584       EmacsApp delegate implementation
5586    ************************************************************************** */
5588 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5589 /* --------------------------------------------------------------------------
5590      When application is loaded, terminate event loop in ns_term_init
5591    -------------------------------------------------------------------------- */
5593   NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5595 #ifdef NS_IMPL_GNUSTEP
5596   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5597 #endif
5598   [NSApp setServicesProvider: NSApp];
5600   [self antialiasThresholdDidChange:nil];
5601 #ifdef NS_IMPL_COCOA
5602   [[NSNotificationCenter defaultCenter]
5603     addObserver:self
5604        selector:@selector(antialiasThresholdDidChange:)
5605            name:NSAntialiasThresholdChangedNotification
5606          object:nil];
5607 #endif
5609 #ifdef NS_IMPL_COCOA
5610   if ([NSApp activationPolicy] == NSApplicationActivationPolicyProhibited) {
5611     /* Set the app's activation policy to regular when we run outside
5612        of a bundle.  This is already done for us by Info.plist when we
5613        run inside a bundle. */
5614     [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
5615     [NSApp setApplicationIconImage:
5616              [EmacsImage
5617                allocInitFromFile:
5618                  build_string("icons/hicolor/128x128/apps/emacs.png")]];
5619   }
5620 #endif
5622   ns_send_appdefined (-2);
5625 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5627 #ifdef NS_IMPL_COCOA
5628   macfont_update_antialias_threshold ();
5629 #endif
5633 /* Termination sequences:
5634     C-x C-c:
5635     Cmd-Q:
5636     MenuBar | File | Exit:
5637     Select Quit from App menubar:
5638         -terminate
5639         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5640         ns_term_shutdown()
5642     Select Quit from Dock menu:
5643     Logout attempt:
5644         -appShouldTerminate
5645           Cancel -> Nothing else
5646           Accept ->
5648           -terminate
5649           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5650           ns_term_shutdown()
5654 - (void) terminate: (id)sender
5656   NSTRACE ("[EmacsApp terminate:]");
5658   struct frame *emacsframe = SELECTED_FRAME ();
5660   if (!emacs_event)
5661     return;
5663   emacs_event->kind = NS_NONKEY_EVENT;
5664   emacs_event->code = KEY_NS_POWER_OFF;
5665   emacs_event->arg = Qt; /* mark as non-key event */
5666   EV_TRAILER ((id)nil);
5669 static bool
5670 runAlertPanel(NSString *title,
5671               NSString *msgFormat,
5672               NSString *defaultButton,
5673               NSString *alternateButton)
5675 #ifdef NS_IMPL_GNUSTEP
5676   return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5677     == NSAlertDefaultReturn;
5678 #else
5679   NSAlert *alert = [[NSAlert alloc] init];
5680   [alert setAlertStyle: NSAlertStyleCritical];
5681   [alert setMessageText: msgFormat];
5682   [alert addButtonWithTitle: defaultButton];
5683   [alert addButtonWithTitle: alternateButton];
5684   NSInteger ret = [alert runModal];
5685   [alert release];
5686   return ret == NSAlertFirstButtonReturn;
5687 #endif
5691 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5693   NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5695   bool ret;
5697   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
5698     return NSTerminateNow;
5700   ret = runAlertPanel(ns_app_name,
5701                       @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
5702                       @"Save Buffers and Exit", @"Cancel");
5704   return ret ? NSTerminateNow : NSTerminateCancel;
5707 static int
5708 not_in_argv (NSString *arg)
5710   int k;
5711   const char *a = [arg UTF8String];
5712   for (k = 1; k < initial_argc; ++k)
5713     if (strcmp (a, initial_argv[k]) == 0) return 0;
5714   return 1;
5717 /*   Notification from the Workspace to open a file */
5718 - (BOOL)application: sender openFile: (NSString *)file
5720   if (ns_do_open_file || not_in_argv (file))
5721     [ns_pending_files addObject: file];
5722   return YES;
5726 /*   Open a file as a temporary file */
5727 - (BOOL)application: sender openTempFile: (NSString *)file
5729   if (ns_do_open_file || not_in_argv (file))
5730     [ns_pending_files addObject: file];
5731   return YES;
5735 /*   Notification from the Workspace to open a file noninteractively (?) */
5736 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5738   if (ns_do_open_file || not_in_argv (file))
5739     [ns_pending_files addObject: file];
5740   return YES;
5743 /*   Notification from the Workspace to open multiple files */
5744 - (void)application: sender openFiles: (NSArray *)fileList
5746   NSEnumerator *files = [fileList objectEnumerator];
5747   NSString *file;
5748   /* Don't open files from the command line unconditionally,
5749      Cocoa parses the command line wrong, --option value tries to open value
5750      if --option is the last option.  */
5751   while ((file = [files nextObject]) != nil)
5752     if (ns_do_open_file || not_in_argv (file))
5753       [ns_pending_files addObject: file];
5755   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5760 /* Handle dock menu requests.  */
5761 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5763   return dockMenu;
5767 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5768 - (void)applicationWillBecomeActive: (NSNotification *)notification
5770   NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5771   //ns_app_active=YES;
5774 - (void)applicationDidBecomeActive: (NSNotification *)notification
5776   NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5778 #ifdef NS_IMPL_GNUSTEP
5779   if (! applicationDidFinishLaunchingCalled)
5780     [self applicationDidFinishLaunching:notification];
5781 #endif
5782   //ns_app_active=YES;
5784   ns_update_auto_hide_menu_bar ();
5785   // No constraining takes place when the application is not active.
5786   ns_constrain_all_frames ();
5788 - (void)applicationDidResignActive: (NSNotification *)notification
5790   NSTRACE ("[EmacsApp applicationDidResignActive:]");
5792   //ns_app_active=NO;
5793   ns_send_appdefined (-1);
5798 /* ==========================================================================
5800     EmacsApp aux handlers for managing event loop
5802    ========================================================================== */
5805 - (void)timeout_handler: (NSTimer *)timedEntry
5806 /* --------------------------------------------------------------------------
5807      The timeout specified to ns_select has passed.
5808    -------------------------------------------------------------------------- */
5810   /*NSTRACE ("timeout_handler"); */
5811   ns_send_appdefined (-2);
5814 - (void)sendFromMainThread:(id)unused
5816   ns_send_appdefined (nextappdefined);
5819 - (void)fd_handler:(id)unused
5820 /* --------------------------------------------------------------------------
5821      Check data waiting on file descriptors and terminate if so
5822    -------------------------------------------------------------------------- */
5824   int result;
5825   int waiting = 1, nfds;
5826   char c;
5828   fd_set readfds, writefds, *wfds;
5829   struct timespec timeout, *tmo;
5830   NSAutoreleasePool *pool = nil;
5832   /* NSTRACE ("fd_handler"); */
5834   for (;;)
5835     {
5836       [pool release];
5837       pool = [[NSAutoreleasePool alloc] init];
5839       if (waiting)
5840         {
5841           fd_set fds;
5842           FD_ZERO (&fds);
5843           FD_SET (selfds[0], &fds);
5844           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5845           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5846             waiting = 0;
5847         }
5848       else
5849         {
5850           pthread_mutex_lock (&select_mutex);
5851           nfds = select_nfds;
5853           if (select_valid & SELECT_HAVE_READ)
5854             readfds = select_readfds;
5855           else
5856             FD_ZERO (&readfds);
5858           if (select_valid & SELECT_HAVE_WRITE)
5859             {
5860               writefds = select_writefds;
5861               wfds = &writefds;
5862             }
5863           else
5864             wfds = NULL;
5865           if (select_valid & SELECT_HAVE_TMO)
5866             {
5867               timeout = select_timeout;
5868               tmo = &timeout;
5869             }
5870           else
5871             tmo = NULL;
5873           pthread_mutex_unlock (&select_mutex);
5875           FD_SET (selfds[0], &readfds);
5876           if (selfds[0] >= nfds) nfds = selfds[0]+1;
5878           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5880           if (result == 0)
5881             ns_send_appdefined (-2);
5882           else if (result > 0)
5883             {
5884               if (FD_ISSET (selfds[0], &readfds))
5885                 {
5886                   if (read (selfds[0], &c, 1) == 1 && c == 's')
5887                     waiting = 1;
5888                 }
5889               else
5890                 {
5891                   pthread_mutex_lock (&select_mutex);
5892                   if (select_valid & SELECT_HAVE_READ)
5893                     select_readfds = readfds;
5894                   if (select_valid & SELECT_HAVE_WRITE)
5895                     select_writefds = writefds;
5896                   if (select_valid & SELECT_HAVE_TMO)
5897                     select_timeout = timeout;
5898                   pthread_mutex_unlock (&select_mutex);
5900                   ns_send_appdefined (result);
5901                 }
5902             }
5903           waiting = 1;
5904         }
5905     }
5910 /* ==========================================================================
5912     Service provision
5914    ========================================================================== */
5916 /* called from system: queue for next pass through event loop */
5917 - (void)requestService: (NSPasteboard *)pboard
5918               userData: (NSString *)userData
5919                  error: (NSString **)error
5921   [ns_pending_service_names addObject: userData];
5922   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5923       SSDATA (ns_string_from_pasteboard (pboard))]];
5927 /* called from ns_read_socket to clear queue */
5928 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5930   struct frame *emacsframe = SELECTED_FRAME ();
5931   NSEvent *theEvent = [NSApp currentEvent];
5933   NSTRACE ("[EmacsApp fulfillService:withArg:]");
5935   if (!emacs_event)
5936     return NO;
5938   emacs_event->kind = NS_NONKEY_EVENT;
5939   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5940   ns_input_spi_name = build_string ([name UTF8String]);
5941   ns_input_spi_arg = build_string ([arg UTF8String]);
5942   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5943   EV_TRAILER (theEvent);
5945   return YES;
5949 @end  /* EmacsApp */
5953 /* ==========================================================================
5955     EmacsView implementation
5957    ========================================================================== */
5960 @implementation EmacsView
5962 /* needed to inform when window closed from LISP */
5963 - (void) setWindowClosing: (BOOL)closing
5965   NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5967   windowClosing = closing;
5971 - (void)dealloc
5973   NSTRACE ("[EmacsView dealloc]");
5974   [toolbar release];
5975   if (fs_state == FULLSCREEN_BOTH)
5976     [nonfs_window release];
5977   [super dealloc];
5981 /* called on font panel selection */
5982 - (void)changeFont: (id)sender
5984   NSEvent *e = [[self window] currentEvent];
5985   struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID);
5986   struct font *font = face->font;
5987   id newFont;
5988   CGFloat size;
5989   NSFont *nsfont;
5991   NSTRACE ("[EmacsView changeFont:]");
5993   if (!emacs_event)
5994     return;
5996 #ifdef NS_IMPL_GNUSTEP
5997   nsfont = ((struct nsfont_info *)font)->nsfont;
5998 #endif
5999 #ifdef NS_IMPL_COCOA
6000   nsfont = (NSFont *) macfont_get_nsctfont (font);
6001 #endif
6003   if ((newFont = [sender convertFont: nsfont]))
6004     {
6005       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
6007       emacs_event->kind = NS_NONKEY_EVENT;
6008       emacs_event->modifiers = 0;
6009       emacs_event->code = KEY_NS_CHANGE_FONT;
6011       size = [newFont pointSize];
6012       ns_input_fontsize = make_number (lrint (size));
6013       ns_input_font = build_string ([[newFont familyName] UTF8String]);
6014       EV_TRAILER (e);
6015     }
6019 - (BOOL)acceptsFirstResponder
6021   NSTRACE ("[EmacsView acceptsFirstResponder]");
6022   return YES;
6026 - (void)resetCursorRects
6028   NSRect visible = [self visibleRect];
6029   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
6030   NSTRACE ("[EmacsView resetCursorRects]");
6032   if (currentCursor == nil)
6033     currentCursor = [NSCursor arrowCursor];
6035   if (!NSIsEmptyRect (visible))
6036     [self addCursorRect: visible cursor: currentCursor];
6037   [currentCursor setOnMouseEntered: YES];
6042 /*****************************************************************************/
6043 /* Keyboard handling. */
6044 #define NS_KEYLOG 0
6046 - (void)keyDown: (NSEvent *)theEvent
6048   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6049   int code;
6050   unsigned fnKeysym = 0;
6051   static NSMutableArray *nsEvArray;
6052   int left_is_none;
6053   unsigned int flags = [theEvent modifierFlags];
6055   NSTRACE ("[EmacsView keyDown:]");
6057   /* Rhapsody and macOS give up and down events for the arrow keys */
6058   if (ns_fake_keydown == YES)
6059     ns_fake_keydown = NO;
6060   else if ([theEvent type] != NSEventTypeKeyDown)
6061     return;
6063   if (!emacs_event)
6064     return;
6066  if (![[self window] isKeyWindow]
6067      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
6068      /* we must avoid an infinite loop here. */
6069      && (EmacsView *)[[theEvent window] delegate] != self)
6070    {
6071      /* XXX: There is an occasional condition in which, when Emacs display
6072          updates a different frame from the current one, and temporarily
6073          selects it, then processes some interrupt-driven input
6074          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
6075          for some reason that window has its first responder set to the NSView
6076          most recently updated (I guess), which is not the correct one. */
6077      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
6078      return;
6079    }
6081   if (nsEvArray == nil)
6082     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
6084   [NSCursor setHiddenUntilMouseMoves: YES];
6086   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
6087     {
6088       clear_mouse_face (hlinfo);
6089       hlinfo->mouse_face_hidden = 1;
6090     }
6092   if (!processingCompose)
6093     {
6094       /* When using screen sharing, no left or right information is sent,
6095          so use Left key in those cases.  */
6096       int is_left_key, is_right_key;
6098       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
6099         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
6101       /* (Carbon way: [theEvent keyCode]) */
6103       /* is it a "function key"? */
6104       /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad
6105          flag set (this is probably a bug in the OS).
6106       */
6107       if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad))
6108         {
6109           fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad);
6110         }
6111       if (fnKeysym == 0)
6112         {
6113           fnKeysym = ns_convert_key (code);
6114         }
6116       if (fnKeysym)
6117         {
6118           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
6119              because Emacs treats Delete and KP-Delete same (in simple.el). */
6120           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
6121 #ifdef NS_IMPL_GNUSTEP
6122               /*  GNUstep uses incompatible keycodes, even for those that are
6123                   supposed to be hardware independent.  Just check for delete.
6124                   Keypad delete does not have keysym 0xFFFF.
6125                   See https://savannah.gnu.org/bugs/?25395
6126               */
6127               || (fnKeysym == 0xFFFF && code == 127)
6128 #endif
6129             )
6130             code = 0xFF08; /* backspace */
6131           else
6132             code = fnKeysym;
6133         }
6135       /* are there modifiers? */
6136       emacs_event->modifiers = 0;
6138       if (flags & NSEventModifierFlagHelp)
6139           emacs_event->modifiers |= hyper_modifier;
6141       if (flags & NSEventModifierFlagShift)
6142         emacs_event->modifiers |= shift_modifier;
6144       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
6145       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
6146         || (! is_right_key && (flags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand);
6148       if (is_right_key)
6149         emacs_event->modifiers |= parse_solitary_modifier
6150           (EQ (ns_right_command_modifier, Qleft)
6151            ? ns_command_modifier
6152            : ns_right_command_modifier);
6154       if (is_left_key)
6155         {
6156           emacs_event->modifiers |= parse_solitary_modifier
6157             (ns_command_modifier);
6159           /* if super (default), take input manager's word so things like
6160              dvorak / qwerty layout work */
6161           if (EQ (ns_command_modifier, Qsuper)
6162               && !fnKeysym
6163               && [[theEvent characters] length] != 0)
6164             {
6165               /* XXX: the code we get will be unshifted, so if we have
6166                  a shift modifier, must convert ourselves */
6167               if (!(flags & NSEventModifierFlagShift))
6168                 code = [[theEvent characters] characterAtIndex: 0];
6169 #if 0
6170               /* this is ugly and also requires linking w/Carbon framework
6171                  (for LMGetKbdType) so for now leave this rare (?) case
6172                  undealt with.. in future look into CGEvent methods */
6173               else
6174                 {
6175                   long smv = GetScriptManagerVariable (smKeyScript);
6176                   Handle uchrHandle = GetResource
6177                     ('uchr', GetScriptVariable (smv, smScriptKeys));
6178                   UInt32 dummy = 0;
6179                   UCKeyTranslate ((UCKeyboardLayout *) *uchrHandle,
6180                                  [[theEvent characters] characterAtIndex: 0],
6181                                  kUCKeyActionDisplay,
6182                                  (flags & ~NSEventModifierFlagCommand) >> 8,
6183                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
6184                                  &dummy, 1, &dummy, &code);
6185                   code &= 0xFF;
6186                 }
6187 #endif
6188             }
6189         }
6191       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
6192       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
6193         || (! is_right_key && (flags & NSEventModifierFlagControl) == NSEventModifierFlagControl);
6195       if (is_right_key)
6196           emacs_event->modifiers |= parse_solitary_modifier
6197               (EQ (ns_right_control_modifier, Qleft)
6198                ? ns_control_modifier
6199                : ns_right_control_modifier);
6201       if (is_left_key)
6202         emacs_event->modifiers |= parse_solitary_modifier
6203           (ns_control_modifier);
6205       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
6206           emacs_event->modifiers |=
6207             parse_solitary_modifier (ns_function_modifier);
6209       left_is_none = NILP (ns_alternate_modifier)
6210         || EQ (ns_alternate_modifier, Qnone);
6212       is_right_key = (flags & NSRightAlternateKeyMask)
6213         == NSRightAlternateKeyMask;
6214       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
6215         || (! is_right_key
6216             && (flags & NSEventModifierFlagOption) == NSEventModifierFlagOption);
6218       if (is_right_key)
6219         {
6220           if ((NILP (ns_right_alternate_modifier)
6221                || EQ (ns_right_alternate_modifier, Qnone)
6222                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
6223               && !fnKeysym)
6224             {   /* accept pre-interp alt comb */
6225               if ([[theEvent characters] length] > 0)
6226                 code = [[theEvent characters] characterAtIndex: 0];
6227               /*HACK: clear lone shift modifier to stop next if from firing */
6228               if (emacs_event->modifiers == shift_modifier)
6229                 emacs_event->modifiers = 0;
6230             }
6231           else
6232             emacs_event->modifiers |= parse_solitary_modifier
6233               (EQ (ns_right_alternate_modifier, Qleft)
6234                ? ns_alternate_modifier
6235                : ns_right_alternate_modifier);
6236         }
6238       if (is_left_key) /* default = meta */
6239         {
6240           if (left_is_none && !fnKeysym)
6241             {   /* accept pre-interp alt comb */
6242               if ([[theEvent characters] length] > 0)
6243                 code = [[theEvent characters] characterAtIndex: 0];
6244               /*HACK: clear lone shift modifier to stop next if from firing */
6245               if (emacs_event->modifiers == shift_modifier)
6246                 emacs_event->modifiers = 0;
6247             }
6248           else
6249               emacs_event->modifiers |=
6250                 parse_solitary_modifier (ns_alternate_modifier);
6251         }
6253   if (NS_KEYLOG)
6254     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6255              (unsigned) code, fnKeysym, flags, emacs_event->modifiers);
6257       /* if it was a function key or had modifiers, pass it directly to emacs */
6258       if (fnKeysym || (emacs_event->modifiers
6259                        && (emacs_event->modifiers != shift_modifier)
6260                        && [[theEvent charactersIgnoringModifiers] length] > 0))
6261 /*[[theEvent characters] length] */
6262         {
6263           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6264           if (code < 0x20)
6265             code |= (1<<28)|(3<<16);
6266           else if (code == 0x7f)
6267             code |= (1<<28)|(3<<16);
6268           else if (!fnKeysym)
6269             emacs_event->kind = code > 0xFF
6270               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6272           emacs_event->code = code;
6273           EV_TRAILER (theEvent);
6274           processingCompose = NO;
6275           return;
6276         }
6277     }
6280   if (NS_KEYLOG && !processingCompose)
6281     fprintf (stderr, "keyDown: Begin compose sequence.\n");
6283   processingCompose = YES;
6284   [nsEvArray addObject: theEvent];
6285   [self interpretKeyEvents: nsEvArray];
6286   [nsEvArray removeObject: theEvent];
6290 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6293 /* <NSTextInput>: called when done composing;
6294    NOTE: also called when we delete over working text, followed immed.
6295          by doCommandBySelector: deleteBackward: */
6296 - (void)insertText: (id)aString
6298   int code;
6299   int len = [(NSString *)aString length];
6300   int i;
6302   NSTRACE ("[EmacsView insertText:]");
6304   if (NS_KEYLOG)
6305     NSLog (@"insertText '%@'\tlen = %d", aString, len);
6306   processingCompose = NO;
6308   if (!emacs_event)
6309     return;
6311   /* first, clear any working text */
6312   if (workingText != nil)
6313     [self deleteWorkingText];
6315   /* now insert the string as keystrokes */
6316   for (i =0; i<len; i++)
6317     {
6318       code = [aString characterAtIndex: i];
6319       /* TODO: still need this? */
6320       if (code == 0x2DC)
6321         code = '~'; /* 0x7E */
6322       if (code != 32) /* Space */
6323         emacs_event->modifiers = 0;
6324       emacs_event->kind
6325         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6326       emacs_event->code = code;
6327       EV_TRAILER ((id)nil);
6328     }
6332 /* <NSTextInput>: inserts display of composing characters */
6333 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6335   NSString *str = [aString respondsToSelector: @selector (string)] ?
6336     [aString string] : aString;
6338   NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6340   if (NS_KEYLOG)
6341     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6342            str, (unsigned long)[str length],
6343            (unsigned long)selRange.length,
6344            (unsigned long)selRange.location);
6346   if (workingText != nil)
6347     [self deleteWorkingText];
6348   if ([str length] == 0)
6349     return;
6351   if (!emacs_event)
6352     return;
6354   processingCompose = YES;
6355   workingText = [str copy];
6356   ns_working_text = build_string ([workingText UTF8String]);
6358   emacs_event->kind = NS_TEXT_EVENT;
6359   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6360   EV_TRAILER ((id)nil);
6364 /* delete display of composing characters [not in <NSTextInput>] */
6365 - (void)deleteWorkingText
6367   NSTRACE ("[EmacsView deleteWorkingText]");
6369   if (workingText == nil)
6370     return;
6371   if (NS_KEYLOG)
6372     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6373   [workingText release];
6374   workingText = nil;
6375   processingCompose = NO;
6377   if (!emacs_event)
6378     return;
6380   emacs_event->kind = NS_TEXT_EVENT;
6381   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6382   EV_TRAILER ((id)nil);
6386 - (BOOL)hasMarkedText
6388   NSTRACE ("[EmacsView hasMarkedText]");
6390   return workingText != nil;
6394 - (NSRange)markedRange
6396   NSTRACE ("[EmacsView markedRange]");
6398   NSRange rng = workingText != nil
6399     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6400   if (NS_KEYLOG)
6401     NSLog (@"markedRange request");
6402   return rng;
6406 - (void)unmarkText
6408   NSTRACE ("[EmacsView unmarkText]");
6410   if (NS_KEYLOG)
6411     NSLog (@"unmark (accept) text");
6412   [self deleteWorkingText];
6413   processingCompose = NO;
6417 /* used to position char selection windows, etc. */
6418 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6420   NSRect rect;
6421   NSPoint pt;
6422   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6424   NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6426   if (NS_KEYLOG)
6427     NSLog (@"firstRectForCharRange request");
6429   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6430   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6431   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6432   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6433                                        +FRAME_LINE_HEIGHT (emacsframe));
6435   pt = [self convertPoint: pt toView: nil];
6437 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6438 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6439   if ([[self window] respondsToSelector: @selector(convertRectToScreen:)])
6440     {
6441 #endif
6442       rect.origin = pt;
6443       rect = [(EmacsWindow *) [self window] convertRectToScreen: rect];
6444 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6445     }
6446   else
6447 #endif
6448 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6449 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
6450   || defined (NS_IMPL_GNUSTEP)
6451     {
6452       pt = [[self window] convertBaseToScreen: pt];
6453       rect.origin = pt;
6454     }
6455 #endif
6457   return rect;
6461 - (NSInteger)conversationIdentifier
6463   return (NSInteger)self;
6467 - (void)doCommandBySelector: (SEL)aSelector
6469   NSTRACE ("[EmacsView doCommandBySelector:]");
6471   if (NS_KEYLOG)
6472     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6474   processingCompose = NO;
6475   if (aSelector == @selector (deleteBackward:))
6476     {
6477       /* happens when user backspaces over an ongoing composition:
6478          throw a 'delete' into the event queue */
6479       if (!emacs_event)
6480         return;
6481       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6482       emacs_event->code = 0xFF08;
6483       EV_TRAILER ((id)nil);
6484     }
6487 - (NSArray *)validAttributesForMarkedText
6489   static NSArray *arr = nil;
6490   if (arr == nil) arr = [NSArray new];
6491  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6492   return arr;
6495 - (NSRange)selectedRange
6497   if (NS_KEYLOG)
6498     NSLog (@"selectedRange request");
6499   return NSMakeRange (NSNotFound, 0);
6502 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6503     GNUSTEP_GUI_MINOR_VERSION > 22
6504 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6505 #else
6506 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6507 #endif
6509   if (NS_KEYLOG)
6510     NSLog (@"characterIndexForPoint request");
6511   return 0;
6514 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6516   static NSAttributedString *str = nil;
6517   if (str == nil) str = [NSAttributedString new];
6518   if (NS_KEYLOG)
6519     NSLog (@"attributedSubstringFromRange request");
6520   return str;
6523 /* End <NSTextInput> impl. */
6524 /*****************************************************************************/
6527 /* This is what happens when the user presses a mouse button.  */
6528 - (void)mouseDown: (NSEvent *)theEvent
6530   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6531   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6533   NSTRACE ("[EmacsView mouseDown:]");
6535   [self deleteWorkingText];
6537   if (!emacs_event)
6538     return;
6540   dpyinfo->last_mouse_frame = emacsframe;
6541   /* appears to be needed to prevent spurious movement events generated on
6542      button clicks */
6543   emacsframe->mouse_moved = 0;
6545   if ([theEvent type] == NSEventTypeScrollWheel)
6546     {
6547 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6548 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6549       if ([theEvent respondsToSelector:@selector(hasPreciseScrollingDeltas)])
6550         {
6551 #endif
6552           /* If the input device is a touchpad or similar, use precise
6553            * scrolling deltas.  These are measured in pixels, so we
6554            * have to add them up until they exceed one line height,
6555            * then we can send a scroll wheel event.
6556            *
6557            * If the device only has coarse scrolling deltas, like a
6558            * real mousewheel, the deltas represent a ratio of whole
6559            * lines, so round up the number of lines.  This means we
6560            * always send one scroll event per click, but can still
6561            * scroll more than one line if the OS tells us to.
6562            */
6563           bool horizontal;
6564           int lines = 0;
6565           int scrollUp = NO;
6567           /* FIXME: At the top or bottom of the buffer we should
6568            * ignore momentum-phase events.  */
6569           if (! ns_use_mwheel_momentum
6570               && [theEvent momentumPhase] != NSEventPhaseNone)
6571             return;
6573           if ([theEvent hasPreciseScrollingDeltas])
6574             {
6575               static int totalDeltaX, totalDeltaY;
6576               int lineHeight;
6578               if (NUMBERP (ns_mwheel_line_height))
6579                 lineHeight = XINT (ns_mwheel_line_height);
6580               else
6581                 {
6582                   /* FIXME: Use actual line height instead of the default.  */
6583                   lineHeight = default_line_pixel_height
6584                     (XWINDOW (FRAME_SELECTED_WINDOW (emacsframe)));
6585                 }
6587               if ([theEvent phase] == NSEventPhaseBegan)
6588                 {
6589                   totalDeltaX = 0;
6590                   totalDeltaY = 0;
6591                 }
6593               totalDeltaX += [theEvent scrollingDeltaX];
6594               totalDeltaY += [theEvent scrollingDeltaY];
6596               /* Calculate the number of lines, if any, to scroll, and
6597                * reset the total delta for the direction we're NOT
6598                * scrolling so that small movements don't add up.  */
6599               if (abs (totalDeltaX) > abs (totalDeltaY)
6600                   && abs (totalDeltaX) > lineHeight)
6601                 {
6602                   horizontal = YES;
6603                   scrollUp = totalDeltaX > 0;
6605                   lines = abs (totalDeltaX / lineHeight);
6606                   totalDeltaX = totalDeltaX % lineHeight;
6607                   totalDeltaY = 0;
6608                 }
6609               else if (abs (totalDeltaY) >= abs (totalDeltaX)
6610                        && abs (totalDeltaY) > lineHeight)
6611                 {
6612                   horizontal = NO;
6613                   scrollUp = totalDeltaY > 0;
6615                   lines = abs (totalDeltaY / lineHeight);
6616                   totalDeltaY = totalDeltaY % lineHeight;
6617                   totalDeltaX = 0;
6618                 }
6620               if (lines > 1 && ! ns_use_mwheel_acceleration)
6621                 lines = 1;
6622             }
6623           else
6624             {
6625               CGFloat delta;
6627               if ([theEvent scrollingDeltaY] == 0)
6628                 {
6629                   horizontal = YES;
6630                   delta = [theEvent scrollingDeltaX];
6631                 }
6632               else
6633                 {
6634                   horizontal = NO;
6635                   delta = [theEvent scrollingDeltaY];
6636                 }
6638               lines = (ns_use_mwheel_acceleration)
6639                 ? ceil (fabs (delta)) : 1;
6641               scrollUp = delta > 0;
6642             }
6644           if (lines == 0)
6645             return;
6647           emacs_event->kind = horizontal ? HORIZ_WHEEL_EVENT : WHEEL_EVENT;
6648           emacs_event->arg = (make_number (lines));
6650           emacs_event->code = 0;
6651           emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6652             (scrollUp ? up_modifier : down_modifier);
6653 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6654         }
6655       else
6656 #endif
6657 #endif /* defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6658 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6659         {
6660           CGFloat delta = [theEvent deltaY];
6661           /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6662           if (delta == 0)
6663             {
6664               delta = [theEvent deltaX];
6665               if (delta == 0)
6666                 {
6667                   NSTRACE_MSG ("deltaIsZero");
6668                   return;
6669                 }
6670               emacs_event->kind = HORIZ_WHEEL_EVENT;
6671             }
6672           else
6673             emacs_event->kind = WHEEL_EVENT;
6675           emacs_event->code = 0;
6676           emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6677             ((delta > 0) ? up_modifier : down_modifier);
6678         }
6679 #endif
6680     }
6681   else
6682     {
6683       emacs_event->kind = MOUSE_CLICK_EVENT;
6684       emacs_event->code = EV_BUTTON (theEvent);
6685       emacs_event->modifiers = EV_MODIFIERS (theEvent)
6686                              | EV_UDMODIFIERS (theEvent);
6687     }
6689   XSETINT (emacs_event->x, lrint (p.x));
6690   XSETINT (emacs_event->y, lrint (p.y));
6691   EV_TRAILER (theEvent);
6692   return;
6696 - (void)rightMouseDown: (NSEvent *)theEvent
6698   NSTRACE ("[EmacsView rightMouseDown:]");
6699   [self mouseDown: theEvent];
6703 - (void)otherMouseDown: (NSEvent *)theEvent
6705   NSTRACE ("[EmacsView otherMouseDown:]");
6706   [self mouseDown: theEvent];
6710 - (void)mouseUp: (NSEvent *)theEvent
6712   NSTRACE ("[EmacsView mouseUp:]");
6713   [self mouseDown: theEvent];
6717 - (void)rightMouseUp: (NSEvent *)theEvent
6719   NSTRACE ("[EmacsView rightMouseUp:]");
6720   [self mouseDown: theEvent];
6724 - (void)otherMouseUp: (NSEvent *)theEvent
6726   NSTRACE ("[EmacsView otherMouseUp:]");
6727   [self mouseDown: theEvent];
6731 - (void) scrollWheel: (NSEvent *)theEvent
6733   NSTRACE ("[EmacsView scrollWheel:]");
6734   [self mouseDown: theEvent];
6738 /* Tell emacs the mouse has moved. */
6739 - (void)mouseMoved: (NSEvent *)e
6741   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6742   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6743   Lisp_Object frame;
6744   NSPoint pt;
6746   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6748   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6749   pt = [self convertPoint: [e locationInWindow] fromView: nil];
6750   dpyinfo->last_mouse_motion_x = pt.x;
6751   dpyinfo->last_mouse_motion_y = pt.y;
6753   /* update any mouse face */
6754   if (hlinfo->mouse_face_hidden)
6755     {
6756       hlinfo->mouse_face_hidden = 0;
6757       clear_mouse_face (hlinfo);
6758     }
6760   /* tooltip handling */
6761   previous_help_echo_string = help_echo_string;
6762   help_echo_string = Qnil;
6764   if (!NILP (Vmouse_autoselect_window))
6765     {
6766       NSTRACE_MSG ("mouse_autoselect_window");
6767       static Lisp_Object last_mouse_window;
6768       Lisp_Object window
6769         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6771       if (WINDOWP (window)
6772           && !EQ (window, last_mouse_window)
6773           && !EQ (window, selected_window)
6774           && (!NILP (focus_follows_mouse)
6775               || (EQ (XWINDOW (window)->frame,
6776                       XWINDOW (selected_window)->frame))))
6777         {
6778           NSTRACE_MSG ("in_window");
6779           emacs_event->kind = SELECT_WINDOW_EVENT;
6780           emacs_event->frame_or_window = window;
6781           EV_TRAILER2 (e);
6782         }
6783       /* Remember the last window where we saw the mouse.  */
6784       last_mouse_window = window;
6785     }
6787   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6788     help_echo_string = previous_help_echo_string;
6790   XSETFRAME (frame, emacsframe);
6791   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6792     {
6793       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6794          (note_mouse_highlight), which is called through the
6795          note_mouse_movement () call above */
6796       any_help_event_p = YES;
6797       gen_help_event (help_echo_string, frame, help_echo_window,
6798                       help_echo_object, help_echo_pos);
6799     }
6801   if (emacsframe->mouse_moved && send_appdefined)
6802     ns_send_appdefined (-1);
6806 - (void)mouseDragged: (NSEvent *)e
6808   NSTRACE ("[EmacsView mouseDragged:]");
6809   [self mouseMoved: e];
6813 - (void)rightMouseDragged: (NSEvent *)e
6815   NSTRACE ("[EmacsView rightMouseDragged:]");
6816   [self mouseMoved: e];
6820 - (void)otherMouseDragged: (NSEvent *)e
6822   NSTRACE ("[EmacsView otherMouseDragged:]");
6823   [self mouseMoved: e];
6827 - (BOOL)windowShouldClose: (id)sender
6829   NSEvent *e =[[self window] currentEvent];
6831   NSTRACE ("[EmacsView windowShouldClose:]");
6832   windowClosing = YES;
6833   if (!emacs_event)
6834     return NO;
6835   emacs_event->kind = DELETE_WINDOW_EVENT;
6836   emacs_event->modifiers = 0;
6837   emacs_event->code = 0;
6838   EV_TRAILER (e);
6839   /* Don't close this window, let this be done from lisp code.  */
6840   return NO;
6843 - (void) updateFrameSize: (BOOL) delay
6845   NSWindow *window = [self window];
6846   NSRect wr = [window frame];
6847   int extra = 0;
6848   int oldc = cols, oldr = rows;
6849   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6850   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6851   int neww, newh;
6853   NSTRACE ("[EmacsView updateFrameSize:]");
6854   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6855   NSTRACE_RECT ("Original frame", wr);
6856   NSTRACE_MSG  ("Original columns: %d", cols);
6857   NSTRACE_MSG  ("Original rows: %d", rows);
6859   if (! [self isFullscreen])
6860     {
6861       int toolbar_height;
6862 #ifdef NS_IMPL_GNUSTEP
6863       // GNUstep does not always update the tool bar height.  Force it.
6864       if (toolbar && [toolbar isVisible])
6865           update_frame_tool_bar (emacsframe);
6866 #endif
6868       toolbar_height = FRAME_TOOLBAR_HEIGHT (emacsframe);
6869       if (toolbar_height < 0)
6870         toolbar_height = 35;
6872       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6873         + toolbar_height;
6874     }
6876   if (wait_for_tool_bar)
6877     {
6878       /* The toolbar height is always 0 in fullscreen and undecorated
6879          frames, so don't wait for it to become available. */
6880       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0
6881           && FRAME_UNDECORATED (emacsframe) == false
6882           && ! [self isFullscreen])
6883         {
6884           NSTRACE_MSG ("Waiting for toolbar");
6885           return;
6886         }
6887       wait_for_tool_bar = NO;
6888     }
6890   neww = (int)wr.size.width - emacsframe->border_width;
6891   newh = (int)wr.size.height - extra;
6893   NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6894   NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
6895   NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
6897   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6898   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6900   if (cols < MINWIDTH)
6901     cols = MINWIDTH;
6903   if (rows < MINHEIGHT)
6904     rows = MINHEIGHT;
6906   NSTRACE_MSG ("New columns: %d", cols);
6907   NSTRACE_MSG ("New rows: %d", rows);
6909   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6910     {
6911       NSView *view = FRAME_NS_VIEW (emacsframe);
6913       change_frame_size (emacsframe,
6914                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6915                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6916                          0, delay, 0, 1);
6917       SET_FRAME_GARBAGED (emacsframe);
6918       cancel_mouse_face (emacsframe);
6920       /* The next two lines set the frame to the same size as we've
6921          already set above.  We need to do this when we switch back
6922          from non-native fullscreen, in other circumstances it appears
6923          to be a noop.  (bug#28872) */
6924       wr = NSMakeRect (0, 0, neww, newh);
6925       [view setFrame: wr];
6927       // to do: consider using [NSNotificationCenter postNotificationName:].
6928       [self windowDidMove: // Update top/left.
6929               [NSNotification notificationWithName:NSWindowDidMoveNotification
6930                                             object:[view window]]];
6931     }
6932   else
6933     {
6934       NSTRACE_MSG ("No change");
6935     }
6938 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6939 /* normalize frame to gridded text size */
6941   int extra = 0;
6943   NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6944            NSTRACE_ARG_SIZE (frameSize));
6945   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6946   NSTRACE_FSTYPE ("fs_state", fs_state);
6948   if (!FRAME_LIVE_P (emacsframe))
6949     return frameSize;
6951   if (fs_state == FULLSCREEN_MAXIMIZED
6952       && (maximized_width != (int)frameSize.width
6953           || maximized_height != (int)frameSize.height))
6954     [self setFSValue: FULLSCREEN_NONE];
6955   else if (fs_state == FULLSCREEN_WIDTH
6956            && maximized_width != (int)frameSize.width)
6957     [self setFSValue: FULLSCREEN_NONE];
6958   else if (fs_state == FULLSCREEN_HEIGHT
6959            && maximized_height != (int)frameSize.height)
6960     [self setFSValue: FULLSCREEN_NONE];
6962   if (fs_state == FULLSCREEN_NONE)
6963     maximized_width = maximized_height = -1;
6965   if (! [self isFullscreen])
6966     {
6967       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6968         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6969     }
6971   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6972   if (cols < MINWIDTH)
6973     cols = MINWIDTH;
6975   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6976                                            frameSize.height - extra);
6977   if (rows < MINHEIGHT)
6978     rows = MINHEIGHT;
6979 #ifdef NS_IMPL_COCOA
6980   {
6981     /* this sets window title to have size in it; the wm does this under GS */
6982     NSRect r = [[self window] frame];
6983     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6984       {
6985         if (old_title != 0)
6986           {
6987             xfree (old_title);
6988             old_title = 0;
6989           }
6990       }
6991     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
6992              && [[self window] title] != NULL)
6993       {
6994         char *size_title;
6995         NSWindow *window = [self window];
6996         if (old_title == 0)
6997           {
6998             char *t = strdup ([[[self window] title] UTF8String]);
6999             char *pos = strstr (t, "  â€”  ");
7000             if (pos)
7001               *pos = '\0';
7002             old_title = t;
7003           }
7004         size_title = xmalloc (strlen (old_title) + 40);
7005         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
7006         [window setTitle: [NSString stringWithUTF8String: size_title]];
7007         [window display];
7008         xfree (size_title);
7009       }
7010   }
7011 #endif /* NS_IMPL_COCOA */
7013   NSTRACE_MSG ("cols: %d  rows: %d", cols, rows);
7015   /* Restrict the new size to the text gird.
7017      Don't restrict the width if the user only adjusted the height, and
7018      vice versa.  (Without this, the frame would shrink, and move
7019      slightly, if the window was resized by dragging one of its
7020      borders.) */
7021   if (!frame_resize_pixelwise)
7022     {
7023       NSRect r = [[self window] frame];
7025       if (r.size.width != frameSize.width)
7026         {
7027           frameSize.width =
7028             FRAME_TEXT_COLS_TO_PIXEL_WIDTH  (emacsframe, cols);
7029         }
7031       if (r.size.height != frameSize.height)
7032         {
7033           frameSize.height =
7034             FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
7035         }
7036     }
7038   NSTRACE_RETURN_SIZE (frameSize);
7040   return frameSize;
7044 - (void)windowDidResize: (NSNotification *)notification
7046   NSTRACE ("[EmacsView windowDidResize:]");
7047   if (!FRAME_LIVE_P (emacsframe))
7048     {
7049       NSTRACE_MSG ("Ignored (frame dead)");
7050       return;
7051     }
7052   if (emacsframe->output_data.ns->in_animation)
7053     {
7054       NSTRACE_MSG ("Ignored (in animation)");
7055       return;
7056     }
7058   if (! [self fsIsNative])
7059     {
7060       NSWindow *theWindow = [notification object];
7061       /* We can get notification on the non-FS window when in
7062          fullscreen mode.  */
7063       if ([self window] != theWindow) return;
7064     }
7066   NSTRACE_RECT ("frame", [[notification object] frame]);
7068 #ifdef NS_IMPL_GNUSTEP
7069   NSWindow *theWindow = [notification object];
7071    /* In GNUstep, at least currently, it's possible to get a didResize
7072       without getting a willResize.. therefore we need to act as if we got
7073       the willResize now */
7074   NSSize sz = [theWindow frame].size;
7075   sz = [self windowWillResize: theWindow toSize: sz];
7076 #endif /* NS_IMPL_GNUSTEP */
7078   if (cols > 0 && rows > 0)
7079     {
7080       [self updateFrameSize: YES];
7081     }
7083   ns_send_appdefined (-1);
7086 #ifdef NS_IMPL_COCOA
7087 - (void)viewDidEndLiveResize
7089   NSTRACE ("[EmacsView viewDidEndLiveResize]");
7091   [super viewDidEndLiveResize];
7092   if (old_title != 0)
7093     {
7094       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
7095       xfree (old_title);
7096       old_title = 0;
7097     }
7098   maximizing_resize = NO;
7100 #endif /* NS_IMPL_COCOA */
7103 - (void)windowDidBecomeKey: (NSNotification *)notification
7104 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
7106   [self windowDidBecomeKey];
7110 - (void)windowDidBecomeKey      /* for direct calls */
7112   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7113   struct frame *old_focus = dpyinfo->x_focus_frame;
7115   NSTRACE ("[EmacsView windowDidBecomeKey]");
7117   if (emacsframe != old_focus)
7118     dpyinfo->x_focus_frame = emacsframe;
7120   ns_frame_rehighlight (emacsframe);
7122   if (emacs_event)
7123     {
7124       emacs_event->kind = FOCUS_IN_EVENT;
7125       EV_TRAILER ((id)nil);
7126     }
7130 - (void)windowDidResignKey: (NSNotification *)notification
7131 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
7133   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7134   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
7135   NSTRACE ("[EmacsView windowDidResignKey:]");
7137   if (is_focus_frame)
7138     dpyinfo->x_focus_frame = 0;
7140   emacsframe->mouse_moved = 0;
7141   ns_frame_rehighlight (emacsframe);
7143   /* FIXME: for some reason needed on second and subsequent clicks away
7144             from sole-frame Emacs to get hollow box to show */
7145   if (!windowClosing && [[self window] isVisible] == YES)
7146     {
7147       x_update_cursor (emacsframe, 1);
7148       x_set_frame_alpha (emacsframe);
7149     }
7151   if (any_help_event_p)
7152     {
7153       Lisp_Object frame;
7154       XSETFRAME (frame, emacsframe);
7155       help_echo_string = Qnil;
7156       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
7157     }
7159   if (emacs_event && is_focus_frame)
7160     {
7161       [self deleteWorkingText];
7162       emacs_event->kind = FOCUS_OUT_EVENT;
7163       EV_TRAILER ((id)nil);
7164     }
7168 - (void)windowWillMiniaturize: sender
7170   NSTRACE ("[EmacsView windowWillMiniaturize:]");
7174 - (void)setFrame:(NSRect)frameRect
7176   NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
7177            NSTRACE_ARG_RECT (frameRect));
7179   [super setFrame:(NSRect)frameRect];
7183 - (BOOL)isFlipped
7185   return YES;
7189 - (BOOL)isOpaque
7191   return NO;
7195 - (void)createToolbar: (struct frame *)f
7197   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
7198   NSWindow *window = [view window];
7200   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
7201                    [NSString stringWithFormat: @"Emacs Frame %d",
7202                              ns_window_num]];
7203   [toolbar setVisible: NO];
7204   [window setToolbar: toolbar];
7206   /* Don't set frame garbaged until tool bar is up to date?
7207      This avoids an extra clear and redraw (flicker) at frame creation.  */
7208   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
7209   else wait_for_tool_bar = NO;
7212 #ifdef NS_IMPL_COCOA
7213   {
7214     NSButton *toggleButton;
7215     toggleButton = [window standardWindowButton: NSWindowToolbarButton];
7216     [toggleButton setTarget: self];
7217     [toggleButton setAction: @selector (toggleToolbar: )];
7218   }
7219 #endif
7223 - (instancetype) initFrameFromEmacs: (struct frame *)f
7225   NSRect r, wr;
7226   Lisp_Object tem;
7227   NSWindow *win;
7228   NSColor *col;
7229   NSString *name;
7231   NSTRACE ("[EmacsView initFrameFromEmacs:]");
7232   NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
7234   windowClosing = NO;
7235   processingCompose = NO;
7236   scrollbarsNeedingUpdate = 0;
7237   fs_state = FULLSCREEN_NONE;
7238   fs_before_fs = next_maximized = -1;
7240   fs_is_native = NO;
7241 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7242 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7243   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7244 #endif
7245     fs_is_native = ns_use_native_fullscreen;
7246 #endif
7248   maximized_width = maximized_height = -1;
7249   nonfs_window = nil;
7251   ns_userRect = NSMakeRect (0, 0, 0, 0);
7252   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
7253                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
7254   [self initWithFrame: r];
7255   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
7257   FRAME_NS_VIEW (f) = self;
7258   emacsframe = f;
7259 #ifdef NS_IMPL_COCOA
7260   old_title = 0;
7261   maximizing_resize = NO;
7262 #endif
7264   win = [[EmacsWindow alloc]
7265             initWithContentRect: r
7266                       styleMask: (FRAME_UNDECORATED (f)
7267                                   ? FRAME_UNDECORATED_FLAGS
7268                                   : FRAME_DECORATED_FLAGS)
7269                         backing: NSBackingStoreBuffered
7270                           defer: YES];
7272 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7273 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7274   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7275 #endif
7276     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
7277 #endif
7279   wr = [win frame];
7280   bwidth = f->border_width = wr.size.width - r.size.width;
7282   [win setAcceptsMouseMovedEvents: YES];
7283   [win setDelegate: self];
7284 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7285 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7286   if ([win respondsToSelector: @selector(useOptimizedDrawing:)])
7287 #endif
7288     [win useOptimizedDrawing: YES];
7289 #endif
7291   [[win contentView] addSubview: self];
7293   if (ns_drag_types)
7294     [self registerForDraggedTypes: ns_drag_types];
7296   tem = f->name;
7297   name = [NSString stringWithUTF8String:
7298                    NILP (tem) ? "Emacs" : SSDATA (tem)];
7299   [win setTitle: name];
7301   /* toolbar support */
7302   if (! FRAME_UNDECORATED (f))
7303     [self createToolbar: f];
7305 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7306 #ifndef NSAppKitVersionNumber10_10
7307 #define NSAppKitVersionNumber10_10 1343
7308 #endif
7310   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_10
7311       && FRAME_NS_APPEARANCE (f) != ns_appearance_aqua)
7312     win.appearance = [NSAppearance
7313                           appearanceNamed: NSAppearanceNameVibrantDark];
7314 #endif
7316 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7317   if ([win respondsToSelector: @selector(titlebarAppearsTransparent)])
7318     win.titlebarAppearsTransparent = FRAME_NS_TRANSPARENT_TITLEBAR (f);
7319 #endif
7321   tem = f->icon_name;
7322   if (!NILP (tem))
7323     [win setMiniwindowTitle:
7324            [NSString stringWithUTF8String: SSDATA (tem)]];
7326   if (FRAME_PARENT_FRAME (f) != NULL)
7327     {
7328       NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
7329       [parent addChildWindow: win
7330                      ordered: NSWindowAbove];
7331     }
7333   if (FRAME_Z_GROUP (f) != z_group_none)
7334       win.level = NSNormalWindowLevel
7335         + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
7337   {
7338     NSScreen *screen = [win screen];
7340     if (screen != 0)
7341       {
7342         NSPoint pt = NSMakePoint
7343           (IN_BOUND (-SCREENMAX, f->left_pos
7344                      + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7345            IN_BOUND (-SCREENMAX,
7346                      NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7347                      SCREENMAX));
7349         [win setFrameTopLeftPoint: pt];
7351         NSTRACE_RECT ("new frame", [win frame]);
7352       }
7353   }
7355   [win makeFirstResponder: self];
7357   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7358                                  (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7359                                  emacsframe);
7360   [win setBackgroundColor: col];
7361   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7362     [win setOpaque: NO];
7364 #if !defined (NS_IMPL_COCOA) \
7365   || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7366 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7367   if ([self respondsToSelector: @selector(allocateGState)])
7368 #endif
7369     [self allocateGState];
7370 #endif
7371   [NSApp registerServicesMenuSendTypes: ns_send_types
7372                            returnTypes: [NSArray array]];
7374   /* macOS Sierra automatically enables tabbed windows.  We can't
7375      allow this to be enabled until it's available on a Free system.
7376      Currently it only happens by accident and is buggy anyway. */
7377 #if defined (NS_IMPL_COCOA) \
7378   && MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
7379 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
7380   if ([win respondsToSelector: @selector(setTabbingMode:)])
7381 #endif
7382     [win setTabbingMode: NSWindowTabbingModeDisallowed];
7383 #endif
7385   ns_window_num++;
7386   return self;
7390 - (void)windowDidMove: sender
7392   NSWindow *win = [self window];
7393   NSRect r = [win frame];
7394   NSArray *screens = [NSScreen screens];
7395   NSScreen *screen = [screens objectAtIndex: 0];
7397   NSTRACE ("[EmacsView windowDidMove:]");
7399   if (!emacsframe->output_data.ns)
7400     return;
7401   if (screen != nil)
7402     {
7403       emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7404       emacsframe->top_pos =
7405         NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7407       if (emacs_event)
7408         {
7409           emacs_event->kind = MOVE_FRAME_EVENT;
7410           EV_TRAILER ((id)nil);
7411         }
7412     }
7416 /* Called AFTER method below, but before our windowWillResize call there leads
7417    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
7418    location so set_window_size moves the frame. */
7419 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7421   NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7422             NSTRACE_FMT_RETURN "YES"),
7423            NSTRACE_ARG_RECT (newFrame));
7425   emacsframe->output_data.ns->zooming = 1;
7426   return YES;
7430 /* Override to do something slightly nonstandard, but nice.  First click on
7431    zoom button will zoom vertically.  Second will zoom completely.  Third
7432    returns to original. */
7433 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7434                         defaultFrame:(NSRect)defaultFrame
7436   // TODO: Rename to "currentFrame" and assign "result" properly in
7437   // all paths.
7438   NSRect result = [sender frame];
7440   NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7441             NSTRACE_FMT_RECT "]"),
7442            NSTRACE_ARG_RECT (defaultFrame));
7443   NSTRACE_FSTYPE ("fs_state", fs_state);
7444   NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7445   NSTRACE_FSTYPE ("next_maximized", next_maximized);
7446   NSTRACE_RECT   ("ns_userRect", ns_userRect);
7447   NSTRACE_RECT   ("[sender frame]", [sender frame]);
7449   if (fs_before_fs != -1) /* Entering fullscreen */
7450     {
7451       NSTRACE_MSG ("Entering fullscreen");
7452       result = defaultFrame;
7453     }
7454   else
7455     {
7456       // Save the window size and position (frame) before the resize.
7457       if (fs_state != FULLSCREEN_MAXIMIZED
7458           && fs_state != FULLSCREEN_WIDTH)
7459         {
7460           ns_userRect.size.width = result.size.width;
7461           ns_userRect.origin.x   = result.origin.x;
7462         }
7464       if (fs_state != FULLSCREEN_MAXIMIZED
7465           && fs_state != FULLSCREEN_HEIGHT)
7466         {
7467           ns_userRect.size.height = result.size.height;
7468           ns_userRect.origin.y    = result.origin.y;
7469         }
7471       NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7473       if (next_maximized == FULLSCREEN_HEIGHT
7474           || (next_maximized == -1
7475               && abs ((int)(defaultFrame.size.height - result.size.height))
7476               > FRAME_LINE_HEIGHT (emacsframe)))
7477         {
7478           /* first click */
7479           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7480           maximized_height = result.size.height = defaultFrame.size.height;
7481           maximized_width = -1;
7482           result.origin.y = defaultFrame.origin.y;
7483           if (ns_userRect.size.height != 0)
7484             {
7485               result.origin.x = ns_userRect.origin.x;
7486               result.size.width = ns_userRect.size.width;
7487             }
7488           [self setFSValue: FULLSCREEN_HEIGHT];
7489 #ifdef NS_IMPL_COCOA
7490           maximizing_resize = YES;
7491 #endif
7492         }
7493       else if (next_maximized == FULLSCREEN_WIDTH)
7494         {
7495           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7496           maximized_width = result.size.width = defaultFrame.size.width;
7497           maximized_height = -1;
7498           result.origin.x = defaultFrame.origin.x;
7499           if (ns_userRect.size.width != 0)
7500             {
7501               result.origin.y = ns_userRect.origin.y;
7502               result.size.height = ns_userRect.size.height;
7503             }
7504           [self setFSValue: FULLSCREEN_WIDTH];
7505         }
7506       else if (next_maximized == FULLSCREEN_MAXIMIZED
7507                || (next_maximized == -1
7508                    && abs ((int)(defaultFrame.size.width - result.size.width))
7509                    > FRAME_COLUMN_WIDTH (emacsframe)))
7510         {
7511           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7513           result = defaultFrame;  /* second click */
7514           maximized_width = result.size.width;
7515           maximized_height = result.size.height;
7516           [self setFSValue: FULLSCREEN_MAXIMIZED];
7517 #ifdef NS_IMPL_COCOA
7518           maximizing_resize = YES;
7519 #endif
7520         }
7521       else
7522         {
7523           /* restore */
7524           NSTRACE_MSG ("Restore");
7525           result = ns_userRect.size.height ? ns_userRect : result;
7526           NSTRACE_RECT ("restore (2)", result);
7527           ns_userRect = NSMakeRect (0, 0, 0, 0);
7528 #ifdef NS_IMPL_COCOA
7529           maximizing_resize = fs_state != FULLSCREEN_NONE;
7530 #endif
7531           [self setFSValue: FULLSCREEN_NONE];
7532           maximized_width = maximized_height = -1;
7533         }
7534     }
7536   if (fs_before_fs == -1) next_maximized = -1;
7538   NSTRACE_RECT   ("Final ns_userRect", ns_userRect);
7539   NSTRACE_MSG    ("Final maximized_width: %d", maximized_width);
7540   NSTRACE_MSG    ("Final maximized_height: %d", maximized_height);
7541   NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7543   [self windowWillResize: sender toSize: result.size];
7545   NSTRACE_RETURN_RECT (result);
7547   return result;
7551 - (void)windowDidDeminiaturize: sender
7553   NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7554   if (!emacsframe->output_data.ns)
7555     return;
7557   SET_FRAME_ICONIFIED (emacsframe, 0);
7558   SET_FRAME_VISIBLE (emacsframe, 1);
7559   windows_or_buffers_changed = 63;
7561   if (emacs_event)
7562     {
7563       emacs_event->kind = DEICONIFY_EVENT;
7564       EV_TRAILER ((id)nil);
7565     }
7569 - (void)windowDidExpose: sender
7571   NSTRACE ("[EmacsView windowDidExpose:]");
7572   if (!emacsframe->output_data.ns)
7573     return;
7575   SET_FRAME_VISIBLE (emacsframe, 1);
7576   SET_FRAME_GARBAGED (emacsframe);
7578   if (send_appdefined)
7579     ns_send_appdefined (-1);
7583 - (void)windowDidMiniaturize: sender
7585   NSTRACE ("[EmacsView windowDidMiniaturize:]");
7586   if (!emacsframe->output_data.ns)
7587     return;
7589   SET_FRAME_ICONIFIED (emacsframe, 1);
7590   SET_FRAME_VISIBLE (emacsframe, 0);
7592   if (emacs_event)
7593     {
7594       emacs_event->kind = ICONIFY_EVENT;
7595       EV_TRAILER ((id)nil);
7596     }
7599 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7600 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7601       willUseFullScreenPresentationOptions:
7602   (NSApplicationPresentationOptions)proposedOptions
7604   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7606 #endif
7608 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7610   NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7611   [self windowWillEnterFullScreen];
7613 - (void)windowWillEnterFullScreen /* provided for direct calls */
7615   NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7616   fs_before_fs = fs_state;
7619 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7621   NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7622   [self windowDidEnterFullScreen];
7625 - (void)windowDidEnterFullScreen /* provided for direct calls */
7627   NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7628   [self setFSValue: FULLSCREEN_BOTH];
7629   if (! [self fsIsNative])
7630     {
7631       [self windowDidBecomeKey];
7632       [nonfs_window orderOut:self];
7633     }
7634   else
7635     {
7636       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7637 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \
7638   && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
7639       unsigned val = (unsigned)[NSApp presentationOptions];
7641       // Mac OS X 10.7 bug fix, the menu won't appear without this.
7642       // val is non-zero on other macOS versions.
7643       if (val == 0)
7644         {
7645           NSApplicationPresentationOptions options
7646             = NSApplicationPresentationAutoHideDock
7647             | NSApplicationPresentationAutoHideMenuBar
7648             | NSApplicationPresentationFullScreen
7649             | NSApplicationPresentationAutoHideToolbar;
7651           [NSApp setPresentationOptions: options];
7652         }
7653 #endif
7654       [toolbar setVisible:tbar_visible];
7655     }
7658 - (void)windowWillExitFullScreen:(NSNotification *)notification
7660   NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7661   [self windowWillExitFullScreen];
7664 - (void)windowWillExitFullScreen /* provided for direct calls */
7666   NSTRACE ("[EmacsView windowWillExitFullScreen]");
7667   if (!FRAME_LIVE_P (emacsframe))
7668     {
7669       NSTRACE_MSG ("Ignored (frame dead)");
7670       return;
7671     }
7672   if (next_maximized != -1)
7673     fs_before_fs = next_maximized;
7676 - (void)windowDidExitFullScreen:(NSNotification *)notification
7678   NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7679   [self windowDidExitFullScreen];
7682 - (void)windowDidExitFullScreen /* provided for direct calls */
7684   NSTRACE ("[EmacsView windowDidExitFullScreen]");
7685   if (!FRAME_LIVE_P (emacsframe))
7686     {
7687       NSTRACE_MSG ("Ignored (frame dead)");
7688       return;
7689     }
7690   [self setFSValue: fs_before_fs];
7691   fs_before_fs = -1;
7692 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7693   [self updateCollectionBehavior];
7694 #endif
7695   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7696     {
7697       [toolbar setVisible:YES];
7698       update_frame_tool_bar (emacsframe);
7699       [self updateFrameSize:YES];
7700       [[self window] display];
7701     }
7702   else
7703     [toolbar setVisible:NO];
7705   if (next_maximized != -1)
7706     [[self window] performZoom:self];
7709 - (BOOL)fsIsNative
7711   return fs_is_native;
7714 - (BOOL)isFullscreen
7716   BOOL res;
7718   if (! fs_is_native)
7719     {
7720       res = (nonfs_window != nil);
7721     }
7722   else
7723     {
7724 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7725       res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7726 #else
7727       res = NO;
7728 #endif
7729     }
7731   NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7732            (int) res);
7734   return res;
7737 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7738 - (void)updateCollectionBehavior
7740   NSTRACE ("[EmacsView updateCollectionBehavior]");
7742   if (! [self isFullscreen])
7743     {
7744       NSWindow *win = [self window];
7745       NSWindowCollectionBehavior b = [win collectionBehavior];
7746       if (ns_use_native_fullscreen)
7747         b |= NSWindowCollectionBehaviorFullScreenPrimary;
7748       else
7749         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7751       [win setCollectionBehavior: b];
7752 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7753       if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7754 #endif
7755         fs_is_native = ns_use_native_fullscreen;
7756     }
7758 #endif
7760 - (void)toggleFullScreen: (id)sender
7762   NSWindow *w, *fw;
7763   BOOL onFirstScreen;
7764   struct frame *f;
7765   NSRect r, wr;
7766   NSColor *col;
7768   NSTRACE ("[EmacsView toggleFullScreen:]");
7770   if (fs_is_native)
7771     {
7772 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7773 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7774       if ([[self window] respondsToSelector: @selector(toggleFullScreen:)])
7775 #endif
7776         [[self window] toggleFullScreen:sender];
7777 #endif
7778       return;
7779     }
7781   w = [self window];
7782   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7783   f = emacsframe;
7784   wr = [w frame];
7785   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7786                                  (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7787                                  f);
7789   if (fs_state != FULLSCREEN_BOTH)
7790     {
7791       NSScreen *screen = [w screen];
7793 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
7794       /* Hide ghost menu bar on secondary monitor? */
7795       if (! onFirstScreen
7796 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
7797           && [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)]
7798 #endif
7799           )
7800         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7801 #endif
7802       /* Hide dock and menubar if we are on the primary screen.  */
7803       if (onFirstScreen)
7804         {
7805 #ifdef NS_IMPL_COCOA
7806           NSApplicationPresentationOptions options
7807             = NSApplicationPresentationAutoHideDock
7808             | NSApplicationPresentationAutoHideMenuBar;
7810           [NSApp setPresentationOptions: options];
7811 #else
7812           [NSMenu setMenuBarVisible:NO];
7813 #endif
7814         }
7816       fw = [[EmacsFSWindow alloc]
7817                        initWithContentRect:[w contentRectForFrameRect:wr]
7818                                  styleMask:NSWindowStyleMaskBorderless
7819                                    backing:NSBackingStoreBuffered
7820                                      defer:YES
7821                                     screen:screen];
7823       [fw setContentView:[w contentView]];
7824       [fw setTitle:[w title]];
7825       [fw setDelegate:self];
7826       [fw setAcceptsMouseMovedEvents: YES];
7827 #if !defined (NS_IMPL_COCOA) \
7828   || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7829 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7830       if ([fw respondsToSelector: @selector(useOptimizedDrawing:)])
7831 #endif
7832         [fw useOptimizedDrawing: YES];
7833 #endif
7834       [fw setBackgroundColor: col];
7835       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7836         [fw setOpaque: NO];
7838       f->border_width = 0;
7840       nonfs_window = w;
7842       [self windowWillEnterFullScreen];
7843       [fw makeKeyAndOrderFront:NSApp];
7844       [fw makeFirstResponder:self];
7845       [w orderOut:self];
7846       r = [fw frameRectForContentRect:[screen frame]];
7847       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7848       [self windowDidEnterFullScreen];
7849       [fw display];
7850     }
7851   else
7852     {
7853       fw = w;
7854       w = nonfs_window;
7855       nonfs_window = nil;
7857       if (onFirstScreen)
7858         {
7859 #ifdef NS_IMPL_COCOA
7860           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7861 #else
7862           [NSMenu setMenuBarVisible:YES];
7863 #endif
7864         }
7866       [w setContentView:[fw contentView]];
7867       [w setBackgroundColor: col];
7868       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7869         [w setOpaque: NO];
7871       f->border_width = bwidth;
7873       // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7875       [self windowWillExitFullScreen];
7876       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7877       [fw close];
7878       [w makeKeyAndOrderFront:NSApp];
7879       [self windowDidExitFullScreen];
7880       [self updateFrameSize:YES];
7881     }
7884 - (void)handleFS
7886   NSTRACE ("[EmacsView handleFS]");
7888   if (fs_state != emacsframe->want_fullscreen)
7889     {
7890       if (fs_state == FULLSCREEN_BOTH)
7891         {
7892           NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7893           [self toggleFullScreen:self];
7894         }
7896       switch (emacsframe->want_fullscreen)
7897         {
7898         case FULLSCREEN_BOTH:
7899           NSTRACE_MSG ("FULLSCREEN_BOTH");
7900           [self toggleFullScreen:self];
7901           break;
7902         case FULLSCREEN_WIDTH:
7903           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7904           next_maximized = FULLSCREEN_WIDTH;
7905           if (fs_state != FULLSCREEN_BOTH)
7906             [[self window] performZoom:self];
7907           break;
7908         case FULLSCREEN_HEIGHT:
7909           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7910           next_maximized = FULLSCREEN_HEIGHT;
7911           if (fs_state != FULLSCREEN_BOTH)
7912             [[self window] performZoom:self];
7913           break;
7914         case FULLSCREEN_MAXIMIZED:
7915           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7916           next_maximized = FULLSCREEN_MAXIMIZED;
7917           if (fs_state != FULLSCREEN_BOTH)
7918             [[self window] performZoom:self];
7919           break;
7920         case FULLSCREEN_NONE:
7921           NSTRACE_MSG ("FULLSCREEN_NONE");
7922           if (fs_state != FULLSCREEN_BOTH)
7923             {
7924               next_maximized = FULLSCREEN_NONE;
7925               [[self window] performZoom:self];
7926             }
7927           break;
7928         }
7930       emacsframe->want_fullscreen = FULLSCREEN_NONE;
7931     }
7935 - (void) setFSValue: (int)value
7937   NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7938            NSTRACE_ARG_FSTYPE(value));
7940   Lisp_Object lval = Qnil;
7941   switch (value)
7942     {
7943     case FULLSCREEN_BOTH:
7944       lval = Qfullboth;
7945       break;
7946     case FULLSCREEN_WIDTH:
7947       lval = Qfullwidth;
7948       break;
7949     case FULLSCREEN_HEIGHT:
7950       lval = Qfullheight;
7951       break;
7952     case FULLSCREEN_MAXIMIZED:
7953       lval = Qmaximized;
7954       break;
7955     }
7956   store_frame_param (emacsframe, Qfullscreen, lval);
7957   fs_state = value;
7960 - (void)mouseEntered: (NSEvent *)theEvent
7962   NSTRACE ("[EmacsView mouseEntered:]");
7963   if (emacsframe)
7964     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7965       = EV_TIMESTAMP (theEvent);
7969 - (void)mouseExited: (NSEvent *)theEvent
7971   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7973   NSTRACE ("[EmacsView mouseExited:]");
7975   if (!hlinfo)
7976     return;
7978   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7979     = EV_TIMESTAMP (theEvent);
7981   if (emacsframe == hlinfo->mouse_face_mouse_frame)
7982     {
7983       clear_mouse_face (hlinfo);
7984       hlinfo->mouse_face_mouse_frame = 0;
7985     }
7989 - (instancetype)menuDown: sender
7991   NSTRACE ("[EmacsView menuDown:]");
7992   if (context_menu_value == -1)
7993     context_menu_value = [sender tag];
7994   else
7995     {
7996       NSInteger tag = [sender tag];
7997       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7998                                     emacsframe->menu_bar_vector,
7999                                     (void *)tag);
8000     }
8002   ns_send_appdefined (-1);
8003   return self;
8007 - (EmacsToolbar *)toolbar
8009   return toolbar;
8013 /* this gets called on toolbar button click */
8014 - (instancetype)toolbarClicked: (id)item
8016   NSEvent *theEvent;
8017   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
8019   NSTRACE ("[EmacsView toolbarClicked:]");
8021   if (!emacs_event)
8022     return self;
8024   /* send first event (for some reason two needed) */
8025   theEvent = [[self window] currentEvent];
8026   emacs_event->kind = TOOL_BAR_EVENT;
8027   XSETFRAME (emacs_event->arg, emacsframe);
8028   EV_TRAILER (theEvent);
8030   emacs_event->kind = TOOL_BAR_EVENT;
8031 /*   XSETINT (emacs_event->code, 0); */
8032   emacs_event->arg = AREF (emacsframe->tool_bar_items,
8033                            idx + TOOL_BAR_ITEM_KEY);
8034   emacs_event->modifiers = EV_MODIFIERS (theEvent);
8035   EV_TRAILER (theEvent);
8036   return self;
8040 - (instancetype)toggleToolbar: (id)sender
8042   NSTRACE ("[EmacsView toggleToolbar:]");
8044   if (!emacs_event)
8045     return self;
8047   emacs_event->kind = NS_NONKEY_EVENT;
8048   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
8049   EV_TRAILER ((id)nil);
8050   return self;
8054 - (void)drawRect: (NSRect)rect
8056   int x = NSMinX (rect), y = NSMinY (rect);
8057   int width = NSWidth (rect), height = NSHeight (rect);
8059   NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
8060            NSTRACE_ARG_RECT(rect));
8062   if (!emacsframe || !emacsframe->output_data.ns)
8063     return;
8065   ns_clear_frame_area (emacsframe, x, y, width, height);
8066   block_input ();
8067   expose_frame (emacsframe, x, y, width, height);
8068   unblock_input ();
8070   /*
8071     drawRect: may be called (at least in Mac OS X 10.5) for invisible
8072     views as well for some reason.  Thus, do not infer visibility
8073     here.
8075     emacsframe->async_visible = 1;
8076     emacsframe->async_iconified = 0;
8077   */
8081 /* NSDraggingDestination protocol methods.  Actually this is not really a
8082    protocol, but a category of Object.  O well...  */
8084 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
8086   NSTRACE ("[EmacsView draggingEntered:]");
8087   return NSDragOperationGeneric;
8091 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
8093   return YES;
8097 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
8099   id pb;
8100   int x, y;
8101   NSString *type;
8102   NSEvent *theEvent = [[self window] currentEvent];
8103   NSPoint position;
8104   NSDragOperation op = [sender draggingSourceOperationMask];
8105   int modifiers = 0;
8107   NSTRACE ("[EmacsView performDragOperation:]");
8109   if (!emacs_event)
8110     return NO;
8112   position = [self convertPoint: [sender draggingLocation] fromView: nil];
8113   x = lrint (position.x);  y = lrint (position.y);
8115   pb = [sender draggingPasteboard];
8116   type = [pb availableTypeFromArray: ns_drag_types];
8118   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
8119       // URL drags contain all operations (0xf), don't allow all to be set.
8120       (op & 0xf) != 0xf)
8121     {
8122       if (op & NSDragOperationLink)
8123         modifiers |= NSEventModifierFlagControl;
8124       if (op & NSDragOperationCopy)
8125         modifiers |= NSEventModifierFlagOption;
8126       if (op & NSDragOperationGeneric)
8127         modifiers |= NSEventModifierFlagCommand;
8128     }
8130   modifiers = EV_MODIFIERS2 (modifiers);
8131   if (type == 0)
8132     {
8133       return NO;
8134     }
8135   else if ([type isEqualToString: NSFilenamesPboardType])
8136     {
8137       NSArray *files;
8138       NSEnumerator *fenum;
8139       NSString *file;
8141       if (!(files = [pb propertyListForType: type]))
8142         return NO;
8144       fenum = [files objectEnumerator];
8145       while ( (file = [fenum nextObject]) )
8146         {
8147           emacs_event->kind = DRAG_N_DROP_EVENT;
8148           XSETINT (emacs_event->x, x);
8149           XSETINT (emacs_event->y, y);
8150           emacs_event->modifiers = modifiers;
8151           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
8152           EV_TRAILER (theEvent);
8153         }
8154       return YES;
8155     }
8156   else if ([type isEqualToString: NSURLPboardType])
8157     {
8158       NSURL *url = [NSURL URLFromPasteboard: pb];
8159       if (url == nil) return NO;
8161       emacs_event->kind = DRAG_N_DROP_EVENT;
8162       XSETINT (emacs_event->x, x);
8163       XSETINT (emacs_event->y, y);
8164       emacs_event->modifiers = modifiers;
8165       emacs_event->arg =  list2 (Qurl,
8166                                  build_string ([[url absoluteString]
8167                                                  UTF8String]));
8168       EV_TRAILER (theEvent);
8170       if ([url isFileURL] != NO)
8171         {
8172           NSString *file = [url path];
8173           ns_input_file = append2 (ns_input_file,
8174                                    build_string ([file UTF8String]));
8175         }
8176       return YES;
8177     }
8178   else if ([type isEqualToString: NSStringPboardType]
8179            || [type isEqualToString: NSTabularTextPboardType])
8180     {
8181       NSString *data;
8183       if (! (data = [pb stringForType: type]))
8184         return NO;
8186       emacs_event->kind = DRAG_N_DROP_EVENT;
8187       XSETINT (emacs_event->x, x);
8188       XSETINT (emacs_event->y, y);
8189       emacs_event->modifiers = modifiers;
8190       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
8191       EV_TRAILER (theEvent);
8192       return YES;
8193     }
8194   else
8195     {
8196       fprintf (stderr, "Invalid data type in dragging pasteboard");
8197       return NO;
8198     }
8202 - (id) validRequestorForSendType: (NSString *)typeSent
8203                       returnType: (NSString *)typeReturned
8205   NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
8206   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
8207       && typeReturned == nil)
8208     {
8209       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
8210         return self;
8211     }
8213   return [super validRequestorForSendType: typeSent
8214                                returnType: typeReturned];
8218 /* The next two methods are part of NSServicesRequests informal protocol,
8219    supposedly called when a services menu item is chosen from this app.
8220    But this should not happen because we override the services menu with our
8221    own entries which call ns-perform-service.
8222    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
8223    So let's at least stub them out until further investigation can be done. */
8225 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
8227   /* we could call ns_string_from_pasteboard(pboard) here but then it should
8228      be written into the buffer in place of the existing selection..
8229      ordinary service calls go through functions defined in ns-win.el */
8230   return NO;
8233 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
8235   NSArray *typesDeclared;
8236   Lisp_Object val;
8238   NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
8240   /* We only support NSStringPboardType */
8241   if ([types containsObject:NSStringPboardType] == NO) {
8242     return NO;
8243   }
8245   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8246   if (CONSP (val) && SYMBOLP (XCAR (val)))
8247     {
8248       val = XCDR (val);
8249       if (CONSP (val) && NILP (XCDR (val)))
8250         val = XCAR (val);
8251     }
8252   if (! STRINGP (val))
8253     return NO;
8255   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
8256   [pb declareTypes:typesDeclared owner:nil];
8257   ns_string_to_pasteboard (pb, val);
8258   return YES;
8262 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
8263    (gives a miniaturized version of the window); currently we use the latter for
8264    frames whose active buffer doesn't correspond to any file
8265    (e.g., '*scratch*') */
8266 - (instancetype)setMiniwindowImage: (BOOL) setMini
8268   id image = [[self window] miniwindowImage];
8269   NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
8271   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
8272      about "AppleDockIconEnabled" notwithstanding, however the set message
8273      below has its effect nonetheless. */
8274   if (image != emacsframe->output_data.ns->miniimage)
8275     {
8276       if (image && [image isKindOfClass: [EmacsImage class]])
8277         [image release];
8278       [[self window] setMiniwindowImage:
8279                        setMini ? emacsframe->output_data.ns->miniimage : nil];
8280     }
8282   return self;
8286 - (void) setRows: (int) r andColumns: (int) c
8288   NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
8289   rows = r;
8290   cols = c;
8293 - (int) fullscreenState
8295   return fs_state;
8298 @end  /* EmacsView */
8302 /* ==========================================================================
8304     EmacsWindow implementation
8306    ========================================================================== */
8308 @implementation EmacsWindow
8310 #ifdef NS_IMPL_COCOA
8311 - (id)accessibilityAttributeValue:(NSString *)attribute
8313   Lisp_Object str = Qnil;
8314   struct frame *f = SELECTED_FRAME ();
8315   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
8317   NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
8319   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
8320     return NSAccessibilityTextFieldRole;
8322   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
8323       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
8324     {
8325       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8326     }
8327   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
8328     {
8329       if (! NILP (BVAR (curbuf, mark_active)))
8330           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8332       if (NILP (str))
8333         {
8334           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
8335           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
8336           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
8338           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
8339             str = make_uninit_multibyte_string (range, byte_range);
8340           else
8341             str = make_uninit_string (range);
8342           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
8343              Is this a problem?  */
8344           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
8345         }
8346     }
8349   if (! NILP (str))
8350     {
8351       if (CONSP (str) && SYMBOLP (XCAR (str)))
8352         {
8353           str = XCDR (str);
8354           if (CONSP (str) && NILP (XCDR (str)))
8355             str = XCAR (str);
8356         }
8357       if (STRINGP (str))
8358         {
8359           const char *utfStr = SSDATA (str);
8360           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8361           return nsStr;
8362         }
8363     }
8365   return [super accessibilityAttributeValue:attribute];
8367 #endif /* NS_IMPL_COCOA */
8369 /* Constrain size and placement of a frame.
8371    By returning the original "frameRect", the frame is not
8372    constrained. This can lead to unwanted situations where, for
8373    example, the menu bar covers the frame.
8375    The default implementation (accessed using "super") constrains the
8376    frame to the visible area of SCREEN, minus the menu bar (if
8377    present) and the Dock.  Note that default implementation also calls
8378    windowWillResize, with the frame it thinks should have.  (This can
8379    make the frame exit maximized mode.)
8381    Note that this should work in situations where multiple monitors
8382    are present.  Common configurations are side-by-side monitors and a
8383    monitor on top of another (e.g. when a laptop is placed under a
8384    large screen). */
8385 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8387   NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8388              NSTRACE_ARG_RECT (frameRect));
8390 #ifdef NS_IMPL_COCOA
8391 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
8392   // If separate spaces is on, it is like each screen is independent.  There is
8393   // no spanning of frames across screens.
8394   if (
8395 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
8396       [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)] &&
8397 #endif
8398       [NSScreen screensHaveSeparateSpaces])
8399     {
8400       NSTRACE_MSG ("Screens have separate spaces");
8401       frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8402       NSTRACE_RETURN_RECT (frameRect);
8403       return frameRect;
8404     }
8405   else
8406 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */
8408     // Check that the proposed frameRect is visible in at least one
8409     // screen.  If it is not, ask the system to reposition it (only
8410     // for non-child windows).
8412     if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe))
8413     {
8414       NSArray *screens = [NSScreen screens];
8415       NSUInteger nr_screens = [screens count];
8417       int i;
8418       BOOL frame_on_screen = NO;
8420       for (i = 0; i < nr_screens; ++i)
8421         {
8422           NSScreen *s = [screens objectAtIndex: i];
8423           NSRect scrRect = [s frame];
8425           if (NSIntersectsRect(frameRect, scrRect))
8426             {
8427               frame_on_screen = YES;
8428               break;
8429             }
8430         }
8432       if (!frame_on_screen)
8433         {
8434           NSTRACE_MSG ("Frame outside screens; constraining");
8435           frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8436           NSTRACE_RETURN_RECT (frameRect);
8437           return frameRect;
8438         }
8439     }
8440 #endif
8442   return constrain_frame_rect(frameRect,
8443                               [(EmacsView *)[self delegate] isFullscreen]);
8447 - (void)performZoom:(id)sender
8449   NSTRACE ("[EmacsWindow performZoom:]");
8451   return [super performZoom:sender];
8454 - (void)zoom:(id)sender
8456   NSTRACE ("[EmacsWindow zoom:]");
8458   ns_update_auto_hide_menu_bar();
8460   // Below are three zoom implementations.  In the final commit, the
8461   // idea is that the last should be included.
8463 #if 0
8464   // Native zoom done using the standard zoom animation.  Size of the
8465   // resulting frame reduced to accommodate the Dock and, if present,
8466   // the menu-bar.
8467   [super zoom:sender];
8469 #elif 0
8470   // Native zoom done using the standard zoom animation, plus an
8471   // explicit resize to cover the full screen, except the menu-bar and
8472   // dock, if present.
8473   [super zoom:sender];
8475   // After the native zoom, resize the resulting frame to fill the
8476   // entire screen, except the menu-bar.
8477   //
8478   // This works for all practical purposes.  (The only minor oddity is
8479   // when transiting from full-height frame to a maximized, the
8480   // animation reduces the height of the frame slightly (to the 4
8481   // pixels needed to accommodate the Doc) before it snaps back into
8482   // full height.  The user would need a very trained eye to spot
8483   // this.)
8484   NSScreen * screen = [self screen];
8485   if (screen != nil)
8486     {
8487       int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8489       NSTRACE_FSTYPE ("fullscreenState", fs_state);
8491       NSRect sr = [screen frame];
8492       struct EmacsMargins margins
8493         = ns_screen_margins_ignoring_hidden_dock(screen);
8495       NSRect wr = [self frame];
8496       NSTRACE_RECT ("Rect after zoom", wr);
8498       NSRect newWr = wr;
8500       if (fs_state == FULLSCREEN_MAXIMIZED
8501           || fs_state == FULLSCREEN_HEIGHT)
8502         {
8503           newWr.origin.y = sr.origin.y + margins.bottom;
8504           newWr.size.height = sr.size.height - margins.top - margins.bottom;
8505         }
8507       if (fs_state == FULLSCREEN_MAXIMIZED
8508           || fs_state == FULLSCREEN_WIDTH)
8509         {
8510           newWr.origin.x = sr.origin.x + margins.left;
8511           newWr.size.width = sr.size.width - margins.right - margins.left;
8512         }
8514       if (newWr.size.width     != wr.size.width
8515           || newWr.size.height != wr.size.height
8516           || newWr.origin.x    != wr.origin.x
8517           || newWr.origin.y    != wr.origin.y)
8518         {
8519           NSTRACE_MSG ("New frame different");
8520           [self setFrame: newWr display: NO];
8521         }
8522     }
8523 #else
8524   // Non-native zoom which is done instantaneously.  The resulting
8525   // frame covers the entire screen, except the menu-bar and dock, if
8526   // present.
8527   NSScreen * screen = [self screen];
8528   if (screen != nil)
8529     {
8530       NSRect sr = [screen frame];
8531       struct EmacsMargins margins
8532         = ns_screen_margins_ignoring_hidden_dock(screen);
8534       sr.size.height -= (margins.top + margins.bottom);
8535       sr.size.width  -= (margins.left + margins.right);
8536       sr.origin.x += margins.left;
8537       sr.origin.y += margins.bottom;
8539       sr = [[self delegate] windowWillUseStandardFrame:self
8540                                           defaultFrame:sr];
8541       [self setFrame: sr display: NO];
8542     }
8543 #endif
8546 - (void)setFrame:(NSRect)windowFrame
8547          display:(BOOL)displayViews
8549   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8550            NSTRACE_ARG_RECT (windowFrame), displayViews);
8552   [super setFrame:windowFrame display:displayViews];
8555 - (void)setFrame:(NSRect)windowFrame
8556          display:(BOOL)displayViews
8557          animate:(BOOL)performAnimation
8559   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8560            " display:%d performAnimation:%d]",
8561            NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8563   [super setFrame:windowFrame display:displayViews animate:performAnimation];
8566 - (void)setFrameTopLeftPoint:(NSPoint)point
8568   NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8569            NSTRACE_ARG_POINT (point));
8571   [super setFrameTopLeftPoint:point];
8574 - (BOOL)canBecomeKeyWindow
8576   return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8578 @end /* EmacsWindow */
8581 @implementation EmacsFSWindow
8583 - (BOOL)canBecomeKeyWindow
8585   return YES;
8588 - (BOOL)canBecomeMainWindow
8590   return YES;
8593 @end
8595 /* ==========================================================================
8597     EmacsScroller implementation
8599    ========================================================================== */
8602 @implementation EmacsScroller
8604 /* for repeat button push */
8605 #define SCROLL_BAR_FIRST_DELAY 0.5
8606 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8608 + (CGFloat) scrollerWidth
8610   /* TODO: if we want to allow variable widths, this is the place to do it,
8611            however neither GNUstep nor Cocoa support it very well */
8612   CGFloat r;
8613 #if defined (NS_IMPL_COCOA) \
8614   && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
8615 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8616   if ([NSScroller respondsToSelector:
8617                     @selector(scrollerWidthForControlSize:scrollerStyle:)])
8618 #endif
8619     r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8620                                   scrollerStyle: NSScrollerStyleLegacy];
8621 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8622   else
8623 #endif
8624 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
8625 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
8626   || defined (NS_IMPL_GNUSTEP)
8627     r = [NSScroller scrollerWidth];
8628 #endif
8629   return r;
8632 - (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin
8634   NSTRACE ("[EmacsScroller initFrame: window:]");
8636   if (r.size.width > r.size.height)
8637       horizontal = YES;
8638   else
8639       horizontal = NO;
8641   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8642   [self setContinuous: YES];
8643   [self setEnabled: YES];
8645   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8646      locked against the top and bottom edges, and right edge on macOS, where
8647      scrollers are on right. */
8648 #ifdef NS_IMPL_GNUSTEP
8649   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8650 #else
8651   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8652 #endif
8654   window = XWINDOW (nwin);
8655   condemned = NO;
8656   if (horizontal)
8657     pixel_length = NSWidth (r);
8658   else
8659     pixel_length = NSHeight (r);
8660   if (pixel_length == 0) pixel_length = 1;
8661   min_portion = 20 / pixel_length;
8663   frame = XFRAME (window->frame);
8664   if (FRAME_LIVE_P (frame))
8665     {
8666       int i;
8667       EmacsView *view = FRAME_NS_VIEW (frame);
8668       NSView *sview = [[view window] contentView];
8669       NSArray *subs = [sview subviews];
8671       /* disable optimization stopping redraw of other scrollbars */
8672       view->scrollbarsNeedingUpdate = 0;
8673       for (i =[subs count]-1; i >= 0; i--)
8674         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8675           view->scrollbarsNeedingUpdate++;
8676       [sview addSubview: self];
8677     }
8679 /*  [self setFrame: r]; */
8681   return self;
8685 - (void)setFrame: (NSRect)newRect
8687   NSTRACE ("[EmacsScroller setFrame:]");
8689 /*  block_input (); */
8690   if (horizontal)
8691     pixel_length = NSWidth (newRect);
8692   else
8693     pixel_length = NSHeight (newRect);
8694   if (pixel_length == 0) pixel_length = 1;
8695   min_portion = 20 / pixel_length;
8696   [super setFrame: newRect];
8697 /*  unblock_input (); */
8701 - (void)dealloc
8703   NSTRACE ("[EmacsScroller dealloc]");
8704   if (window)
8705     {
8706       if (horizontal)
8707         wset_horizontal_scroll_bar (window, Qnil);
8708       else
8709         wset_vertical_scroll_bar (window, Qnil);
8710     }
8711   window = 0;
8712   [super dealloc];
8716 - (instancetype)condemn
8718   NSTRACE ("[EmacsScroller condemn]");
8719   condemned =YES;
8720   return self;
8724 - (instancetype)reprieve
8726   NSTRACE ("[EmacsScroller reprieve]");
8727   condemned =NO;
8728   return self;
8732 -(bool)judge
8734   NSTRACE ("[EmacsScroller judge]");
8735   bool ret = condemned;
8736   if (condemned)
8737     {
8738       EmacsView *view;
8739       block_input ();
8740       /* ensure other scrollbar updates after deletion */
8741       view = (EmacsView *)FRAME_NS_VIEW (frame);
8742       if (view != nil)
8743         view->scrollbarsNeedingUpdate++;
8744       if (window)
8745         {
8746           if (horizontal)
8747             wset_horizontal_scroll_bar (window, Qnil);
8748           else
8749             wset_vertical_scroll_bar (window, Qnil);
8750         }
8751       window = 0;
8752       [self removeFromSuperview];
8753       [self release];
8754       unblock_input ();
8755     }
8756   return ret;
8760 - (void)resetCursorRects
8762   NSRect visible = [self visibleRect];
8763   NSTRACE ("[EmacsScroller resetCursorRects]");
8765   if (!NSIsEmptyRect (visible))
8766     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8767   [[NSCursor arrowCursor] setOnMouseEntered: YES];
8771 - (int) checkSamePosition: (int) position portion: (int) portion
8772                     whole: (int) whole
8774   return em_position ==position && em_portion ==portion && em_whole ==whole
8775     && portion != whole; /* needed for resize empty buf */
8779 - (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole
8781   NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8783   em_position = position;
8784   em_portion = portion;
8785   em_whole = whole;
8787   if (portion >= whole)
8788     {
8789 #ifdef NS_IMPL_COCOA
8790       [self setKnobProportion: 1.0];
8791       [self setDoubleValue: 1.0];
8792 #else
8793       [self setFloatValue: 0.0 knobProportion: 1.0];
8794 #endif
8795     }
8796   else
8797     {
8798       float pos;
8799       CGFloat por;
8800       portion = max ((float)whole*min_portion/pixel_length, portion);
8801       pos = (float)position / (whole - portion);
8802       por = (CGFloat)portion/whole;
8803 #ifdef NS_IMPL_COCOA
8804       [self setKnobProportion: por];
8805       [self setDoubleValue: pos];
8806 #else
8807       [self setFloatValue: pos knobProportion: por];
8808 #endif
8809     }
8811   return self;
8814 /* set up emacs_event */
8815 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8817   Lisp_Object win;
8819   NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8821   if (!emacs_event)
8822     return;
8824   emacs_event->part = last_hit_part;
8825   emacs_event->code = 0;
8826   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8827   XSETWINDOW (win, window);
8828   emacs_event->frame_or_window = win;
8829   emacs_event->timestamp = EV_TIMESTAMP (e);
8830   emacs_event->arg = Qnil;
8832   if (horizontal)
8833     {
8834       emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8835       XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8836       XSETINT (emacs_event->y, em_whole);
8837     }
8838   else
8839     {
8840       emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8841       XSETINT (emacs_event->x, loc);
8842       XSETINT (emacs_event->y, pixel_length-20);
8843     }
8845   if (q_event_ptr)
8846     {
8847       n_emacs_events_pending++;
8848       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8849     }
8850   else
8851     hold_event (emacs_event);
8852   EVENT_INIT (*emacs_event);
8853   ns_send_appdefined (-1);
8857 /* called manually thru timer to implement repeated button action w/hold-down */
8858 - (instancetype)repeatScroll: (NSTimer *)scrollEntry
8860   NSEvent *e = [[self window] currentEvent];
8861   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
8862   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8864   NSTRACE ("[EmacsScroller repeatScroll:]");
8866   /* clear timer if need be */
8867   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8868     {
8869         [scroll_repeat_entry invalidate];
8870         [scroll_repeat_entry release];
8871         scroll_repeat_entry = nil;
8873         if (inKnob)
8874           return self;
8876         scroll_repeat_entry
8877           = [[NSTimer scheduledTimerWithTimeInterval:
8878                         SCROLL_BAR_CONTINUOUS_DELAY
8879                                             target: self
8880                                           selector: @selector (repeatScroll:)
8881                                           userInfo: 0
8882                                            repeats: YES]
8883               retain];
8884     }
8886   [self sendScrollEventAtLoc: 0 fromEvent: e];
8887   return self;
8891 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
8892    mouseDragged events without going into a modal loop. */
8893 - (void)mouseDown: (NSEvent *)e
8895   NSRect sr, kr;
8896   /* hitPart is only updated AFTER event is passed on */
8897   NSScrollerPart part = [self testPart: [e locationInWindow]];
8898   CGFloat loc, kloc, pos UNINIT;
8899   int edge = 0;
8901   NSTRACE ("[EmacsScroller mouseDown:]");
8903   switch (part)
8904     {
8905     case NSScrollerDecrementPage:
8906       last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
8907     case NSScrollerIncrementPage:
8908       last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
8909     case NSScrollerDecrementLine:
8910       last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
8911     case NSScrollerIncrementLine:
8912       last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
8913     case NSScrollerKnob:
8914       last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
8915     case NSScrollerKnobSlot:  /* GNUstep-only */
8916       last_hit_part = scroll_bar_move_ratio; break;
8917     default:  /* NSScrollerNoPart? */
8918       fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
8919                (long) part);
8920       return;
8921     }
8923   if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
8924     {
8925       /* handle, or on GNUstep possibly slot */
8926       NSEvent *fake_event;
8927       int length;
8929       /* compute float loc in slot and mouse offset on knob */
8930       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8931                       toView: nil];
8932       if (horizontal)
8933         {
8934           length = NSWidth (sr);
8935           loc = ([e locationInWindow].x - NSMinX (sr));
8936         }
8937       else
8938         {
8939           length = NSHeight (sr);
8940           loc = length - ([e locationInWindow].y - NSMinY (sr));
8941         }
8943       if (loc <= 0.0)
8944         {
8945           loc = 0.0;
8946           edge = -1;
8947         }
8948       else if (loc >= length)
8949         {
8950           loc = length;
8951           edge = 1;
8952         }
8954       if (edge)
8955         kloc = 0.5 * edge;
8956       else
8957         {
8958           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8959                           toView: nil];
8960           if (horizontal)
8961             kloc = ([e locationInWindow].x - NSMinX (kr));
8962           else
8963             kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8964         }
8965       last_mouse_offset = kloc;
8967       /* if knob, tell emacs a location offset by knob pos
8968          (to indicate top of handle) */
8969       if (part == NSScrollerKnob)
8970         pos = (loc - last_mouse_offset);
8971       else
8972         /* else this is a slot click on GNUstep: go straight there */
8973         pos = loc;
8975       /* If there are buttons in the scroller area, we need to
8976          recalculate pos as emacs expects the scroller slot to take up
8977          the entire available length.  */
8978       if (length != pixel_length)
8979         pos = pos * pixel_length / length;
8981       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8982       fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
8983                                       location: [e locationInWindow]
8984                                  modifierFlags: [e modifierFlags]
8985                                      timestamp: [e timestamp]
8986                                   windowNumber: [e windowNumber]
8987                                        context: nil
8988                                    eventNumber: [e eventNumber]
8989                                     clickCount: [e clickCount]
8990                                       pressure: [e pressure]];
8991       [super mouseUp: fake_event];
8992     }
8993   else
8994     {
8995       pos = 0;      /* ignored */
8997       /* set a timer to repeat, as we can't let superclass do this modally */
8998       scroll_repeat_entry
8999         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
9000                                             target: self
9001                                           selector: @selector (repeatScroll:)
9002                                           userInfo: 0
9003                                            repeats: YES]
9004             retain];
9005     }
9007   if (part != NSScrollerKnob)
9008     [self sendScrollEventAtLoc: pos fromEvent: e];
9012 /* Called as we manually track scroller drags, rather than superclass. */
9013 - (void)mouseDragged: (NSEvent *)e
9015     NSRect sr;
9016     double loc, pos;
9017     int length;
9019     NSTRACE ("[EmacsScroller mouseDragged:]");
9021       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
9022                       toView: nil];
9024       if (horizontal)
9025         {
9026           length = NSWidth (sr);
9027           loc = ([e locationInWindow].x - NSMinX (sr));
9028         }
9029       else
9030         {
9031           length = NSHeight (sr);
9032           loc = length - ([e locationInWindow].y - NSMinY (sr));
9033         }
9035       if (loc <= 0.0)
9036         {
9037           loc = 0.0;
9038         }
9039       else if (loc >= length + last_mouse_offset)
9040         {
9041           loc = length + last_mouse_offset;
9042         }
9044       pos = (loc - last_mouse_offset);
9046       /* If there are buttons in the scroller area, we need to
9047          recalculate pos as emacs expects the scroller slot to take up
9048          the entire available length.  */
9049       if (length != pixel_length)
9050         pos = pos * pixel_length / length;
9052       [self sendScrollEventAtLoc: pos fromEvent: e];
9056 - (void)mouseUp: (NSEvent *)e
9058   NSTRACE ("[EmacsScroller mouseUp:]");
9060   if (scroll_repeat_entry)
9061     {
9062       [scroll_repeat_entry invalidate];
9063       [scroll_repeat_entry release];
9064       scroll_repeat_entry = nil;
9065     }
9066   last_hit_part = scroll_bar_above_handle;
9070 /* treat scrollwheel events in the bar as though they were in the main window */
9071 - (void) scrollWheel: (NSEvent *)theEvent
9073   NSTRACE ("[EmacsScroller scrollWheel:]");
9075   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
9076   [view mouseDown: theEvent];
9079 @end  /* EmacsScroller */
9082 #ifdef NS_IMPL_GNUSTEP
9083 /* Dummy class to get rid of startup warnings.  */
9084 @implementation EmacsDocument
9086 @end
9087 #endif
9090 /* ==========================================================================
9092    Font-related functions; these used to be in nsfaces.m
9094    ========================================================================== */
9097 Lisp_Object
9098 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
9100   struct font *font = XFONT_OBJECT (font_object);
9101   EmacsView *view = FRAME_NS_VIEW (f);
9102   int font_ascent, font_descent;
9104   if (fontset < 0)
9105     fontset = fontset_from_font (font_object);
9106   FRAME_FONTSET (f) = fontset;
9108   if (FRAME_FONT (f) == font)
9109     /* This font is already set in frame F.  There's nothing more to
9110        do.  */
9111     return font_object;
9113   FRAME_FONT (f) = font;
9115   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
9116   FRAME_COLUMN_WIDTH (f) = font->average_width;
9117   get_font_ascent_descent (font, &font_ascent, &font_descent);
9118   FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
9120   /* Compute the scroll bar width in character columns.  */
9121   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
9122     {
9123       int wid = FRAME_COLUMN_WIDTH (f);
9124       FRAME_CONFIG_SCROLL_BAR_COLS (f)
9125         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
9126     }
9127   else
9128     {
9129       int wid = FRAME_COLUMN_WIDTH (f);
9130       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
9131     }
9133   /* Compute the scroll bar height in character lines.  */
9134   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
9135     {
9136       int height = FRAME_LINE_HEIGHT (f);
9137       FRAME_CONFIG_SCROLL_BAR_LINES (f)
9138         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
9139     }
9140   else
9141     {
9142       int height = FRAME_LINE_HEIGHT (f);
9143       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
9144     }
9146   /* Now make the frame display the given font.  */
9147   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
9148     adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
9149                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
9150                        false, Qfont);
9152   return font_object;
9156 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
9157 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
9158          in 1.43. */
9160 const char *
9161 ns_xlfd_to_fontname (const char *xlfd)
9162 /* --------------------------------------------------------------------------
9163     Convert an X font name (XLFD) to an NS font name.
9164     Only family is used.
9165     The string returned is temporarily allocated.
9166    -------------------------------------------------------------------------- */
9168   char *name = xmalloc (180);
9169   int i, len;
9170   const char *ret;
9172   if (!strncmp (xlfd, "--", 2))
9173     sscanf (xlfd, "--%*[^-]-%179[^-]-", name);
9174   else
9175     sscanf (xlfd, "-%*[^-]-%179[^-]-", name);
9177   /* stopgap for malformed XLFD input */
9178   if (strlen (name) == 0)
9179     strcpy (name, "Monaco");
9181   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
9182      also uppercase after '-' or ' ' */
9183   name[0] = c_toupper (name[0]);
9184   for (len =strlen (name), i =0; i<len; i++)
9185     {
9186       if (name[i] == '$')
9187         {
9188           name[i] = '-';
9189           if (i+1<len)
9190             name[i+1] = c_toupper (name[i+1]);
9191         }
9192       else if (name[i] == '_')
9193         {
9194           name[i] = ' ';
9195           if (i+1<len)
9196             name[i+1] = c_toupper (name[i+1]);
9197         }
9198     }
9199 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
9200   ret = [[NSString stringWithUTF8String: name] UTF8String];
9201   xfree (name);
9202   return ret;
9206 void
9207 syms_of_nsterm (void)
9209   NSTRACE ("syms_of_nsterm");
9211   ns_antialias_threshold = 10.0;
9213   /* from 23+ we need to tell emacs what modifiers there are.. */
9214   DEFSYM (Qmodifier_value, "modifier-value");
9215   DEFSYM (Qalt, "alt");
9216   DEFSYM (Qhyper, "hyper");
9217   DEFSYM (Qmeta, "meta");
9218   DEFSYM (Qsuper, "super");
9219   DEFSYM (Qcontrol, "control");
9220   DEFSYM (QUTF8_STRING, "UTF8_STRING");
9222   DEFSYM (Qfile, "file");
9223   DEFSYM (Qurl, "url");
9225   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
9226   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
9227   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
9228   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
9229   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
9231   DEFVAR_LISP ("ns-input-file", ns_input_file,
9232               "The file specified in the last NS event.");
9233   ns_input_file =Qnil;
9235   DEFVAR_LISP ("ns-working-text", ns_working_text,
9236               "String for visualizing working composition sequence.");
9237   ns_working_text =Qnil;
9239   DEFVAR_LISP ("ns-input-font", ns_input_font,
9240               "The font specified in the last NS event.");
9241   ns_input_font =Qnil;
9243   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
9244               "The fontsize specified in the last NS event.");
9245   ns_input_fontsize =Qnil;
9247   DEFVAR_LISP ("ns-input-line", ns_input_line,
9248                "The line specified in the last NS event.");
9249   ns_input_line =Qnil;
9251   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
9252                "The service name specified in the last NS event.");
9253   ns_input_spi_name =Qnil;
9255   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
9256                "The service argument specified in the last NS event.");
9257   ns_input_spi_arg =Qnil;
9259   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
9260                "This variable describes the behavior of the alternate or option key.\n\
9261 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9262 that key.\n\
9263 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9264 at all, allowing it to be used at a lower level for accented character entry.");
9265   ns_alternate_modifier = Qmeta;
9267   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
9268                "This variable describes the behavior of the right alternate or option key.\n\
9269 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9270 that key.\n\
9271 Set to left means be the same key as `ns-alternate-modifier'.\n\
9272 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9273 at all, allowing it to be used at a lower level for accented character entry.");
9274   ns_right_alternate_modifier = Qleft;
9276   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
9277                "This variable describes the behavior of the command key.\n\
9278 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9279 that key.");
9280   ns_command_modifier = Qsuper;
9282   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
9283                "This variable describes the behavior of the right command key.\n\
9284 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9285 that key.\n\
9286 Set to left means be the same key as `ns-command-modifier'.\n\
9287 Set to none means that the command / option key is not interpreted by Emacs\n\
9288 at all, allowing it to be used at a lower level for accented character entry.");
9289   ns_right_command_modifier = Qleft;
9291   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
9292                "This variable describes the behavior of the control key.\n\
9293 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9294 that key.");
9295   ns_control_modifier = Qcontrol;
9297   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
9298                "This variable describes the behavior of the right control key.\n\
9299 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9300 that key.\n\
9301 Set to left means be the same key as `ns-control-modifier'.\n\
9302 Set to none means that the control / option key is not interpreted by Emacs\n\
9303 at all, allowing it to be used at a lower level for accented character entry.");
9304   ns_right_control_modifier = Qleft;
9306   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
9307                "This variable describes the behavior of the function key (on laptops).\n\
9308 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9309 that key.\n\
9310 Set to none means that the function key is not interpreted by Emacs at all,\n\
9311 allowing it to be used at a lower level for accented character entry.");
9312   ns_function_modifier = Qnone;
9314   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
9315                "Non-nil (the default) means to render text antialiased.");
9316   ns_antialias_text = Qt;
9318   DEFVAR_LISP ("ns-use-thin-smoothing", ns_use_thin_smoothing,
9319                "Non-nil turns on a font smoothing method that produces thinner strokes.");
9320   ns_use_thin_smoothing = Qnil;
9322   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
9323                "Whether to confirm application quit using dialog.");
9324   ns_confirm_quit = Qnil;
9326   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
9327                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
9328 Only works on Mac OS X 10.6 or later.  */);
9329   ns_auto_hide_menu_bar = Qnil;
9331   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
9332      doc: /*Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
9333 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
9334 multiple monitors, but lacks tool bar.  This variable is ignored on
9335 Mac OS X < 10.7.  Default is t.  */);
9336   ns_use_native_fullscreen = YES;
9337   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
9339   DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
9340      doc: /*Non-nil means use animation on non-native fullscreen.
9341 For native fullscreen, this does nothing.
9342 Default is nil.  */);
9343   ns_use_fullscreen_animation = NO;
9345   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
9346      doc: /*Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
9347 Note that this does not apply to images.
9348 This variable is ignored on Mac OS X < 10.7 and GNUstep.  */);
9349   ns_use_srgb_colorspace = YES;
9351   DEFVAR_BOOL ("ns-use-mwheel-acceleration",
9352                ns_use_mwheel_acceleration,
9353      doc: /*Non-nil means use macOS's standard mouse wheel acceleration.
9354 This variable is ignored on macOS < 10.7 and GNUstep.  Default is t.  */);
9355   ns_use_mwheel_acceleration = YES;
9357   DEFVAR_LISP ("ns-mwheel-line-height", ns_mwheel_line_height,
9358                doc: /*The number of pixels touchpad scrolling considers one line.
9359 Nil or a non-number means use the default frame line height.
9360 This variable is ignored on macOS < 10.7 and GNUstep.  Default is nil.  */);
9361   ns_mwheel_line_height = Qnil;
9363   DEFVAR_BOOL ("ns-use-mwheel-momentum", ns_use_mwheel_momentum,
9364                doc: /*Non-nil means mouse wheel scrolling uses momentum.
9365 This variable is ignored on macOS < 10.7 and GNUstep.  Default is t.  */);
9366   ns_use_mwheel_momentum = YES;
9368   /* TODO: move to common code */
9369   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
9370                doc: /* Which toolkit scroll bars Emacs uses, if any.
9371 A value of nil means Emacs doesn't use toolkit scroll bars.
9372 With the X Window system, the value is a symbol describing the
9373 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
9374 With MS Windows or Nextstep, the value is t.  */);
9375   Vx_toolkit_scroll_bars = Qt;
9377   DEFVAR_BOOL ("x-use-underline-position-properties",
9378                x_use_underline_position_properties,
9379      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
9380 A value of nil means ignore them.  If you encounter fonts with bogus
9381 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
9382 to 4.1, set this to nil. */);
9383   x_use_underline_position_properties = 0;
9385   DEFVAR_BOOL ("x-underline-at-descent-line",
9386                x_underline_at_descent_line,
9387      doc: /* Non-nil means to draw the underline at the same place as the descent line.
9388 (If `line-spacing' is in effect, that moves the underline lower by
9389 that many pixels.)
9390 A value of nil means to draw the underline according to the value of the
9391 variable `x-use-underline-position-properties', which is usually at the
9392 baseline level.  The default value is nil.  */);
9393   x_underline_at_descent_line = 0;
9395   /* Tell Emacs about this window system.  */
9396   Fprovide (Qns, Qnil);
9398   DEFSYM (Qcocoa, "cocoa");
9399   DEFSYM (Qgnustep, "gnustep");
9401 #ifdef NS_IMPL_COCOA
9402   Fprovide (Qcocoa, Qnil);
9403   syms_of_macfont ();
9404 #else
9405   Fprovide (Qgnustep, Qnil);
9406   syms_of_nsfont ();
9407 #endif