Fix file-attributes race on GNU hosts
[emacs.git] / src / nsterm.m
blob22f8efd6b968af24fa9e9422618609af9d916134
1 /* NeXT/Open/GNUstep / macOS communication module.      -*- coding: utf-8 -*-
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2017 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 <http://www.gnu.org/licenses/>.  */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30    interpretation of even the system includes. */
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 /* GNUstep always shows decorations if the window is resizable,
427    miniaturizable or closable, but Cocoa does strange things in native
428    fullscreen mode if you don't have at least resizable enabled.
430    These flags will be OR'd or XOR'd with the NSWindow's styleMask
431    property depending on what we're doing. */
432 #ifdef NS_IMPL_COCOA
433 #define FRAME_DECORATED_FLAGS NSWindowStyleMaskTitled
434 #else
435 #define FRAME_DECORATED_FLAGS (NSWindowStyleMaskTitled              \
436                                | NSWindowStyleMaskResizable         \
437                                | NSWindowStyleMaskMiniaturizable    \
438                                | NSWindowStyleMaskClosable)
439 #endif
440 #define FRAME_UNDECORATED_FLAGS NSWindowStyleMaskBorderless
442 /* TODO: get rid of need for these forward declarations */
443 static void ns_condemn_scroll_bars (struct frame *f);
444 static void ns_judge_scroll_bars (struct frame *f);
447 /* ==========================================================================
449     Utilities
451    ========================================================================== */
453 void
454 ns_set_represented_filename (NSString *fstr, struct frame *f)
456   represented_filename = [fstr retain];
457   represented_frame = f;
460 void
461 ns_init_events (struct input_event *ev)
463   EVENT_INIT (*ev);
464   emacs_event = ev;
467 void
468 ns_finish_events (void)
470   emacs_event = NULL;
473 static void
474 hold_event (struct input_event *event)
476   if (hold_event_q.nr == hold_event_q.cap)
477     {
478       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
479       else hold_event_q.cap *= 2;
480       hold_event_q.q =
481         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
482     }
484   hold_event_q.q[hold_event_q.nr++] = *event;
485   /* Make sure ns_read_socket is called, i.e. we have input.  */
486   raise (SIGIO);
487   send_appdefined = YES;
490 static Lisp_Object
491 append2 (Lisp_Object list, Lisp_Object item)
492 /* --------------------------------------------------------------------------
493    Utility to append to a list
494    -------------------------------------------------------------------------- */
496   return CALLN (Fnconc, list, list1 (item));
500 const char *
501 ns_etc_directory (void)
502 /* If running as a self-contained app bundle, return as a string the
503    filename of the etc directory, if present; else nil.  */
505   NSBundle *bundle = [NSBundle mainBundle];
506   NSString *resourceDir = [bundle resourcePath];
507   NSString *resourcePath;
508   NSFileManager *fileManager = [NSFileManager defaultManager];
509   BOOL isDir;
511   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
512   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
513     {
514       if (isDir) return [resourcePath UTF8String];
515     }
516   return NULL;
520 const char *
521 ns_exec_path (void)
522 /* If running as a self-contained app bundle, return as a path string
523    the filenames of the libexec and bin directories, ie libexec:bin.
524    Otherwise, return nil.
525    Normally, Emacs does not add its own bin/ directory to the PATH.
526    However, a self-contained NS build has a different layout, with
527    bin/ and libexec/ subdirectories in the directory that contains
528    Emacs.app itself.
529    We put libexec first, because init_callproc_1 uses the first
530    element to initialize exec-directory.  An alternative would be
531    for init_callproc to check for invocation-directory/libexec.
534   NSBundle *bundle = [NSBundle mainBundle];
535   NSString *resourceDir = [bundle resourcePath];
536   NSString *binDir = [bundle bundlePath];
537   NSString *resourcePath, *resourcePaths;
538   NSRange range;
539   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
540   NSFileManager *fileManager = [NSFileManager defaultManager];
541   NSArray *paths;
542   NSEnumerator *pathEnum;
543   BOOL isDir;
545   range = [resourceDir rangeOfString: @"Contents"];
546   if (range.location != NSNotFound)
547     {
548       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
549 #ifdef NS_IMPL_COCOA
550       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
551 #endif
552     }
554   paths = [binDir stringsByAppendingPaths:
555                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
556   pathEnum = [paths objectEnumerator];
557   resourcePaths = @"";
559   while ((resourcePath = [pathEnum nextObject]))
560     {
561       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
562         if (isDir)
563           {
564             if ([resourcePaths length] > 0)
565               resourcePaths
566                 = [resourcePaths stringByAppendingString: pathSeparator];
567             resourcePaths
568               = [resourcePaths stringByAppendingString: resourcePath];
569           }
570     }
571   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
573   return NULL;
577 const char *
578 ns_load_path (void)
579 /* If running as a self-contained app bundle, return as a path string
580    the filenames of the site-lisp and lisp directories.
581    Ie, site-lisp:lisp.  Otherwise, return nil.  */
583   NSBundle *bundle = [NSBundle mainBundle];
584   NSString *resourceDir = [bundle resourcePath];
585   NSString *resourcePath, *resourcePaths;
586   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
587   NSFileManager *fileManager = [NSFileManager defaultManager];
588   BOOL isDir;
589   NSArray *paths = [resourceDir stringsByAppendingPaths:
590                               [NSArray arrayWithObjects:
591                                          @"site-lisp", @"lisp", nil]];
592   NSEnumerator *pathEnum = [paths objectEnumerator];
593   resourcePaths = @"";
595   /* Hack to skip site-lisp.  */
596   if (no_site_lisp) resourcePath = [pathEnum nextObject];
598   while ((resourcePath = [pathEnum nextObject]))
599     {
600       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
601         if (isDir)
602           {
603             if ([resourcePaths length] > 0)
604               resourcePaths
605                 = [resourcePaths stringByAppendingString: pathSeparator];
606             resourcePaths
607               = [resourcePaths stringByAppendingString: resourcePath];
608           }
609     }
610   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
612   return NULL;
616 void
617 ns_init_locale (void)
618 /* macOS doesn't set any environment variables for the locale when run
619    from the GUI. Get the locale from the OS and set LANG. */
621   NSLocale *locale = [NSLocale currentLocale];
623   NSTRACE ("ns_init_locale");
625   @try
626     {
627       /* It seems macOS should probably use UTF-8 everywhere.
628          'localeIdentifier' does not specify the encoding, and I can't
629          find any way to get the OS to tell us which encoding to use,
630          so hard-code '.UTF-8'. */
631       NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
632                                      [locale localeIdentifier]];
634       /* Set LANG to locale, but not if LANG is already set. */
635       setenv("LANG", [localeID UTF8String], 0);
636     }
637   @catch (NSException *e)
638     {
639       NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
640     }
644 void
645 ns_release_object (void *obj)
646 /* --------------------------------------------------------------------------
647     Release an object (callable from C)
648    -------------------------------------------------------------------------- */
650     [(id)obj release];
654 void
655 ns_retain_object (void *obj)
656 /* --------------------------------------------------------------------------
657     Retain an object (callable from C)
658    -------------------------------------------------------------------------- */
660     [(id)obj retain];
664 void *
665 ns_alloc_autorelease_pool (void)
666 /* --------------------------------------------------------------------------
667      Allocate a pool for temporary objects (callable from C)
668    -------------------------------------------------------------------------- */
670   return [[NSAutoreleasePool alloc] init];
674 void
675 ns_release_autorelease_pool (void *pool)
676 /* --------------------------------------------------------------------------
677      Free a pool and temporary objects it refers to (callable from C)
678    -------------------------------------------------------------------------- */
680   ns_release_object (pool);
684 static BOOL
685 ns_menu_bar_should_be_hidden (void)
686 /* True, if the menu bar should be hidden.  */
688   return !NILP (ns_auto_hide_menu_bar)
689     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
693 struct EmacsMargins
695   CGFloat top;
696   CGFloat bottom;
697   CGFloat left;
698   CGFloat right;
702 static struct EmacsMargins
703 ns_screen_margins (NSScreen *screen)
704 /* The parts of SCREEN used by the operating system.  */
706   NSTRACE ("ns_screen_margins");
708   struct EmacsMargins margins;
710   NSRect screenFrame = [screen frame];
711   NSRect screenVisibleFrame = [screen visibleFrame];
713   /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
714      menu bar, check this explicitly.  */
715   if (ns_menu_bar_should_be_hidden())
716     {
717       margins.top = 0;
718     }
719   else
720     {
721       CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
722       CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
723                                  + screenVisibleFrame.size.height);
725       margins.top = frameTop - visibleFrameTop;
726     }
728   {
729     CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
730     CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
731                                  + screenVisibleFrame.size.width);
732     margins.right = frameRight - visibleFrameRight;
733   }
735   margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
736   margins.left   = screenVisibleFrame.origin.x - screenFrame.origin.x;
738   NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
739                margins.left,
740                margins.right,
741                margins.top,
742                margins.bottom);
744   return margins;
748 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
749    assumed to contain a hidden dock.  macOS currently use 4 pixels for
750    this, however, to be future compatible, a larger value is used.  */
751 #define DOCK_IGNORE_LIMIT 6
753 static struct EmacsMargins
754 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
755 /* The parts of SCREEN used by the operating system, excluding the parts
756 reserved for an hidden dock.  */
758   NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
760   struct EmacsMargins margins = ns_screen_margins(screen);
762   /* macOS (currently) reserved 4 pixels along the edge where a hidden
763      dock is located.  Unfortunately, it's not possible to find the
764      location and information about if the dock is hidden.  Instead,
765      it is assumed that if the margin of an edge is less than
766      DOCK_IGNORE_LIMIT, it contains a hidden dock.  */
767   if (margins.left <= DOCK_IGNORE_LIMIT)
768     {
769       margins.left = 0;
770     }
771   if (margins.right <= DOCK_IGNORE_LIMIT)
772     {
773       margins.right = 0;
774     }
775   if (margins.top <= DOCK_IGNORE_LIMIT)
776     {
777       margins.top = 0;
778     }
779   /* Note: This doesn't occur in current versions of macOS, but
780      included for completeness and future compatibility.  */
781   if (margins.bottom <= DOCK_IGNORE_LIMIT)
782     {
783       margins.bottom = 0;
784     }
786   NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
787                margins.left,
788                margins.right,
789                margins.top,
790                margins.bottom);
792   return margins;
796 static CGFloat
797 ns_menu_bar_height (NSScreen *screen)
798 /* The height of the menu bar, if visible.
800    Note: Don't use this when fullscreen is enabled -- the screen
801    sometimes includes, sometimes excludes the menu bar area.  */
803   struct EmacsMargins margins = ns_screen_margins(screen);
805   CGFloat res = margins.top;
807   NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
809   return res;
813 /* ==========================================================================
815     Focus (clipping) and screen update
817    ========================================================================== */
820 // Window constraining
821 // -------------------
823 // To ensure that the windows are not placed under the menu bar, they
824 // are typically moved by the call-back constrainFrameRect. However,
825 // by overriding it, it's possible to inhibit this, leaving the window
826 // in it's original position.
828 // It's possible to hide the menu bar. However, technically, it's only
829 // possible to hide it when the application is active. To ensure that
830 // this work properly, the menu bar and window constraining are
831 // deferred until the application becomes active.
833 // Even though it's not possible to manually move a window above the
834 // top of the screen, it is allowed if it's done programmatically,
835 // when the menu is hidden. This allows the editable area to cover the
836 // full screen height.
838 // Test cases
839 // ----------
841 // Use the following extra files:
843 //    init.el:
844 //       ;; Hide menu and place frame slightly above the top of the screen.
845 //       (setq ns-auto-hide-menu-bar t)
846 //       (set-frame-position (selected-frame) 0 -20)
848 // Test 1:
850 //    emacs -Q -l init.el
852 //    Result: No menu bar, and the title bar should be above the screen.
854 // Test 2:
856 //    emacs -Q
858 //    Result: Menu bar visible, frame placed immediately below the menu.
861 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
863   NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
864              NSTRACE_ARG_RECT (frameRect));
866   // --------------------
867   // Collect information about the screen the frame is covering.
868   //
870   NSArray *screens = [NSScreen screens];
871   NSUInteger nr_screens = [screens count];
873   int i;
875   // The height of the menu bar, if present in any screen the frame is
876   // displayed in.
877   int menu_bar_height = 0;
879   // A rectangle covering all the screen the frame is displayed in.
880   NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
881   for (i = 0; i < nr_screens; ++i )
882     {
883       NSScreen *s = [screens objectAtIndex: i];
884       NSRect scrRect = [s frame];
886       NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
887                    i, NSTRACE_ARG_RECT (scrRect));
889       if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
890         {
891           multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
893           if (!isFullscreen)
894             {
895               CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
896               menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
897             }
898         }
899     }
901   NSTRACE_RECT ("multiscreenRect", multiscreenRect);
903   NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
905   if (multiscreenRect.size.width == 0
906       || multiscreenRect.size.height == 0)
907     {
908       // Failed to find any monitor, give up.
909       NSTRACE_MSG ("multiscreenRect empty");
910       NSTRACE_RETURN_RECT (frameRect);
911       return frameRect;
912     }
915   // --------------------
916   // Find a suitable placement.
917   //
919   if (ns_menu_bar_should_be_hidden())
920     {
921       // When the menu bar is hidden, the user may place part of the
922       // frame above the top of the screen, for example to hide the
923       // title bar.
924       //
925       // Hence, keep the original position.
926     }
927   else
928     {
929       // Ensure that the frame is below the menu bar, or below the top
930       // of the screen.
931       //
932       // This assume that the menu bar is placed at the top in the
933       // rectangle that covers the monitors.  (It doesn't have to be,
934       // but if it's not it's hard to do anything useful.)
935       CGFloat topOfWorkArea = (multiscreenRect.origin.y
936                                + multiscreenRect.size.height
937                                - menu_bar_height);
939       CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
940       if (topOfFrame > topOfWorkArea)
941         {
942           frameRect.origin.y -= topOfFrame - topOfWorkArea;
943           NSTRACE_RECT ("After placement adjust", frameRect);
944         }
945     }
947   // Include the following section to restrict frame to the screens.
948   // (If so, update it to allow the frame to stretch down below the
949   // screen.)
950 #if 0
951   // --------------------
952   // Ensure frame doesn't stretch below the screens.
953   //
955   CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
957   if (diff > 0)
958     {
959       frameRect.origin.y = multiscreenRect.origin.y;
960       frameRect.size.height -= diff;
961     }
962 #endif
964   NSTRACE_RETURN_RECT (frameRect);
965   return frameRect;
969 static void
970 ns_constrain_all_frames (void)
971 /* --------------------------------------------------------------------------
972      Ensure that the menu bar doesn't cover any frames.
973    -------------------------------------------------------------------------- */
975   Lisp_Object tail, frame;
977   NSTRACE ("ns_constrain_all_frames");
979   block_input ();
981   FOR_EACH_FRAME (tail, frame)
982     {
983       struct frame *f = XFRAME (frame);
984       if (FRAME_NS_P (f))
985         {
986           EmacsView *view = FRAME_NS_VIEW (f);
988           if (![view isFullscreen])
989             {
990               [[view window]
991                 setFrame:constrain_frame_rect([[view window] frame], false)
992                  display:NO];
993             }
994         }
995     }
997   unblock_input ();
1001 static void
1002 ns_update_auto_hide_menu_bar (void)
1003 /* --------------------------------------------------------------------------
1004      Show or hide the menu bar, based on user setting.
1005    -------------------------------------------------------------------------- */
1007 #ifdef NS_IMPL_COCOA
1008   NSTRACE ("ns_update_auto_hide_menu_bar");
1010   block_input ();
1012   if (NSApp != nil && [NSApp isActive])
1013     {
1014       // Note, "setPresentationOptions" triggers an error unless the
1015       // application is active.
1016       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
1018       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
1019         {
1020           NSApplicationPresentationOptions options
1021             = NSApplicationPresentationDefault;
1023           if (menu_bar_should_be_hidden)
1024             options |= NSApplicationPresentationAutoHideMenuBar
1025               | NSApplicationPresentationAutoHideDock;
1027           [NSApp setPresentationOptions: options];
1029           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
1031           if (!ns_menu_bar_is_hidden)
1032             {
1033               ns_constrain_all_frames ();
1034             }
1035         }
1036     }
1038   unblock_input ();
1039 #endif
1043 static void
1044 ns_update_begin (struct frame *f)
1045 /* --------------------------------------------------------------------------
1046    Prepare for a grouped sequence of drawing calls
1047    external (RIF) call; whole frame, called before update_window_begin
1048    -------------------------------------------------------------------------- */
1050   EmacsView *view = FRAME_NS_VIEW (f);
1051   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1053   ns_update_auto_hide_menu_bar ();
1055 #ifdef NS_IMPL_COCOA
1056   if ([view isFullscreen] && [view fsIsNative])
1057   {
1058     // Fix reappearing tool bar in fullscreen for Mac OS X 10.7
1059     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1060     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1061     if (! tbar_visible != ! [toolbar isVisible])
1062       [toolbar setVisible: tbar_visible];
1063   }
1064 #endif
1066   ns_updating_frame = f;
1067   [view lockFocus];
1069   /* drawRect may have been called for say the minibuffer, and then clip path
1070      is for the minibuffer.  But the display engine may draw more because
1071      we have set the frame as garbaged.  So reset clip path to the whole
1072      view.  */
1073 #ifdef NS_IMPL_COCOA
1074   {
1075     NSBezierPath *bp;
1076     NSRect r = [view frame];
1077     NSRect cr = [[view window] frame];
1078     /* If a large frame size is set, r may be larger than the window frame
1079        before constrained.  In that case don't change the clip path, as we
1080        will clear in to the tool bar and title bar.  */
1081     if (r.size.height
1082         + FRAME_NS_TITLEBAR_HEIGHT (f)
1083         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1084       {
1085         bp = [[NSBezierPath bezierPathWithRect: r] retain];
1086         [bp setClip];
1087         [bp release];
1088       }
1089   }
1090 #endif
1092 #ifdef NS_IMPL_GNUSTEP
1093   uRect = NSMakeRect (0, 0, 0, 0);
1094 #endif
1098 static void
1099 ns_update_window_begin (struct window *w)
1100 /* --------------------------------------------------------------------------
1101    Prepare for a grouped sequence of drawing calls
1102    external (RIF) call; for one window, called after update_begin
1103    -------------------------------------------------------------------------- */
1105   struct frame *f = XFRAME (WINDOW_FRAME (w));
1106   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1108   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1109   w->output_cursor = w->cursor;
1111   block_input ();
1113   if (f == hlinfo->mouse_face_mouse_frame)
1114     {
1115       /* Don't do highlighting for mouse motion during the update.  */
1116       hlinfo->mouse_face_defer = 1;
1118         /* If the frame needs to be redrawn,
1119            simply forget about any prior mouse highlighting.  */
1120       if (FRAME_GARBAGED_P (f))
1121         hlinfo->mouse_face_window = Qnil;
1123       /* (further code for mouse faces ifdef'd out in other terms elided) */
1124     }
1126   unblock_input ();
1130 static void
1131 ns_update_window_end (struct window *w, bool cursor_on_p,
1132                       bool mouse_face_overwritten_p)
1133 /* --------------------------------------------------------------------------
1134    Finished a grouped sequence of drawing calls
1135    external (RIF) call; for one window called before update_end
1136    -------------------------------------------------------------------------- */
1138   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1140   /* note: this fn is nearly identical in all terms */
1141   if (!w->pseudo_window_p)
1142     {
1143       block_input ();
1145       if (cursor_on_p)
1146         display_and_set_cursor (w, 1,
1147                                 w->output_cursor.hpos, w->output_cursor.vpos,
1148                                 w->output_cursor.x, w->output_cursor.y);
1150       if (draw_window_fringes (w, 1))
1151         {
1152           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1153             x_draw_right_divider (w);
1154           else
1155             x_draw_vertical_border (w);
1156         }
1158       unblock_input ();
1159     }
1161   /* If a row with mouse-face was overwritten, arrange for
1162      frame_up_to_date to redisplay the mouse highlight.  */
1163   if (mouse_face_overwritten_p)
1164     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1168 static void
1169 ns_update_end (struct frame *f)
1170 /* --------------------------------------------------------------------------
1171    Finished a grouped sequence of drawing calls
1172    external (RIF) call; for whole frame, called after update_window_end
1173    -------------------------------------------------------------------------- */
1175   EmacsView *view = FRAME_NS_VIEW (f);
1177   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1179 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1180   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1182   block_input ();
1184   [view unlockFocus];
1185   [[view window] flushWindow];
1187   unblock_input ();
1188   ns_updating_frame = NULL;
1191 static void
1192 ns_focus (struct frame *f, NSRect *r, int n)
1193 /* --------------------------------------------------------------------------
1194    Internal: Focus on given frame.  During small local updates this is used to
1195      draw, however during large updates, ns_update_begin and ns_update_end are
1196      called to wrap the whole thing, in which case these calls are stubbed out.
1197      Except, on GNUstep, we accumulate the rectangle being drawn into, because
1198      the back end won't do this automatically, and will just end up flushing
1199      the entire window.
1200    -------------------------------------------------------------------------- */
1202   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1203   if (r != NULL)
1204     {
1205       NSTRACE_RECT ("r", *r);
1206     }
1208   if (f != ns_updating_frame)
1209     {
1210       NSView *view = FRAME_NS_VIEW (f);
1211       if (view != focus_view)
1212         {
1213           if (focus_view != NULL)
1214             {
1215               [focus_view unlockFocus];
1216               [[focus_view window] flushWindow];
1217 /*debug_lock--; */
1218             }
1220           if (view)
1221             [view lockFocus];
1222           focus_view = view;
1223 /*if (view) debug_lock++; */
1224         }
1225     }
1227   /* clipping */
1228   if (r)
1229     {
1230       [[NSGraphicsContext currentContext] saveGraphicsState];
1231       if (n == 2)
1232         NSRectClipList (r, 2);
1233       else
1234         NSRectClip (*r);
1235       gsaved = YES;
1236     }
1240 static void
1241 ns_unfocus (struct frame *f)
1242 /* --------------------------------------------------------------------------
1243      Internal: Remove focus on given frame
1244    -------------------------------------------------------------------------- */
1246   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1248   if (gsaved)
1249     {
1250       [[NSGraphicsContext currentContext] restoreGraphicsState];
1251       gsaved = NO;
1252     }
1254   if (f != ns_updating_frame)
1255     {
1256       if (focus_view != NULL)
1257         {
1258           [focus_view unlockFocus];
1259           [[focus_view window] flushWindow];
1260           focus_view = NULL;
1261 /*debug_lock--; */
1262         }
1263     }
1267 static void
1268 ns_clip_to_row (struct window *w, struct glyph_row *row,
1269                 enum glyph_row_area area, BOOL gc)
1270 /* --------------------------------------------------------------------------
1271      Internal (but parallels other terms): Focus drawing on given row
1272    -------------------------------------------------------------------------- */
1274   struct frame *f = XFRAME (WINDOW_FRAME (w));
1275   NSRect clip_rect;
1276   int window_x, window_y, window_width;
1278   window_box (w, area, &window_x, &window_y, &window_width, 0);
1280   clip_rect.origin.x = window_x;
1281   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1282   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1283   clip_rect.size.width = window_width;
1284   clip_rect.size.height = row->visible_height;
1286   ns_focus (f, &clip_rect, 1);
1290 /* ==========================================================================
1292     Visible bell and beep.
1294    ========================================================================== */
1297 // This bell implementation shows the visual bell image asynchronously
1298 // from the rest of Emacs. This is done by adding a NSView to the
1299 // superview of the Emacs window and removing it using a timer.
1301 // Unfortunately, some Emacs operations, like scrolling, is done using
1302 // low-level primitives that copy the content of the window, including
1303 // the bell image. To some extent, this is handled by removing the
1304 // image prior to scrolling and marking that the window is in need for
1305 // redisplay.
1307 // To test this code, make sure that there is no artifacts of the bell
1308 // image in the following situations. Use a non-empty buffer (like the
1309 // tutorial) to ensure that a scroll is performed:
1311 // * Single-window: C-g C-v
1313 // * Side-by-windows: C-x 3 C-g C-v
1315 // * Windows above each other: C-x 2 C-g C-v
1317 @interface EmacsBell : NSImageView
1319   // Number of currently active bell:s.
1320   unsigned int nestCount;
1321   NSView * mView;
1322   bool isAttached;
1324 - (void)show:(NSView *)view;
1325 - (void)hide;
1326 - (void)remove;
1327 @end
1329 @implementation EmacsBell
1331 - (id)init
1333   NSTRACE ("[EmacsBell init]");
1334   if ((self = [super init]))
1335     {
1336       nestCount = 0;
1337       isAttached = false;
1338 #ifdef NS_IMPL_GNUSTEP
1339       // GNUstep doesn't provide named images.  This was reported in
1340       // 2011, see https://savannah.gnu.org/bugs/?33396
1341       //
1342       // As a drop in replacement, a semitransparent gray square is used.
1343       self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1344       [self.image lockFocus];
1345       [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1346       NSRectFill(NSMakeRect(0, 0, 32, 32));
1347       [self.image unlockFocus];
1348 #else
1349       self.image = [NSImage imageNamed:NSImageNameCaution];
1350       [self.image setSize:NSMakeSize(self.image.size.width * 5,
1351                                      self.image.size.height * 5)];
1352 #endif
1353     }
1354   return self;
1357 - (void)show:(NSView *)view
1359   NSTRACE ("[EmacsBell show:]");
1360   NSTRACE_MSG ("nestCount: %u", nestCount);
1362   // Show the image, unless it's already shown.
1363   if (nestCount == 0)
1364     {
1365       NSRect rect = [view bounds];
1366       NSPoint pos;
1367       pos.x = rect.origin.x + (rect.size.width  - self.image.size.width )/2;
1368       pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1370       [self setFrameOrigin:pos];
1371       [self setFrameSize:self.image.size];
1373       isAttached = true;
1374       mView = view;
1375       [[[view window] contentView] addSubview:self
1376                                    positioned:NSWindowAbove
1377                                    relativeTo:nil];
1378     }
1380   ++nestCount;
1382   [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1386 - (void)hide
1388   // Note: Trace output from this method isn't shown, reason unknown.
1389   // NSTRACE ("[EmacsBell hide]");
1391   if (nestCount > 0)
1392     --nestCount;
1394   // Remove the image once the last bell became inactive.
1395   if (nestCount == 0)
1396     {
1397       [self remove];
1398     }
1402 -(void)remove
1404   NSTRACE ("[EmacsBell remove]");
1405   if (isAttached)
1406     {
1407       NSTRACE_MSG ("removeFromSuperview");
1408       [self removeFromSuperview];
1409       mView.needsDisplay = YES;
1410       isAttached = false;
1411     }
1414 @end
1417 static EmacsBell * bell_view = nil;
1419 static void
1420 ns_ring_bell (struct frame *f)
1421 /* --------------------------------------------------------------------------
1422      "Beep" routine
1423    -------------------------------------------------------------------------- */
1425   NSTRACE ("ns_ring_bell");
1426   if (visible_bell)
1427     {
1428       struct frame *frame = SELECTED_FRAME ();
1429       NSView *view;
1431       if (bell_view == nil)
1432         {
1433           bell_view = [[EmacsBell alloc] init];
1434           [bell_view retain];
1435         }
1437       block_input ();
1439       view = FRAME_NS_VIEW (frame);
1440       if (view != nil)
1441         {
1442           [bell_view show:view];
1443         }
1445       unblock_input ();
1446     }
1447   else
1448     {
1449       NSBeep ();
1450     }
1454 static void
1455 hide_bell (void)
1456 /* --------------------------------------------------------------------------
1457      Ensure the bell is hidden.
1458    -------------------------------------------------------------------------- */
1460   NSTRACE ("hide_bell");
1462   if (bell_view != nil)
1463     {
1464       [bell_view remove];
1465     }
1469 /* ==========================================================================
1471     Frame / window manager related functions
1473    ========================================================================== */
1476 static void
1477 ns_raise_frame (struct frame *f, BOOL make_key)
1478 /* --------------------------------------------------------------------------
1479      Bring window to foreground and if make_key is YES, give it focus.
1480    -------------------------------------------------------------------------- */
1482   NSView *view;
1484   check_window_system (f);
1485   view = FRAME_NS_VIEW (f);
1486   block_input ();
1487   if (FRAME_VISIBLE_P (f))
1488     {
1489       if (make_key)
1490         [[view window] makeKeyAndOrderFront: NSApp];
1491       else
1492         [[view window] orderFront: NSApp];
1493     }
1494   unblock_input ();
1498 static void
1499 ns_lower_frame (struct frame *f)
1500 /* --------------------------------------------------------------------------
1501      Send window to back
1502    -------------------------------------------------------------------------- */
1504   NSView *view;
1506   check_window_system (f);
1507   view = FRAME_NS_VIEW (f);
1508   block_input ();
1509   [[view window] orderBack: NSApp];
1510   unblock_input ();
1514 static void
1515 ns_frame_raise_lower (struct frame *f, bool raise)
1516 /* --------------------------------------------------------------------------
1517      External (hook)
1518    -------------------------------------------------------------------------- */
1520   NSTRACE ("ns_frame_raise_lower");
1522   if (raise)
1523     ns_raise_frame (f, YES);
1524   else
1525     ns_lower_frame (f);
1529 static void
1530 ns_frame_rehighlight (struct frame *frame)
1531 /* --------------------------------------------------------------------------
1532      External (hook): called on things like window switching within frame
1533    -------------------------------------------------------------------------- */
1535   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1536   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1538   NSTRACE ("ns_frame_rehighlight");
1539   if (dpyinfo->x_focus_frame)
1540     {
1541       dpyinfo->x_highlight_frame
1542         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1543            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1544            : dpyinfo->x_focus_frame);
1545       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1546         {
1547           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1548           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1549         }
1550     }
1551   else
1552       dpyinfo->x_highlight_frame = 0;
1554   if (dpyinfo->x_highlight_frame &&
1555          dpyinfo->x_highlight_frame != old_highlight)
1556     {
1557       if (old_highlight)
1558         {
1559           x_update_cursor (old_highlight, 1);
1560           x_set_frame_alpha (old_highlight);
1561         }
1562       if (dpyinfo->x_highlight_frame)
1563         {
1564           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1565           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1566         }
1567     }
1571 void
1572 x_make_frame_visible (struct frame *f)
1573 /* --------------------------------------------------------------------------
1574      External: Show the window (X11 semantics)
1575    -------------------------------------------------------------------------- */
1577   NSTRACE ("x_make_frame_visible");
1578   /* XXX: at some points in past this was not needed, as the only place that
1579      called this (frame.c:Fraise_frame ()) also called raise_lower;
1580      if this ends up the case again, comment this out again. */
1581   if (!FRAME_VISIBLE_P (f))
1582     {
1583       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1584       NSWindow *window = [view window];
1586       SET_FRAME_VISIBLE (f, 1);
1587       ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f));
1589       /* Making a new frame from a fullscreen frame will make the new frame
1590          fullscreen also.  So skip handleFS as this will print an error.  */
1591       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1592           && [view isFullscreen])
1593         return;
1595       if (f->want_fullscreen != FULLSCREEN_NONE)
1596         {
1597           block_input ();
1598           [view handleFS];
1599           unblock_input ();
1600         }
1602       /* Making a frame invisible seems to break the parent->child
1603          relationship, so reinstate it. */
1604       if ([window parentWindow] == nil && FRAME_PARENT_FRAME (f) != NULL)
1605         {
1606           NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1608           block_input ();
1609           [parent addChildWindow: window
1610                          ordered: NSWindowAbove];
1611           unblock_input ();
1613           /* If the parent frame moved while the child frame was
1614              invisible, the child frame's position won't have been
1615              updated.  Make sure it's in the right place now. */
1616           x_set_offset(f, f->left_pos, f->top_pos, 0);
1617         }
1618     }
1622 void
1623 x_make_frame_invisible (struct frame *f)
1624 /* --------------------------------------------------------------------------
1625      External: Hide the window (X11 semantics)
1626    -------------------------------------------------------------------------- */
1628   NSView *view;
1629   NSTRACE ("x_make_frame_invisible");
1630   check_window_system (f);
1631   view = FRAME_NS_VIEW (f);
1632   [[view window] orderOut: NSApp];
1633   SET_FRAME_VISIBLE (f, 0);
1634   SET_FRAME_ICONIFIED (f, 0);
1638 void
1639 x_iconify_frame (struct frame *f)
1640 /* --------------------------------------------------------------------------
1641      External: Iconify window
1642    -------------------------------------------------------------------------- */
1644   NSView *view;
1645   struct ns_display_info *dpyinfo;
1647   NSTRACE ("x_iconify_frame");
1648   check_window_system (f);
1649   view = FRAME_NS_VIEW (f);
1650   dpyinfo = FRAME_DISPLAY_INFO (f);
1652   if (dpyinfo->x_highlight_frame == f)
1653     dpyinfo->x_highlight_frame = 0;
1655   if ([[view window] windowNumber] <= 0)
1656     {
1657       /* the window is still deferred.  Make it very small, bring it
1658          on screen and order it out. */
1659       NSRect s = { { 100, 100}, {0, 0} };
1660       NSRect t;
1661       t = [[view window] frame];
1662       [[view window] setFrame: s display: NO];
1663       [[view window] orderBack: NSApp];
1664       [[view window] orderOut: NSApp];
1665       [[view window] setFrame: t display: NO];
1666     }
1668   /* Processing input while Emacs is being minimized can cause a
1669      crash, so block it for the duration. */
1670   block_input();
1671   [[view window] miniaturize: NSApp];
1672   unblock_input();
1675 /* Free X resources of frame F.  */
1677 void
1678 x_free_frame_resources (struct frame *f)
1680   NSView *view;
1681   struct ns_display_info *dpyinfo;
1682   Mouse_HLInfo *hlinfo;
1684   NSTRACE ("x_free_frame_resources");
1685   check_window_system (f);
1686   view = FRAME_NS_VIEW (f);
1687   dpyinfo = FRAME_DISPLAY_INFO (f);
1688   hlinfo = MOUSE_HL_INFO (f);
1690   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1692   block_input ();
1694   free_frame_menubar (f);
1695   free_frame_faces (f);
1697   if (f == dpyinfo->x_focus_frame)
1698     dpyinfo->x_focus_frame = 0;
1699   if (f == dpyinfo->x_highlight_frame)
1700     dpyinfo->x_highlight_frame = 0;
1701   if (f == hlinfo->mouse_face_mouse_frame)
1702     reset_mouse_highlight (hlinfo);
1704   if (f->output_data.ns->miniimage != nil)
1705     [f->output_data.ns->miniimage release];
1707   [[view window] close];
1708   [view release];
1710   xfree (f->output_data.ns);
1712   unblock_input ();
1715 void
1716 x_destroy_window (struct frame *f)
1717 /* --------------------------------------------------------------------------
1718      External: Delete the window
1719    -------------------------------------------------------------------------- */
1721   NSTRACE ("x_destroy_window");
1723   /* If this frame has a parent window, detach it as not doing so can
1724      cause a crash in GNUStep. */
1725   if (FRAME_PARENT_FRAME (f) != NULL)
1726     {
1727       NSWindow *child = [FRAME_NS_VIEW (f) window];
1728       NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1730       [parent removeChildWindow: child];
1731     }
1733   check_window_system (f);
1734   x_free_frame_resources (f);
1735   ns_window_num--;
1739 void
1740 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1741 /* --------------------------------------------------------------------------
1742      External: Position the window
1743    -------------------------------------------------------------------------- */
1745   NSView *view = FRAME_NS_VIEW (f);
1746   NSArray *screens = [NSScreen screens];
1747   NSScreen *fscreen = [screens objectAtIndex: 0];
1748   NSScreen *screen = [[view window] screen];
1750   NSTRACE ("x_set_offset");
1752   block_input ();
1754   f->left_pos = xoff;
1755   f->top_pos = yoff;
1757   if (view != nil && screen && fscreen)
1758     {
1759       f->left_pos = f->size_hint_flags & XNegative
1760         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1761         : f->left_pos;
1762       /* We use visibleFrame here to take menu bar into account.
1763          Ideally we should also adjust left/top with visibleFrame.origin.  */
1765       f->top_pos = f->size_hint_flags & YNegative
1766         ? ([screen visibleFrame].size.height + f->top_pos
1767            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1768            - FRAME_TOOLBAR_HEIGHT (f))
1769         : f->top_pos;
1770 #ifdef NS_IMPL_GNUSTEP
1771       if (FRAME_PARENT_FRAME (f) == NULL)
1772         {
1773           if (f->left_pos < 100)
1774             f->left_pos = 100;  /* don't overlap menu */
1775         }
1776 #endif
1777       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1778          menu bar.  */
1779       NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
1780                                                 + NS_PARENT_WINDOW_LEFT_POS (f)),
1781                                 SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
1782                                                 - f->top_pos));
1783       NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1784       [[view window] setFrameTopLeftPoint: pt];
1785       f->size_hint_flags &= ~(XNegative|YNegative);
1786     }
1788   unblock_input ();
1792 void
1793 x_set_window_size (struct frame *f,
1794                    bool change_gravity,
1795                    int width,
1796                    int height,
1797                    bool pixelwise)
1798 /* --------------------------------------------------------------------------
1799      Adjust window pixel size based on given character grid size
1800      Impl is a bit more complex than other terms, need to do some
1801      internal clipping.
1802    -------------------------------------------------------------------------- */
1804   EmacsView *view = FRAME_NS_VIEW (f);
1805   NSWindow *window = [view window];
1806   NSRect wr = [window frame];
1807   int pixelwidth, pixelheight;
1808   int orig_height = wr.size.height;
1810   NSTRACE ("x_set_window_size");
1812   if (view == nil)
1813     return;
1815   NSTRACE_RECT ("current", wr);
1816   NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1817   NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1819   block_input ();
1821   if (pixelwise)
1822     {
1823       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1824       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1825     }
1826   else
1827     {
1828       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1829       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1830     }
1832   wr.size.width = pixelwidth + f->border_width;
1833   wr.size.height = pixelheight;
1834   if (! [view isFullscreen])
1835     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1836       + FRAME_TOOLBAR_HEIGHT (f);
1838   /* Do not try to constrain to this screen.  We may have multiple
1839      screens, and want Emacs to span those.  Constraining to screen
1840      prevents that, and that is not nice to the user.  */
1841  if (f->output_data.ns->zooming)
1842    f->output_data.ns->zooming = 0;
1843  else
1844    wr.origin.y += orig_height - wr.size.height;
1846  frame_size_history_add
1847    (f, Qx_set_window_size_1, width, height,
1848     list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1849            Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1850            make_number (f->border_width),
1851            make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1852            make_number (FRAME_TOOLBAR_HEIGHT (f))));
1854   [window setFrame: wr display: YES];
1856   [view updateFrameSize: NO];
1857   unblock_input ();
1860 #ifdef NS_IMPL_COCOA
1861 void
1862 x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1863 /* --------------------------------------------------------------------------
1864      Set frame F's `undecorated' parameter.  If non-nil, F's window-system
1865      window is drawn without decorations, title, minimize/maximize boxes
1866      and external borders.  This usually means that the window cannot be
1867      dragged, resized, iconified, maximized or deleted with the mouse.  If
1868      nil, draw the frame with all the elements listed above unless these
1869      have been suspended via window manager settings.
1871      GNUStep cannot change an existing window's style.
1872    -------------------------------------------------------------------------- */
1874   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1875   NSWindow *window = [view window];
1877   NSTRACE ("x_set_undecorated");
1879   if (!EQ (new_value, old_value))
1880     {
1881       block_input ();
1883       if (NILP (new_value))
1884         {
1885           FRAME_UNDECORATED (f) = false;
1886           [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
1887                                   ^ FRAME_UNDECORATED_FLAGS)];
1889           [view createToolbar: f];
1890         }
1891       else
1892         {
1893           [window setToolbar: nil];
1894           /* Do I need to release the toolbar here? */
1896           FRAME_UNDECORATED (f) = true;
1897           [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS)
1898                                  ^ FRAME_DECORATED_FLAGS)];
1899         }
1901       /* At this point it seems we don't have an active NSResponder,
1902          so some key presses (TAB) are swallowed by the system. */
1903       [window makeFirstResponder: view];
1905       [view updateFrameSize: NO];
1906       unblock_input ();
1907     }
1909 #endif /* NS_IMPL_COCOA */
1911 void
1912 x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1913 /* --------------------------------------------------------------------------
1914      Set frame F's `parent-frame' parameter.  If non-nil, make F a child
1915      frame of the frame specified by that parameter.  Technically, this
1916      makes F's window-system window a child window of the parent frame's
1917      window-system window.  If nil, make F's window-system window a
1918      top-level window--a child of its display's root window.
1920      A child frame's `left' and `top' parameters specify positions
1921      relative to the top-left corner of its parent frame's native
1922      rectangle.  On macOS moving a parent frame moves all its child
1923      frames too, keeping their position relative to the parent
1924      unaltered.  When a parent frame is iconified or made invisible, its
1925      child frames are made invisible.  When a parent frame is deleted,
1926      its child frames are deleted too.
1928      Whether a child frame has a tool bar may be window-system or window
1929      manager dependent.  It's advisable to disable it via the frame
1930      parameter settings.
1932      Some window managers may not honor this parameter.
1933    -------------------------------------------------------------------------- */
1935   struct frame *p = NULL;
1936   NSWindow *parent, *child;
1938   NSTRACE ("x_set_parent_frame");
1940   if (!NILP (new_value)
1941       && (!FRAMEP (new_value)
1942           || !FRAME_LIVE_P (p = XFRAME (new_value))
1943           || !FRAME_X_P (p)))
1944     {
1945       store_frame_param (f, Qparent_frame, old_value);
1946       error ("Invalid specification of `parent-frame'");
1947     }
1949   if (p != FRAME_PARENT_FRAME (f))
1950     {
1951       parent = [FRAME_NS_VIEW (p) window];
1952       child = [FRAME_NS_VIEW (f) window];
1954       block_input ();
1955       [parent addChildWindow: child
1956                      ordered: NSWindowAbove];
1957       unblock_input ();
1959       fset_parent_frame (f, new_value);
1960     }
1963 void
1964 x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1965 /* Set frame F's `no-focus-on-map' parameter which, if non-nil, means
1966  * that F's window-system window does not want to receive input focus
1967  * when it is mapped.  (A frame's window is mapped when the frame is
1968  * displayed for the first time and when the frame changes its state
1969  * from `iconified' or `invisible' to `visible'.)
1971  * Some window managers may not honor this parameter. */
1973   NSTRACE ("x_set_no_focus_on_map");
1975   if (!EQ (new_value, old_value))
1976     {
1977       FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
1978     }
1981 void
1982 x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1983 /*  Set frame F's `no-accept-focus' parameter which, if non-nil, hints
1984  * that F's window-system window does not want to receive input focus
1985  * via mouse clicks or by moving the mouse into it.
1987  * If non-nil, this may have the unwanted side-effect that a user cannot
1988  * scroll a non-selected frame with the mouse.
1990  * Some window managers may not honor this parameter. */
1992   NSTRACE ("x_set_no_accept_focus");
1994   if (!EQ (new_value, old_value))
1995     FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
1998 void
1999 x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2000 /* Set frame F's `z-group' parameter.  If `above', F's window-system
2001    window is displayed above all windows that do not have the `above'
2002    property set.  If nil, F's window is shown below all windows that
2003    have the `above' property set and above all windows that have the
2004    `below' property set.  If `below', F's window is displayed below
2005    all windows that do.
2007    Some window managers may not honor this parameter. */
2009   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2010   NSWindow *window = [view window];
2012   NSTRACE ("x_set_z_group");
2014   if (NILP (new_value))
2015     {
2016       window.level = NSNormalWindowLevel;
2017       FRAME_Z_GROUP (f) = z_group_none;
2018     }
2019   else if (EQ (new_value, Qabove))
2020     {
2021       window.level = NSNormalWindowLevel + 1;
2022       FRAME_Z_GROUP (f) = z_group_above;
2023     }
2024   else if (EQ (new_value, Qabove_suspended))
2025     {
2026       /* Not sure what level this should be. */
2027       window.level = NSNormalWindowLevel + 1;
2028       FRAME_Z_GROUP (f) = z_group_above_suspended;
2029     }
2030   else if (EQ (new_value, Qbelow))
2031     {
2032       window.level = NSNormalWindowLevel - 1;
2033       FRAME_Z_GROUP (f) = z_group_below;
2034     }
2035   else
2036     error ("Invalid z-group specification");
2039 #ifdef NS_IMPL_COCOA
2040 void
2041 ns_set_appearance (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2043 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
2044   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2045   NSWindow *window = [view window];
2047   NSTRACE ("ns_set_appearance");
2049 #ifndef NSAppKitVersionNumber10_9
2050 #define NSAppKitVersionNumber10_9 1265
2051 #endif
2053   if (NSAppKitVersionNumber < NSAppKitVersionNumber10_9)
2054     return;
2056   if (EQ (new_value, Qdark))
2057     {
2058       window.appearance = [NSAppearance
2059                             appearanceNamed: NSAppearanceNameVibrantDark];
2060       FRAME_NS_APPEARANCE (f) = ns_appearance_vibrant_dark;
2061     }
2062   else
2063     {
2064       window.appearance = [NSAppearance
2065                             appearanceNamed: NSAppearanceNameAqua];
2066       FRAME_NS_APPEARANCE (f) = ns_appearance_aqua;
2067     }
2068 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */
2071 void
2072 ns_set_transparent_titlebar (struct frame *f, Lisp_Object new_value,
2073                              Lisp_Object old_value)
2075 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
2076   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2077   NSWindow *window = [view window];
2079   NSTRACE ("ns_set_transparent_titlebar");
2081   if ([window respondsToSelector: @selector(titlebarAppearsTransparent)]
2082       && !EQ (new_value, old_value))
2083     {
2084       window.titlebarAppearsTransparent = !NILP (new_value);
2085       FRAME_NS_TRANSPARENT_TITLEBAR (f) = !NILP (new_value);
2086     }
2087 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
2089 #endif /* NS_IMPL_COCOA */
2091 static void
2092 ns_fullscreen_hook (struct frame *f)
2094   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2096   NSTRACE ("ns_fullscreen_hook");
2098   if (!FRAME_VISIBLE_P (f))
2099     return;
2101    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
2102     {
2103       /* Old style fs don't initiate correctly if created from
2104          init/default-frame alist, so use a timer (not nice...).
2105       */
2106       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
2107                                      selector: @selector (handleFS)
2108                                      userInfo: nil repeats: NO];
2109       return;
2110     }
2112   block_input ();
2113   [view handleFS];
2114   unblock_input ();
2117 /* ==========================================================================
2119     Color management
2121    ========================================================================== */
2124 NSColor *
2125 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
2127   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2128   if (idx < 1 || idx >= color_table->avail)
2129     return nil;
2130   return color_table->colors[idx];
2134 unsigned long
2135 ns_index_color (NSColor *color, struct frame *f)
2137   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2138   ptrdiff_t idx;
2139   ptrdiff_t i;
2141   if (!color_table->colors)
2142     {
2143       color_table->size = NS_COLOR_CAPACITY;
2144       color_table->avail = 1; /* skip idx=0 as marker */
2145       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
2146       color_table->colors[0] = nil;
2147       color_table->empty_indices = [[NSMutableSet alloc] init];
2148     }
2150   /* Do we already have this color?  */
2151   for (i = 1; i < color_table->avail; i++)
2152     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
2153       return i;
2155   if ([color_table->empty_indices count] > 0)
2156     {
2157       NSNumber *index = [color_table->empty_indices anyObject];
2158       [color_table->empty_indices removeObject: index];
2159       idx = [index unsignedLongValue];
2160     }
2161   else
2162     {
2163       if (color_table->avail == color_table->size)
2164         color_table->colors =
2165           xpalloc (color_table->colors, &color_table->size, 1,
2166                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
2167       idx = color_table->avail++;
2168     }
2170   color_table->colors[idx] = color;
2171   [color retain];
2172 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
2173   return idx;
2177 static int
2178 ns_get_color (const char *name, NSColor **col)
2179 /* --------------------------------------------------------------------------
2180      Parse a color name
2181    -------------------------------------------------------------------------- */
2182 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
2183    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
2184    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
2186   NSColor *new = nil;
2187   static char hex[20];
2188   int scaling = 0;
2189   float r = -1.0, g, b;
2190   NSString *nsname = [NSString stringWithUTF8String: name];
2192   NSTRACE ("ns_get_color(%s, **)", name);
2194   block_input ();
2196   if ([nsname isEqualToString: @"ns_selection_bg_color"])
2197     {
2198 #ifdef NS_IMPL_COCOA
2199       NSString *defname = [[NSUserDefaults standardUserDefaults]
2200                             stringForKey: @"AppleHighlightColor"];
2201       if (defname != nil)
2202         nsname = defname;
2203       else
2204 #endif
2205       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
2206         {
2207           *col = [new colorUsingDefaultColorSpace];
2208           unblock_input ();
2209           return 0;
2210         }
2211       else
2212         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
2214       name = [nsname UTF8String];
2215     }
2216   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
2217     {
2218       /* NOTE: macOS applications normally don't set foreground
2219          selection, but text may be unreadable if we don't.
2220       */
2221       if ((new = [NSColor selectedTextColor]) != nil)
2222         {
2223           *col = [new colorUsingDefaultColorSpace];
2224           unblock_input ();
2225           return 0;
2226         }
2228       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
2229       name = [nsname UTF8String];
2230     }
2232   /* First, check for some sort of numeric specification. */
2233   hex[0] = '\0';
2235   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
2236     {
2237       NSScanner *scanner = [NSScanner scannerWithString: nsname];
2238       [scanner scanFloat: &r];
2239       [scanner scanFloat: &g];
2240       [scanner scanFloat: &b];
2241     }
2242   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
2243     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2244   else if (name[0] == '#')        /* An old X11 format; convert to newer */
2245     {
2246       int len = (strlen(name) - 1);
2247       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2248       int i;
2249       scaling = strlen(name+start) / 3;
2250       for (i = 0; i < 3; i++)
2251         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2252                  name + start + i * scaling);
2253       hex[3 * (scaling + 1) - 1] = '\0';
2254     }
2256   if (hex[0])
2257     {
2258       unsigned int rr, gg, bb;
2259       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2260       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2261         {
2262           r = rr / fscale;
2263           g = gg / fscale;
2264           b = bb / fscale;
2265         }
2266     }
2268   if (r >= 0.0F)
2269     {
2270       *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2271       unblock_input ();
2272       return 0;
2273     }
2275   /* Otherwise, color is expected to be from a list */
2276   {
2277     NSEnumerator *lenum, *cenum;
2278     NSString *name;
2279     NSColorList *clist;
2281 #ifdef NS_IMPL_GNUSTEP
2282     /* XXX: who is wrong, the requestor or the implementation? */
2283     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2284         == NSOrderedSame)
2285       nsname = @"highlightColor";
2286 #endif
2288     lenum = [[NSColorList availableColorLists] objectEnumerator];
2289     while ( (clist = [lenum nextObject]) && new == nil)
2290       {
2291         cenum = [[clist allKeys] objectEnumerator];
2292         while ( (name = [cenum nextObject]) && new == nil )
2293           {
2294             if ([name compare: nsname
2295                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
2296               new = [clist colorWithKey: name];
2297           }
2298       }
2299   }
2301   if (new)
2302     *col = [new colorUsingDefaultColorSpace];
2303   unblock_input ();
2304   return new ? 0 : 1;
2309 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2310 /* --------------------------------------------------------------------------
2311      Convert a Lisp string object to a NS color
2312    -------------------------------------------------------------------------- */
2314   NSTRACE ("ns_lisp_to_color");
2315   if (STRINGP (color))
2316     return ns_get_color (SSDATA (color), col);
2317   else if (SYMBOLP (color))
2318     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2319   return 1;
2323 void
2324 ns_query_color(void *col, XColor *color_def, int setPixel)
2325 /* --------------------------------------------------------------------------
2326          Get ARGB values out of NSColor col and put them into color_def.
2327          If setPixel, set the pixel to a concatenated version.
2328          and set color_def pixel to the resulting index.
2329    -------------------------------------------------------------------------- */
2331   EmacsCGFloat r, g, b, a;
2333   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2334   color_def->red   = r * 65535;
2335   color_def->green = g * 65535;
2336   color_def->blue  = b * 65535;
2338   if (setPixel == YES)
2339     color_def->pixel
2340       = ARGB_TO_ULONG((int)(a*255),
2341                       (int)(r*255), (int)(g*255), (int)(b*255));
2345 bool
2346 ns_defined_color (struct frame *f,
2347                   const char *name,
2348                   XColor *color_def,
2349                   bool alloc,
2350                   bool makeIndex)
2351 /* --------------------------------------------------------------------------
2352          Return true if named color found, and set color_def rgb accordingly.
2353          If makeIndex and alloc are nonzero put the color in the color_table,
2354          and set color_def pixel to the resulting index.
2355          If makeIndex is zero, set color_def pixel to ARGB.
2356          Return false if not found
2357    -------------------------------------------------------------------------- */
2359   NSColor *col;
2360   NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2362   block_input ();
2363   if (ns_get_color (name, &col) != 0) /* Color not found  */
2364     {
2365       unblock_input ();
2366       return 0;
2367     }
2368   if (makeIndex && alloc)
2369     color_def->pixel = ns_index_color (col, f);
2370   ns_query_color (col, color_def, !makeIndex);
2371   unblock_input ();
2372   return 1;
2376 void
2377 x_set_frame_alpha (struct frame *f)
2378 /* --------------------------------------------------------------------------
2379      change the entire-frame transparency
2380    -------------------------------------------------------------------------- */
2382   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2383   double alpha = 1.0;
2384   double alpha_min = 1.0;
2386   NSTRACE ("x_set_frame_alpha");
2388   if (dpyinfo->x_highlight_frame == f)
2389     alpha = f->alpha[0];
2390   else
2391     alpha = f->alpha[1];
2393   if (FLOATP (Vframe_alpha_lower_limit))
2394     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2395   else if (INTEGERP (Vframe_alpha_lower_limit))
2396     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2398   if (alpha < 0.0)
2399     return;
2400   else if (1.0 < alpha)
2401     alpha = 1.0;
2402   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2403     alpha = alpha_min;
2405 #ifdef NS_IMPL_COCOA
2406   {
2407     EmacsView *view = FRAME_NS_VIEW (f);
2408   [[view window] setAlphaValue: alpha];
2409   }
2410 #endif
2414 /* ==========================================================================
2416     Mouse handling
2418    ========================================================================== */
2421 void
2422 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2423 /* --------------------------------------------------------------------------
2424      Programmatically reposition mouse pointer in pixel coordinates
2425    -------------------------------------------------------------------------- */
2427   NSTRACE ("frame_set_mouse_pixel_position");
2429   /* FIXME: what about GNUstep? */
2430 #ifdef NS_IMPL_COCOA
2431   CGPoint mouse_pos =
2432     CGPointMake(f->left_pos + pix_x,
2433                 f->top_pos + pix_y +
2434                 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
2435   CGWarpMouseCursorPosition (mouse_pos);
2436 #endif
2439 static int
2440 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2441 /*   ------------------------------------------------------------------------
2442      Called by EmacsView on mouseMovement events.  Passes on
2443      to emacs mainstream code if we moved off of a rect of interest
2444      known as last_mouse_glyph.
2445      ------------------------------------------------------------------------ */
2447   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2448   NSRect *r;
2450 //  NSTRACE ("note_mouse_movement");
2452   dpyinfo->last_mouse_motion_frame = frame;
2453   r = &dpyinfo->last_mouse_glyph;
2455   /* Note, this doesn't get called for enter/leave, since we don't have a
2456      position.  Those are taken care of in the corresponding NSView methods. */
2458   /* has movement gone beyond last rect we were tracking? */
2459   if (x < r->origin.x || x >= r->origin.x + r->size.width
2460       || y < r->origin.y || y >= r->origin.y + r->size.height)
2461     {
2462       ns_update_begin (frame);
2463       frame->mouse_moved = 1;
2464       note_mouse_highlight (frame, x, y);
2465       remember_mouse_glyph (frame, x, y, r);
2466       ns_update_end (frame);
2467       return 1;
2468     }
2470   return 0;
2474 static void
2475 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2476                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2477                    Time *time)
2478 /* --------------------------------------------------------------------------
2479     External (hook): inform emacs about mouse position and hit parts.
2480     If a scrollbar is being dragged, set bar_window, part, x, y, time.
2481     x & y should be position in the scrollbar (the whole bar, not the handle)
2482     and length of scrollbar respectively
2483    -------------------------------------------------------------------------- */
2485   id view;
2486   NSPoint position;
2487   Lisp_Object frame, tail;
2488   struct frame *f;
2489   struct ns_display_info *dpyinfo;
2491   NSTRACE ("ns_mouse_position");
2493   if (*fp == NULL)
2494     {
2495       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2496       return;
2497     }
2499   dpyinfo = FRAME_DISPLAY_INFO (*fp);
2501   block_input ();
2503   /* Clear the mouse-moved flag for every frame on this display.  */
2504   FOR_EACH_FRAME (tail, frame)
2505     if (FRAME_NS_P (XFRAME (frame))
2506         && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2507       XFRAME (frame)->mouse_moved = 0;
2509   dpyinfo->last_mouse_scroll_bar = nil;
2510   if (dpyinfo->last_mouse_frame
2511       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2512     f = dpyinfo->last_mouse_frame;
2513   else
2514     f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2516   if (f && FRAME_NS_P (f))
2517     {
2518       view = FRAME_NS_VIEW (*fp);
2520       position = [[view window] mouseLocationOutsideOfEventStream];
2521       position = [view convertPoint: position fromView: nil];
2522       remember_mouse_glyph (f, position.x, position.y,
2523                             &dpyinfo->last_mouse_glyph);
2524       NSTRACE_POINT ("position", position);
2526       if (bar_window) *bar_window = Qnil;
2527       if (part) *part = scroll_bar_above_handle;
2529       if (x) XSETINT (*x, lrint (position.x));
2530       if (y) XSETINT (*y, lrint (position.y));
2531       if (time)
2532         *time = dpyinfo->last_mouse_movement_time;
2533       *fp = f;
2534     }
2536   unblock_input ();
2540 static void
2541 ns_frame_up_to_date (struct frame *f)
2542 /* --------------------------------------------------------------------------
2543     External (hook): Fix up mouse highlighting right after a full update.
2544     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2545    -------------------------------------------------------------------------- */
2547   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2549   if (FRAME_NS_P (f))
2550     {
2551       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2552       if (f == hlinfo->mouse_face_mouse_frame)
2553         {
2554           block_input ();
2555           ns_update_begin(f);
2556           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2557                                 hlinfo->mouse_face_mouse_x,
2558                                 hlinfo->mouse_face_mouse_y);
2559           ns_update_end(f);
2560           unblock_input ();
2561         }
2562     }
2566 static void
2567 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2568 /* --------------------------------------------------------------------------
2569     External (RIF): set frame mouse pointer type.
2570    -------------------------------------------------------------------------- */
2572   NSTRACE ("ns_define_frame_cursor");
2573   if (FRAME_POINTER_TYPE (f) != cursor)
2574     {
2575       EmacsView *view = FRAME_NS_VIEW (f);
2576       FRAME_POINTER_TYPE (f) = cursor;
2577       [[view window] invalidateCursorRectsForView: view];
2578       /* Redisplay assumes this function also draws the changed frame
2579          cursor, but this function doesn't, so do it explicitly.  */
2580       x_update_cursor (f, 1);
2581     }
2586 /* ==========================================================================
2588     Keyboard handling
2590    ========================================================================== */
2593 static unsigned
2594 ns_convert_key (unsigned code)
2595 /* --------------------------------------------------------------------------
2596     Internal call used by NSView-keyDown.
2597    -------------------------------------------------------------------------- */
2599   const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2600   unsigned keysym;
2601   /* An array would be faster, but less easy to read. */
2602   for (keysym = 0; keysym < last_keysym; keysym += 2)
2603     if (code == convert_ns_to_X_keysym[keysym])
2604       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2605   return 0;
2606 /* if decide to use keyCode and Carbon table, use this line:
2607      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2611 char *
2612 x_get_keysym_name (int keysym)
2613 /* --------------------------------------------------------------------------
2614     Called by keyboard.c.  Not sure if the return val is important, except
2615     that it be unique.
2616    -------------------------------------------------------------------------- */
2618   static char value[16];
2619   NSTRACE ("x_get_keysym_name");
2620   sprintf (value, "%d", keysym);
2621   return value;
2626 /* ==========================================================================
2628     Block drawing operations
2630    ========================================================================== */
2633 static void
2634 ns_redraw_scroll_bars (struct frame *f)
2636   int i;
2637   id view;
2638   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2639   NSTRACE ("ns_redraw_scroll_bars");
2640   for (i =[subviews count]-1; i >= 0; i--)
2641     {
2642       view = [subviews objectAtIndex: i];
2643       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2644       [view display];
2645     }
2649 void
2650 ns_clear_frame (struct frame *f)
2651 /* --------------------------------------------------------------------------
2652       External (hook): Erase the entire frame
2653    -------------------------------------------------------------------------- */
2655   NSView *view = FRAME_NS_VIEW (f);
2656   NSRect r;
2658   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2660  /* comes on initial frame because we have
2661     after-make-frame-functions = select-frame */
2662  if (!FRAME_DEFAULT_FACE (f))
2663    return;
2665   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2667   r = [view bounds];
2669   block_input ();
2670   ns_focus (f, &r, 1);
2671   [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2672                             (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
2673   NSRectFill (r);
2674   ns_unfocus (f);
2676   /* as of 2006/11 or so this is now needed */
2677   ns_redraw_scroll_bars (f);
2678   unblock_input ();
2682 static void
2683 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2684 /* --------------------------------------------------------------------------
2685     External (RIF):  Clear section of frame
2686    -------------------------------------------------------------------------- */
2688   NSRect r = NSMakeRect (x, y, width, height);
2689   NSView *view = FRAME_NS_VIEW (f);
2690   struct face *face = FRAME_DEFAULT_FACE (f);
2692   if (!view || !face)
2693     return;
2695   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2697   r = NSIntersectionRect (r, [view frame]);
2698   ns_focus (f, &r, 1);
2699   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2701   NSRectFill (r);
2703   ns_unfocus (f);
2704   return;
2707 static void
2708 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2710   NSTRACE ("ns_copy_bits");
2712   if (FRAME_NS_VIEW (f))
2713     {
2714       hide_bell();              // Ensure the bell image isn't scrolled.
2716       ns_focus (f, &dest, 1);
2717       [FRAME_NS_VIEW (f) scrollRect: src
2718                                  by: NSMakeSize (dest.origin.x - src.origin.x,
2719                                                  dest.origin.y - src.origin.y)];
2720       ns_unfocus (f);
2721     }
2724 static void
2725 ns_scroll_run (struct window *w, struct run *run)
2726 /* --------------------------------------------------------------------------
2727     External (RIF):  Insert or delete n lines at line vpos
2728    -------------------------------------------------------------------------- */
2730   struct frame *f = XFRAME (w->frame);
2731   int x, y, width, height, from_y, to_y, bottom_y;
2733   NSTRACE ("ns_scroll_run");
2735   /* begin copy from other terms */
2736   /* Get frame-relative bounding box of the text display area of W,
2737      without mode lines.  Include in this box the left and right
2738      fringe of W.  */
2739   window_box (w, ANY_AREA, &x, &y, &width, &height);
2741   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2742   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2743   bottom_y = y + height;
2745   if (to_y < from_y)
2746     {
2747       /* Scrolling up.  Make sure we don't copy part of the mode
2748          line at the bottom.  */
2749       if (from_y + run->height > bottom_y)
2750         height = bottom_y - from_y;
2751       else
2752         height = run->height;
2753     }
2754   else
2755     {
2756       /* Scrolling down.  Make sure we don't copy over the mode line.
2757          at the bottom.  */
2758       if (to_y + run->height > bottom_y)
2759         height = bottom_y - to_y;
2760       else
2761         height = run->height;
2762     }
2763   /* end copy from other terms */
2765   if (height == 0)
2766       return;
2768   block_input ();
2770   x_clear_cursor (w);
2772   {
2773     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2774     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2776     ns_copy_bits (f, srcRect , dstRect);
2777   }
2779   unblock_input ();
2783 static void
2784 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2785 /* --------------------------------------------------------------------------
2786     External (RIF): preparatory to fringe update after text was updated
2787    -------------------------------------------------------------------------- */
2789   struct frame *f;
2790   int width, height;
2792   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2794   /* begin copy from other terms */
2795   eassert (w);
2797   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2798     desired_row->redraw_fringe_bitmaps_p = 1;
2800   /* When a window has disappeared, make sure that no rest of
2801      full-width rows stays visible in the internal border.  */
2802   if (windows_or_buffers_changed
2803       && desired_row->full_width_p
2804       && (f = XFRAME (w->frame),
2805           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2806           width != 0)
2807       && (height = desired_row->visible_height,
2808           height > 0))
2809     {
2810       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2812       block_input ();
2813       ns_clear_frame_area (f, 0, y, width, height);
2814       ns_clear_frame_area (f,
2815                            FRAME_PIXEL_WIDTH (f) - width,
2816                            y, width, height);
2817       unblock_input ();
2818     }
2822 static void
2823 ns_shift_glyphs_for_insert (struct frame *f,
2824                            int x, int y, int width, int height,
2825                            int shift_by)
2826 /* --------------------------------------------------------------------------
2827     External (RIF): copy an area horizontally, don't worry about clearing src
2828    -------------------------------------------------------------------------- */
2830   NSRect srcRect = NSMakeRect (x, y, width, height);
2831   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2833   NSTRACE ("ns_shift_glyphs_for_insert");
2835   ns_copy_bits (f, srcRect, dstRect);
2840 /* ==========================================================================
2842     Character encoding and metrics
2844    ========================================================================== */
2847 static void
2848 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2849 /* --------------------------------------------------------------------------
2850      External (RIF); compute left/right overhang of whole string and set in s
2851    -------------------------------------------------------------------------- */
2853   struct font *font = s->font;
2855   if (s->char2b)
2856     {
2857       struct font_metrics metrics;
2858       unsigned int codes[2];
2859       codes[0] = *(s->char2b);
2860       codes[1] = *(s->char2b + s->nchars - 1);
2862       font->driver->text_extents (font, codes, 2, &metrics);
2863       s->left_overhang = -metrics.lbearing;
2864       s->right_overhang
2865         = metrics.rbearing > metrics.width
2866         ? metrics.rbearing - metrics.width : 0;
2867     }
2868   else
2869     {
2870       s->left_overhang = 0;
2871       if (EQ (font->driver->type, Qns))
2872         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2873           FONT_HEIGHT (font) * 0.2 : 0;
2874       else
2875         s->right_overhang = 0;
2876     }
2881 /* ==========================================================================
2883     Fringe and cursor drawing
2885    ========================================================================== */
2888 extern int max_used_fringe_bitmap;
2889 static void
2890 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2891                       struct draw_fringe_bitmap_params *p)
2892 /* --------------------------------------------------------------------------
2893     External (RIF); fringe-related
2894    -------------------------------------------------------------------------- */
2896   /* Fringe bitmaps comes in two variants, normal and periodic.  A
2897      periodic bitmap is used to create a continuous pattern.  Since a
2898      bitmap is rendered one text line at a time, the start offset (dh)
2899      of the bitmap varies.  Concretely, this is used for the empty
2900      line indicator.
2902      For a bitmap, "h + dh" is the full height and is always
2903      invariant.  For a normal bitmap "dh" is zero.
2905      For example, when the period is three and the full height is 72
2906      the following combinations exists:
2908        h=72 dh=0
2909        h=71 dh=1
2910        h=70 dh=2 */
2912   struct frame *f = XFRAME (WINDOW_FRAME (w));
2913   struct face *face = p->face;
2914   static EmacsImage **bimgs = NULL;
2915   static int nBimgs = 0;
2917   NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2918   NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2919                p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2921   /* grow bimgs if needed */
2922   if (nBimgs < max_used_fringe_bitmap)
2923     {
2924       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2925       memset (bimgs + nBimgs, 0,
2926               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2927       nBimgs = max_used_fringe_bitmap;
2928     }
2930   /* Must clip because of partially visible lines.  */
2931   ns_clip_to_row (w, row, ANY_AREA, YES);
2933   if (!p->overlay_p)
2934     {
2935       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2937       if (bx >= 0 && nx > 0)
2938         {
2939           NSRect r = NSMakeRect (bx, by, nx, ny);
2940           NSRectClip (r);
2941           [ns_lookup_indexed_color (face->background, f) set];
2942           NSRectFill (r);
2943         }
2944     }
2946   if (p->which)
2947     {
2948       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2949       EmacsImage *img = bimgs[p->which - 1];
2951       if (!img)
2952         {
2953           // Note: For "periodic" images, allocate one EmacsImage for
2954           // the base image, and use it for all dh:s.
2955           unsigned short *bits = p->bits;
2956           int full_height = p->h + p->dh;
2957           int i;
2958           unsigned char *cbits = xmalloc (full_height);
2960           for (i = 0; i < full_height; i++)
2961             cbits[i] = bits[i];
2962           img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2963                                          height: full_height
2964                                              fg: 0 bg: 0];
2965           bimgs[p->which - 1] = img;
2966           xfree (cbits);
2967         }
2969       NSTRACE_RECT ("r", r);
2971       NSRectClip (r);
2972       /* Since we composite the bitmap instead of just blitting it, we need
2973          to erase the whole background. */
2974       [ns_lookup_indexed_color(face->background, f) set];
2975       NSRectFill (r);
2977       {
2978         NSColor *bm_color;
2979         if (!p->cursor_p)
2980           bm_color = ns_lookup_indexed_color(face->foreground, f);
2981         else if (p->overlay_p)
2982           bm_color = ns_lookup_indexed_color(face->background, f);
2983         else
2984           bm_color = f->output_data.ns->cursor_color;
2985         [img setXBMColor: bm_color];
2986       }
2988 #ifdef NS_IMPL_COCOA
2989       // Note: For periodic images, the full image height is "h + hd".
2990       // By using the height h, a suitable part of the image is used.
2991       NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2993       NSTRACE_RECT ("fromRect", fromRect);
2995       [img drawInRect: r
2996               fromRect: fromRect
2997              operation: NSCompositingOperationSourceOver
2998               fraction: 1.0
2999            respectFlipped: YES
3000                 hints: nil];
3001 #else
3002       {
3003         NSPoint pt = r.origin;
3004         pt.y += p->h;
3005         [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
3006       }
3007 #endif
3008     }
3009   ns_unfocus (f);
3013 static void
3014 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3015                        int x, int y, enum text_cursor_kinds cursor_type,
3016                        int cursor_width, bool on_p, bool active_p)
3017 /* --------------------------------------------------------------------------
3018      External call (RIF): draw cursor.
3019      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
3020    -------------------------------------------------------------------------- */
3022   NSRect r, s;
3023   int fx, fy, h, cursor_height;
3024   struct frame *f = WINDOW_XFRAME (w);
3025   struct glyph *phys_cursor_glyph;
3026   struct glyph *cursor_glyph;
3027   struct face *face;
3028   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
3030   /* If cursor is out of bounds, don't draw garbage.  This can happen
3031      in mini-buffer windows when switching between echo area glyphs
3032      and mini-buffer.  */
3034   NSTRACE ("ns_draw_window_cursor");
3036   if (!on_p)
3037     return;
3039   w->phys_cursor_type = cursor_type;
3040   w->phys_cursor_on_p = on_p;
3042   if (cursor_type == NO_CURSOR)
3043     {
3044       w->phys_cursor_width = 0;
3045       return;
3046     }
3048   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
3049     {
3050       if (glyph_row->exact_window_width_line_p
3051           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
3052         {
3053           glyph_row->cursor_in_fringe_p = 1;
3054           draw_fringe_bitmap (w, glyph_row, 0);
3055         }
3056       return;
3057     }
3059   /* We draw the cursor (with NSRectFill), then draw the glyph on top
3060      (other terminals do it the other way round).  We must set
3061      w->phys_cursor_width to the cursor width.  For bar cursors, that
3062      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
3063   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
3065   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
3066      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
3067   if (cursor_type == BAR_CURSOR)
3068     {
3069       if (cursor_width < 1)
3070         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
3072       /* The bar cursor should never be wider than the glyph. */
3073       if (cursor_width < w->phys_cursor_width)
3074         w->phys_cursor_width = cursor_width;
3075     }
3076   /* If we have an HBAR, "cursor_width" MAY specify height. */
3077   else if (cursor_type == HBAR_CURSOR)
3078     {
3079       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
3080       if (cursor_height > glyph_row->height)
3081         cursor_height = glyph_row->height;
3082       if (h > cursor_height) // Cursor smaller than line height, move down
3083         fy += h - cursor_height;
3084       h = cursor_height;
3085     }
3087   r.origin.x = fx, r.origin.y = fy;
3088   r.size.height = h;
3089   r.size.width = w->phys_cursor_width;
3091   /* Prevent the cursor from being drawn outside the text area. */
3092   ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
3095   face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
3096   if (face && NS_FACE_BACKGROUND (face)
3097       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
3098     {
3099       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
3100       hollow_color = FRAME_CURSOR_COLOR (f);
3101     }
3102   else
3103     [FRAME_CURSOR_COLOR (f) set];
3105 #ifdef NS_IMPL_COCOA
3106   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
3107            atomic.  Cleaner ways of doing this should be investigated.
3108            One way would be to set a global variable DRAWING_CURSOR
3109            when making the call to draw_phys..(), don't focus in that
3110            case, then move the ns_unfocus() here after that call. */
3111   NSDisableScreenUpdates ();
3112 #endif
3114   switch (cursor_type)
3115     {
3116     case DEFAULT_CURSOR:
3117     case NO_CURSOR:
3118       break;
3119     case FILLED_BOX_CURSOR:
3120       NSRectFill (r);
3121       break;
3122     case HOLLOW_BOX_CURSOR:
3123       NSRectFill (r);
3124       [hollow_color set];
3125       NSRectFill (NSInsetRect (r, 1, 1));
3126       [FRAME_CURSOR_COLOR (f) set];
3127       break;
3128     case HBAR_CURSOR:
3129       NSRectFill (r);
3130       break;
3131     case BAR_CURSOR:
3132       s = r;
3133       /* If the character under cursor is R2L, draw the bar cursor
3134          on the right of its glyph, rather than on the left.  */
3135       cursor_glyph = get_phys_cursor_glyph (w);
3136       if ((cursor_glyph->resolved_level & 1) != 0)
3137         s.origin.x += cursor_glyph->pixel_width - s.size.width;
3139       NSRectFill (s);
3140       break;
3141     }
3142   ns_unfocus (f);
3144   /* draw the character under the cursor */
3145   if (cursor_type != NO_CURSOR)
3146     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3148 #ifdef NS_IMPL_COCOA
3149   NSEnableScreenUpdates ();
3150 #endif
3155 static void
3156 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
3157 /* --------------------------------------------------------------------------
3158      External (RIF): Draw a vertical line.
3159    -------------------------------------------------------------------------- */
3161   struct frame *f = XFRAME (WINDOW_FRAME (w));
3162   struct face *face;
3163   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
3165   NSTRACE ("ns_draw_vertical_window_border");
3167   face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
3169   ns_focus (f, &r, 1);
3170   if (face)
3171     [ns_lookup_indexed_color(face->foreground, f) set];
3173   NSRectFill(r);
3174   ns_unfocus (f);
3178 static void
3179 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3180 /* --------------------------------------------------------------------------
3181      External (RIF): Draw a window divider.
3182    -------------------------------------------------------------------------- */
3184   struct frame *f = XFRAME (WINDOW_FRAME (w));
3185   struct face *face;
3186   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
3188   NSTRACE ("ns_draw_window_divider");
3190   face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
3192   ns_focus (f, &r, 1);
3193   if (face)
3194     [ns_lookup_indexed_color(face->foreground, f) set];
3196   NSRectFill(r);
3197   ns_unfocus (f);
3200 static void
3201 ns_show_hourglass (struct frame *f)
3203   /* TODO: add NSProgressIndicator to all frames.  */
3206 static void
3207 ns_hide_hourglass (struct frame *f)
3209   /* TODO: remove NSProgressIndicator from all frames.  */
3212 /* ==========================================================================
3214     Glyph drawing operations
3216    ========================================================================== */
3218 static int
3219 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3220 /* --------------------------------------------------------------------------
3221     Wrapper utility to account for internal border width on full-width lines,
3222     and allow top full-width rows to hit the frame top.  nr should be pointer
3223     to two successive NSRects.  Number of rects actually used is returned.
3224    -------------------------------------------------------------------------- */
3226   int n = get_glyph_string_clip_rects (s, nr, 2);
3227   return n;
3230 /* --------------------------------------------------------------------
3231    Draw a wavy line under glyph string s. The wave fills wave_height
3232    pixels from y.
3234                     x          wave_length = 2
3235                                  --
3236                 y    *   *   *   *   *
3237                      |* * * * * * * * *
3238     wave_height = 3  | *   *   *   *
3239   --------------------------------------------------------------------- */
3241 static void
3242 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3244   int wave_height = 3, wave_length = 2;
3245   int y, dx, dy, odd, xmax;
3246   NSPoint a, b;
3247   NSRect waveClip;
3249   dx = wave_length;
3250   dy = wave_height - 1;
3251   y =  s->ybase - wave_height + 3;
3252   xmax = x + width;
3254   /* Find and set clipping rectangle */
3255   waveClip = NSMakeRect (x, y, width, wave_height);
3256   [[NSGraphicsContext currentContext] saveGraphicsState];
3257   NSRectClip (waveClip);
3259   /* Draw the waves */
3260   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3261   b.x = a.x + dx;
3262   odd = (int)(a.x/dx) % 2;
3263   a.y = b.y = y + 0.5;
3265   if (odd)
3266     a.y += dy;
3267   else
3268     b.y += dy;
3270   while (a.x <= xmax)
3271     {
3272       [NSBezierPath strokeLineFromPoint:a toPoint:b];
3273       a.x = b.x, a.y = b.y;
3274       b.x += dx, b.y = y + 0.5 + odd*dy;
3275       odd = !odd;
3276     }
3278   /* Restore previous clipping rectangle(s) */
3279   [[NSGraphicsContext currentContext] restoreGraphicsState];
3284 static void
3285 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3286                          NSColor *defaultCol, CGFloat width, CGFloat x)
3287 /* --------------------------------------------------------------------------
3288    Draw underline, overline, and strike-through on glyph string s.
3289    -------------------------------------------------------------------------- */
3291   if (s->for_overlaps)
3292     return;
3294   /* Do underline. */
3295   if (face->underline_p)
3296     {
3297       if (s->face->underline_type == FACE_UNDER_WAVE)
3298         {
3299           if (face->underline_defaulted_p)
3300             [defaultCol set];
3301           else
3302             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3304           ns_draw_underwave (s, width, x);
3305         }
3306       else if (s->face->underline_type == FACE_UNDER_LINE)
3307         {
3309           NSRect r;
3310           unsigned long thickness, position;
3312           /* If the prev was underlined, match its appearance. */
3313           if (s->prev && s->prev->face->underline_p
3314               && s->prev->face->underline_type == FACE_UNDER_LINE
3315               && s->prev->underline_thickness > 0)
3316             {
3317               thickness = s->prev->underline_thickness;
3318               position = s->prev->underline_position;
3319             }
3320           else
3321             {
3322               struct font *font = font_for_underline_metrics (s);
3323               unsigned long descent = s->y + s->height - s->ybase;
3325               /* Use underline thickness of font, defaulting to 1. */
3326               thickness = (font && font->underline_thickness > 0)
3327                 ? font->underline_thickness : 1;
3329               /* Determine the offset of underlining from the baseline. */
3330               if (x_underline_at_descent_line)
3331                 position = descent - thickness;
3332               else if (x_use_underline_position_properties
3333                        && font && font->underline_position >= 0)
3334                 position = font->underline_position;
3335               else if (font)
3336                 position = lround (font->descent / 2);
3337               else
3338                 position = underline_minimum_offset;
3340               position = max (position, underline_minimum_offset);
3342               /* Ensure underlining is not cropped. */
3343               if (descent <= position)
3344                 {
3345                   position = descent - 1;
3346                   thickness = 1;
3347                 }
3348               else if (descent < position + thickness)
3349                 thickness = 1;
3350             }
3352           s->underline_thickness = thickness;
3353           s->underline_position = position;
3355           r = NSMakeRect (x, s->ybase + position, width, thickness);
3357           if (face->underline_defaulted_p)
3358             [defaultCol set];
3359           else
3360             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3361           NSRectFill (r);
3362         }
3363     }
3364   /* Do overline. We follow other terms in using a thickness of 1
3365      and ignoring overline_margin. */
3366   if (face->overline_p)
3367     {
3368       NSRect r;
3369       r = NSMakeRect (x, s->y, width, 1);
3371       if (face->overline_color_defaulted_p)
3372         [defaultCol set];
3373       else
3374         [ns_lookup_indexed_color (face->overline_color, s->f) set];
3375       NSRectFill (r);
3376     }
3378   /* Do strike-through.  We follow other terms for thickness and
3379      vertical position.*/
3380   if (face->strike_through_p)
3381     {
3382       NSRect r;
3383       /* Y-coordinate and height of the glyph string's first glyph.
3384          We cannot use s->y and s->height because those could be
3385          larger if there are taller display elements (e.g., characters
3386          displayed with a larger font) in the same glyph row.  */
3387       int glyph_y = s->ybase - s->first_glyph->ascent;
3388       int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
3389       /* Strike-through width and offset from the glyph string's
3390          top edge.  */
3391       unsigned long h = 1;
3392       unsigned long dy;
3394       dy = lrint ((glyph_height - h) / 2);
3395       r = NSMakeRect (x, glyph_y + dy, width, 1);
3397       if (face->strike_through_color_defaulted_p)
3398         [defaultCol set];
3399       else
3400         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3401       NSRectFill (r);
3402     }
3405 static void
3406 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3407              char left_p, char right_p)
3408 /* --------------------------------------------------------------------------
3409     Draw an unfilled rect inside r, optionally leaving left and/or right open.
3410     Note we can't just use an NSDrawRect command, because of the possibility
3411     of some sides not being drawn, and because the rect will be filled.
3412    -------------------------------------------------------------------------- */
3414   NSRect s = r;
3415   [col set];
3417   /* top, bottom */
3418   s.size.height = thickness;
3419   NSRectFill (s);
3420   s.origin.y += r.size.height - thickness;
3421   NSRectFill (s);
3423   s.size.height = r.size.height;
3424   s.origin.y = r.origin.y;
3426   /* left, right (optional) */
3427   s.size.width = thickness;
3428   if (left_p)
3429     NSRectFill (s);
3430   if (right_p)
3431     {
3432       s.origin.x += r.size.width - thickness;
3433       NSRectFill (s);
3434     }
3438 static void
3439 ns_draw_relief (NSRect r, int thickness, char raised_p,
3440                char top_p, char bottom_p, char left_p, char right_p,
3441                struct glyph_string *s)
3442 /* --------------------------------------------------------------------------
3443     Draw a relief rect inside r, optionally leaving some sides open.
3444     Note we can't just use an NSDrawBezel command, because of the possibility
3445     of some sides not being drawn, and because the rect will be filled.
3446    -------------------------------------------------------------------------- */
3448   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3449   NSColor *newBaseCol = nil;
3450   NSRect sr = r;
3452   NSTRACE ("ns_draw_relief");
3454   /* set up colors */
3456   if (s->face->use_box_color_for_shadows_p)
3457     {
3458       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3459     }
3460 /*     else if (s->first_glyph->type == IMAGE_GLYPH
3461            && s->img->pixmap
3462            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3463        {
3464          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
3465        } */
3466   else
3467     {
3468       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3469     }
3471   if (newBaseCol == nil)
3472     newBaseCol = [NSColor grayColor];
3474   if (newBaseCol != baseCol)  /* TODO: better check */
3475     {
3476       [baseCol release];
3477       baseCol = [newBaseCol retain];
3478       [lightCol release];
3479       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3480       [darkCol release];
3481       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3482     }
3484   [(raised_p ? lightCol : darkCol) set];
3486   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3488   /* top */
3489   sr.size.height = thickness;
3490   if (top_p) NSRectFill (sr);
3492   /* left */
3493   sr.size.height = r.size.height;
3494   sr.size.width = thickness;
3495   if (left_p) NSRectFill (sr);
3497   [(raised_p ? darkCol : lightCol) set];
3499   /* bottom */
3500   sr.size.width = r.size.width;
3501   sr.size.height = thickness;
3502   sr.origin.y += r.size.height - thickness;
3503   if (bottom_p) NSRectFill (sr);
3505   /* right */
3506   sr.size.height = r.size.height;
3507   sr.origin.y = r.origin.y;
3508   sr.size.width = thickness;
3509   sr.origin.x += r.size.width - thickness;
3510   if (right_p) NSRectFill (sr);
3514 static void
3515 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3516 /* --------------------------------------------------------------------------
3517       Function modeled after x_draw_glyph_string_box ().
3518       Sets up parameters for drawing.
3519    -------------------------------------------------------------------------- */
3521   int right_x, last_x;
3522   char left_p, right_p;
3523   struct glyph *last_glyph;
3524   NSRect r;
3525   int thickness;
3526   struct face *face;
3528   if (s->hl == DRAW_MOUSE_FACE)
3529     {
3530       face = FACE_FROM_ID_OR_NULL (s->f,
3531                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3532       if (!face)
3533         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3534     }
3535   else
3536     face = s->face;
3538   thickness = face->box_line_width;
3540   NSTRACE ("ns_dumpglyphs_box_or_relief");
3542   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3543             ? WINDOW_RIGHT_EDGE_X (s->w)
3544             : window_box_right (s->w, s->area));
3545   last_glyph = (s->cmp || s->img
3546                 ? s->first_glyph : s->first_glyph + s->nchars-1);
3548   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3549               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3551   left_p = (s->first_glyph->left_box_line_p
3552             || (s->hl == DRAW_MOUSE_FACE
3553                 && (s->prev == NULL || s->prev->hl != s->hl)));
3554   right_p = (last_glyph->right_box_line_p
3555              || (s->hl == DRAW_MOUSE_FACE
3556                  && (s->next == NULL || s->next->hl != s->hl)));
3558   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3560   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3561   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3562     {
3563       ns_draw_box (r, abs (thickness),
3564                    ns_lookup_indexed_color (face->box_color, s->f),
3565                   left_p, right_p);
3566     }
3567   else
3568     {
3569       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3570                      1, 1, left_p, right_p, s);
3571     }
3575 static void
3576 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3577 /* --------------------------------------------------------------------------
3578       Modeled after x_draw_glyph_string_background, which draws BG in
3579       certain cases.  Others are left to the text rendering routine.
3580    -------------------------------------------------------------------------- */
3582   NSTRACE ("ns_maybe_dumpglyphs_background");
3584   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3585     {
3586       int box_line_width = max (s->face->box_line_width, 0);
3587       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3588           /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3589              dimensions, since the actual glyphs might be much
3590              smaller.  So in that case we always clear the rectangle
3591              with background color.  */
3592           || FONT_TOO_HIGH (s->font)
3593           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3594         {
3595           struct face *face;
3596           if (s->hl == DRAW_MOUSE_FACE)
3597             {
3598               face
3599                 = FACE_FROM_ID_OR_NULL (s->f,
3600                                         MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3601               if (!face)
3602                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3603             }
3604           else
3605             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3606           if (!face->stipple)
3607             [(NS_FACE_BACKGROUND (face) != 0
3608               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3609               : FRAME_BACKGROUND_COLOR (s->f)) set];
3610           else
3611             {
3612               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3613               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3614             }
3616           if (s->hl != DRAW_CURSOR)
3617             {
3618               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3619                                     s->background_width,
3620                                     s->height-2*box_line_width);
3621               NSRectFill (r);
3622             }
3624           s->background_filled_p = 1;
3625         }
3626     }
3630 static void
3631 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3632 /* --------------------------------------------------------------------------
3633       Renders an image and associated borders.
3634    -------------------------------------------------------------------------- */
3636   EmacsImage *img = s->img->pixmap;
3637   int box_line_vwidth = max (s->face->box_line_width, 0);
3638   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3639   int bg_x, bg_y, bg_height;
3640   int th;
3641   char raised_p;
3642   NSRect br;
3643   struct face *face;
3644   NSColor *tdCol;
3646   NSTRACE ("ns_dumpglyphs_image");
3648   if (s->face->box != FACE_NO_BOX
3649       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3650     x += abs (s->face->box_line_width);
3652   bg_x = x;
3653   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3654   bg_height = s->height;
3655   /* other terms have this, but was causing problems w/tabbar mode */
3656   /* - 2 * box_line_vwidth; */
3658   if (s->slice.x == 0) x += s->img->hmargin;
3659   if (s->slice.y == 0) y += s->img->vmargin;
3661   /* Draw BG: if we need larger area than image itself cleared, do that,
3662      otherwise, since we composite the image under NS (instead of mucking
3663      with its background color), we must clear just the image area. */
3664   if (s->hl == DRAW_MOUSE_FACE)
3665     {
3666       face = FACE_FROM_ID_OR_NULL (s->f,
3667                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3668       if (!face)
3669        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3670     }
3671   else
3672     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3674   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3676   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3677       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3678     {
3679       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3680       s->background_filled_p = 1;
3681     }
3682   else
3683     {
3684       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3685     }
3687   NSRectFill (br);
3689   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3690   if (img != nil)
3691     {
3692 #ifdef NS_IMPL_COCOA
3693       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3694       NSRect ir = NSMakeRect (s->slice.x,
3695                               s->img->height - s->slice.y - s->slice.height,
3696                               s->slice.width, s->slice.height);
3697       [img drawInRect: dr
3698              fromRect: ir
3699              operation: NSCompositingOperationSourceOver
3700               fraction: 1.0
3701            respectFlipped: YES
3702                 hints: nil];
3703 #else
3704       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3705                   operation: NSCompositingOperationSourceOver];
3706 #endif
3707     }
3709   if (s->hl == DRAW_CURSOR)
3710     {
3711     [FRAME_CURSOR_COLOR (s->f) set];
3712     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3713       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3714     else
3715       /* Currently on NS img->mask is always 0. Since
3716          get_window_cursor_type specifies a hollow box cursor when on
3717          a non-masked image we never reach this clause. But we put it
3718          in in anticipation of better support for image masks on
3719          NS. */
3720       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3721     }
3722   else
3723     {
3724       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3725     }
3727   /* Draw underline, overline, strike-through. */
3728   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3730   /* Draw relief, if requested */
3731   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3732     {
3733       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3734         {
3735           th = tool_bar_button_relief >= 0 ?
3736             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3737           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3738         }
3739       else
3740         {
3741           th = abs (s->img->relief);
3742           raised_p = (s->img->relief > 0);
3743         }
3745       r.origin.x = x - th;
3746       r.origin.y = y - th;
3747       r.size.width = s->slice.width + 2*th-1;
3748       r.size.height = s->slice.height + 2*th-1;
3749       ns_draw_relief (r, th, raised_p,
3750                       s->slice.y == 0,
3751                       s->slice.y + s->slice.height == s->img->height,
3752                       s->slice.x == 0,
3753                       s->slice.x + s->slice.width == s->img->width, s);
3754     }
3756   /* If there is no mask, the background won't be seen,
3757      so draw a rectangle on the image for the cursor.
3758      Do this for all images, getting transparency right is not reliable.  */
3759   if (s->hl == DRAW_CURSOR)
3760     {
3761       int thickness = abs (s->img->relief);
3762       if (thickness == 0) thickness = 1;
3763       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3764     }
3768 static void
3769 ns_dumpglyphs_stretch (struct glyph_string *s)
3771   NSRect r[2];
3772   int n, i;
3773   struct face *face;
3774   NSColor *fgCol, *bgCol;
3776   if (!s->background_filled_p)
3777     {
3778       n = ns_get_glyph_string_clip_rect (s, r);
3779       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3781       ns_focus (s->f, r, n);
3783       if (s->hl == DRAW_MOUSE_FACE)
3784        {
3785          face = FACE_FROM_ID_OR_NULL (s->f,
3786                                       MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3787          if (!face)
3788            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3789        }
3790       else
3791        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3793       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3794       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3796       for (i = 0; i < n; ++i)
3797         {
3798           if (!s->row->full_width_p)
3799             {
3800               int overrun, leftoverrun;
3802               /* truncate to avoid overwriting fringe and/or scrollbar */
3803               overrun = max (0, (s->x + s->background_width)
3804                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3805                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3806               r[i].size.width -= overrun;
3808               /* truncate to avoid overwriting to left of the window box */
3809               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3810                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3812               if (leftoverrun > 0)
3813                 {
3814                   r[i].origin.x += leftoverrun;
3815                   r[i].size.width -= leftoverrun;
3816                 }
3818               /* XXX: Try to work between problem where a stretch glyph on
3819                  a partially-visible bottom row will clear part of the
3820                  modeline, and another where list-buffers headers and similar
3821                  rows erroneously have visible_height set to 0.  Not sure
3822                  where this is coming from as other terms seem not to show. */
3823               r[i].size.height = min (s->height, s->row->visible_height);
3824             }
3826           [bgCol set];
3828           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3829              overwriting cursor (usually when cursor on a tab) */
3830           if (s->hl == DRAW_CURSOR)
3831             {
3832               CGFloat x, width;
3834               x = r[i].origin.x;
3835               width = s->w->phys_cursor_width;
3836               r[i].size.width -= width;
3837               r[i].origin.x += width;
3839               NSRectFill (r[i]);
3841               /* Draw overlining, etc. on the cursor. */
3842               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3843                 ns_draw_text_decoration (s, face, bgCol, width, x);
3844               else
3845                 ns_draw_text_decoration (s, face, fgCol, width, x);
3846             }
3847           else
3848             {
3849               NSRectFill (r[i]);
3850             }
3852           /* Draw overlining, etc. on the stretch glyph (or the part
3853              of the stretch glyph after the cursor). */
3854           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3855                                    r[i].origin.x);
3856         }
3857       ns_unfocus (s->f);
3858       s->background_filled_p = 1;
3859     }
3863 static void
3864 ns_draw_glyph_string_foreground (struct glyph_string *s)
3866   int x, flags;
3867   struct font *font = s->font;
3869   /* If first glyph of S has a left box line, start drawing the text
3870      of S to the right of that box line.  */
3871   if (s->face && s->face->box != FACE_NO_BOX
3872       && s->first_glyph->left_box_line_p)
3873     x = s->x + eabs (s->face->box_line_width);
3874   else
3875     x = s->x;
3877   flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3878     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3879      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3880       NS_DUMPGLYPH_NORMAL));
3882   font->driver->draw
3883     (s, s->cmp_from, s->nchars, x, s->ybase,
3884      (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3885      || flags == NS_DUMPGLYPH_MOUSEFACE);
3889 static void
3890 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3892   int i, j, x;
3893   struct font *font = s->font;
3895   /* If first glyph of S has a left box line, start drawing the text
3896      of S to the right of that box line.  */
3897   if (s->face && s->face->box != FACE_NO_BOX
3898       && s->first_glyph->left_box_line_p)
3899     x = s->x + eabs (s->face->box_line_width);
3900   else
3901     x = s->x;
3903   /* S is a glyph string for a composition.  S->cmp_from is the index
3904      of the first character drawn for glyphs of this composition.
3905      S->cmp_from == 0 means we are drawing the very first character of
3906      this composition.  */
3908   /* Draw a rectangle for the composition if the font for the very
3909      first character of the composition could not be loaded.  */
3910   if (s->font_not_found_p)
3911     {
3912       if (s->cmp_from == 0)
3913         {
3914           NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3915           ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3916         }
3917     }
3918   else if (! s->first_glyph->u.cmp.automatic)
3919     {
3920       int y = s->ybase;
3922       for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3923         /* TAB in a composition means display glyphs with padding
3924            space on the left or right.  */
3925         if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3926           {
3927             int xx = x + s->cmp->offsets[j * 2];
3928             int yy = y - s->cmp->offsets[j * 2 + 1];
3930             font->driver->draw (s, j, j + 1, xx, yy, false);
3931             if (s->face->overstrike)
3932               font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3933           }
3934     }
3935   else
3936     {
3937       Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3938       Lisp_Object glyph;
3939       int y = s->ybase;
3940       int width = 0;
3942       for (i = j = s->cmp_from; i < s->cmp_to; i++)
3943         {
3944           glyph = LGSTRING_GLYPH (gstring, i);
3945           if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3946             width += LGLYPH_WIDTH (glyph);
3947           else
3948             {
3949               int xoff, yoff, wadjust;
3951               if (j < i)
3952                 {
3953                   font->driver->draw (s, j, i, x, y, false);
3954                   if (s->face->overstrike)
3955                     font->driver->draw (s, j, i, x + 1, y, false);
3956                   x += width;
3957                 }
3958               xoff = LGLYPH_XOFF (glyph);
3959               yoff = LGLYPH_YOFF (glyph);
3960               wadjust = LGLYPH_WADJUST (glyph);
3961               font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3962               if (s->face->overstrike)
3963                 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3964                                     false);
3965               x += wadjust;
3966               j = i + 1;
3967               width = 0;
3968             }
3969         }
3970       if (j < i)
3971         {
3972           font->driver->draw (s, j, i, x, y, false);
3973           if (s->face->overstrike)
3974             font->driver->draw (s, j, i, x + 1, y, false);
3975         }
3976     }
3979 static void
3980 ns_draw_glyph_string (struct glyph_string *s)
3981 /* --------------------------------------------------------------------------
3982       External (RIF): Main draw-text call.
3983    -------------------------------------------------------------------------- */
3985   /* TODO (optimize): focus for box and contents draw */
3986   NSRect r[2];
3987   int n;
3988   char box_drawn_p = 0;
3989   struct font *font = s->face->font;
3990   if (! font) font = FRAME_FONT (s->f);
3992   NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3994   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3995     {
3996       int width;
3997       struct glyph_string *next;
3999       for (width = 0, next = s->next;
4000            next && width < s->right_overhang;
4001            width += next->width, next = next->next)
4002         if (next->first_glyph->type != IMAGE_GLYPH)
4003           {
4004             if (next->first_glyph->type != STRETCH_GLYPH)
4005               {
4006                 n = ns_get_glyph_string_clip_rect (s->next, r);
4007                 ns_focus (s->f, r, n);
4008                 ns_maybe_dumpglyphs_background (s->next, 1);
4009                 ns_unfocus (s->f);
4010               }
4011             else
4012               {
4013                 ns_dumpglyphs_stretch (s->next);
4014               }
4015             next->num_clips = 0;
4016           }
4017     }
4019   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
4020         && (s->first_glyph->type == CHAR_GLYPH
4021             || s->first_glyph->type == COMPOSITE_GLYPH))
4022     {
4023       n = ns_get_glyph_string_clip_rect (s, r);
4024       ns_focus (s->f, r, n);
4025       ns_maybe_dumpglyphs_background (s, 1);
4026       ns_dumpglyphs_box_or_relief (s);
4027       ns_unfocus (s->f);
4028       box_drawn_p = 1;
4029     }
4031   switch (s->first_glyph->type)
4032     {
4034     case IMAGE_GLYPH:
4035       n = ns_get_glyph_string_clip_rect (s, r);
4036       ns_focus (s->f, r, n);
4037       ns_dumpglyphs_image (s, r[0]);
4038       ns_unfocus (s->f);
4039       break;
4041     case STRETCH_GLYPH:
4042       ns_dumpglyphs_stretch (s);
4043       break;
4045     case CHAR_GLYPH:
4046     case COMPOSITE_GLYPH:
4047       n = ns_get_glyph_string_clip_rect (s, r);
4048       ns_focus (s->f, r, n);
4050       if (s->for_overlaps || (s->cmp_from > 0
4051                               && ! s->first_glyph->u.cmp.automatic))
4052         s->background_filled_p = 1;
4053       else
4054         ns_maybe_dumpglyphs_background
4055           (s, s->first_glyph->type == COMPOSITE_GLYPH);
4057       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4058         {
4059           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4060           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4061           NS_FACE_FOREGROUND (s->face) = tmp;
4062         }
4064       {
4065         BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
4067         if (isComposite)
4068           ns_draw_composite_glyph_string_foreground (s);
4069         else
4070           ns_draw_glyph_string_foreground (s);
4071       }
4073       {
4074         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
4075                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
4076                                                    s->f)
4077                         : FRAME_FOREGROUND_COLOR (s->f));
4078         [col set];
4080         /* Draw underline, overline, strike-through. */
4081         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
4082       }
4084       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4085         {
4086           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4087           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4088           NS_FACE_FOREGROUND (s->face) = tmp;
4089         }
4091       ns_unfocus (s->f);
4092       break;
4094     case GLYPHLESS_GLYPH:
4095       n = ns_get_glyph_string_clip_rect (s, r);
4096       ns_focus (s->f, r, n);
4098       if (s->for_overlaps || (s->cmp_from > 0
4099                               && ! s->first_glyph->u.cmp.automatic))
4100         s->background_filled_p = 1;
4101       else
4102         ns_maybe_dumpglyphs_background
4103           (s, s->first_glyph->type == COMPOSITE_GLYPH);
4104       /* ... */
4105       /* Not yet implemented.  */
4106       /* ... */
4107       ns_unfocus (s->f);
4108       break;
4110     default:
4111       emacs_abort ();
4112     }
4114   /* Draw box if not done already. */
4115   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
4116     {
4117       n = ns_get_glyph_string_clip_rect (s, r);
4118       ns_focus (s->f, r, n);
4119       ns_dumpglyphs_box_or_relief (s);
4120       ns_unfocus (s->f);
4121     }
4123   s->num_clips = 0;
4128 /* ==========================================================================
4130     Event loop
4132    ========================================================================== */
4135 static void
4136 ns_send_appdefined (int value)
4137 /* --------------------------------------------------------------------------
4138     Internal: post an appdefined event which EmacsApp-sendEvent will
4139               recognize and take as a command to halt the event loop.
4140    -------------------------------------------------------------------------- */
4142   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
4144   // GNUstep needs postEvent to happen on the main thread.
4145   // Cocoa needs nextEventMatchingMask to happen on the main thread too.
4146   if (! [[NSThread currentThread] isMainThread])
4147     {
4148       EmacsApp *app = (EmacsApp *)NSApp;
4149       app->nextappdefined = value;
4150       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
4151                             withObject:nil
4152                          waitUntilDone:NO];
4153       return;
4154     }
4156   /* Only post this event if we haven't already posted one.  This will end
4157        the [NXApp run] main loop after having processed all events queued at
4158        this moment.  */
4160 #ifdef NS_IMPL_COCOA
4161   if (! send_appdefined)
4162     {
4163       /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves
4164          in certain situations (rapid incoming events).
4165          So check if we have one, if not add one.  */
4166       NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
4167                                           untilDate:[NSDate distantPast]
4168                                              inMode:NSDefaultRunLoopMode
4169                                             dequeue:NO];
4170       if (! appev) send_appdefined = YES;
4171     }
4172 #endif
4174   if (send_appdefined)
4175     {
4176       NSEvent *nxev;
4178       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
4179       send_appdefined = NO;
4181       /* Don't need wakeup timer any more */
4182       if (timed_entry)
4183         {
4184           [timed_entry invalidate];
4185           [timed_entry release];
4186           timed_entry = nil;
4187         }
4189       nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
4190                                 location: NSMakePoint (0, 0)
4191                            modifierFlags: 0
4192                                timestamp: 0
4193                             windowNumber: [[NSApp mainWindow] windowNumber]
4194                                  context: [NSApp context]
4195                                  subtype: 0
4196                                    data1: value
4197                                    data2: 0];
4199       /* Post an application defined event on the event queue.  When this is
4200          received the [NXApp run] will return, thus having processed all
4201          events which are currently queued.  */
4202       [NSApp postEvent: nxev atStart: NO];
4203     }
4206 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4207 static void
4208 check_native_fs ()
4210   Lisp_Object frame, tail;
4212   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
4213     return;
4215   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
4217   FOR_EACH_FRAME (tail, frame)
4218     {
4219       struct frame *f = XFRAME (frame);
4220       if (FRAME_NS_P (f))
4221         {
4222           EmacsView *view = FRAME_NS_VIEW (f);
4223           [view updateCollectionBehavior];
4224         }
4225     }
4227 #endif
4229 /* GNUstep does not have cancelTracking.  */
4230 #ifdef NS_IMPL_COCOA
4231 /* Check if menu open should be canceled or continued as normal.  */
4232 void
4233 ns_check_menu_open (NSMenu *menu)
4235   /* Click in menu bar? */
4236   NSArray *a = [[NSApp mainMenu] itemArray];
4237   int i;
4238   BOOL found = NO;
4240   if (menu == nil) // Menu tracking ended.
4241     {
4242       if (menu_will_open_state == MENU_OPENING)
4243         menu_will_open_state = MENU_NONE;
4244       return;
4245     }
4247   for (i = 0; ! found && i < [a count]; i++)
4248     found = menu == [[a objectAtIndex:i] submenu];
4249   if (found)
4250     {
4251       if (menu_will_open_state == MENU_NONE && emacs_event)
4252         {
4253           NSEvent *theEvent = [NSApp currentEvent];
4254           struct frame *emacsframe = SELECTED_FRAME ();
4256           [menu cancelTracking];
4257           menu_will_open_state = MENU_PENDING;
4258           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4259           EV_TRAILER (theEvent);
4261           CGEventRef ourEvent = CGEventCreate (NULL);
4262           menu_mouse_point = CGEventGetLocation (ourEvent);
4263           CFRelease (ourEvent);
4264         }
4265       else if (menu_will_open_state == MENU_OPENING)
4266         {
4267           menu_will_open_state = MENU_NONE;
4268         }
4269     }
4272 /* Redo saved menu click if state is MENU_PENDING.  */
4273 void
4274 ns_check_pending_open_menu ()
4276   if (menu_will_open_state == MENU_PENDING)
4277     {
4278       CGEventSourceRef source
4279         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4281       CGEventRef event = CGEventCreateMouseEvent (source,
4282                                                   kCGEventLeftMouseDown,
4283                                                   menu_mouse_point,
4284                                                   kCGMouseButtonLeft);
4285       CGEventSetType (event, kCGEventLeftMouseDown);
4286       CGEventPost (kCGHIDEventTap, event);
4287       CFRelease (event);
4288       CFRelease (source);
4290       menu_will_open_state = MENU_OPENING;
4291     }
4293 #endif /* NS_IMPL_COCOA */
4295 static int
4296 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4297 /* --------------------------------------------------------------------------
4298      External (hook): Post an event to ourself and keep reading events until
4299      we read it back again.  In effect process all events which were waiting.
4300      From 21+ we have to manage the event buffer ourselves.
4301    -------------------------------------------------------------------------- */
4303   struct input_event ev;
4304   int nevents;
4306   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4308 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4309   check_native_fs ();
4310 #endif
4312   if ([NSApp modalWindow] != nil)
4313     return -1;
4315   if (hold_event_q.nr > 0)
4316     {
4317       int i;
4318       for (i = 0; i < hold_event_q.nr; ++i)
4319         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4320       hold_event_q.nr = 0;
4321       return i;
4322     }
4324   if ([NSThread isMainThread])
4325     {
4326       block_input ();
4327       n_emacs_events_pending = 0;
4328       ns_init_events (&ev);
4329       q_event_ptr = hold_quit;
4331       /* we manage autorelease pools by allocate/reallocate each time around
4332          the loop; strict nesting is occasionally violated but seems not to
4333          matter.. earlier methods using full nesting caused major memory leaks */
4334       [outerpool release];
4335       outerpool = [[NSAutoreleasePool alloc] init];
4337       /* If have pending open-file requests, attend to the next one of those. */
4338       if (ns_pending_files && [ns_pending_files count] != 0
4339           && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4340         {
4341           [ns_pending_files removeObjectAtIndex: 0];
4342         }
4343       /* Deal with pending service requests. */
4344       else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4345                && [(EmacsApp *)
4346                     NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4347                                  withArg: [ns_pending_service_args objectAtIndex: 0]])
4348         {
4349           [ns_pending_service_names removeObjectAtIndex: 0];
4350           [ns_pending_service_args removeObjectAtIndex: 0];
4351         }
4352       else
4353         {
4354           /* Run and wait for events.  We must always send one NX_APPDEFINED event
4355              to ourself, otherwise [NXApp run] will never exit.  */
4356           send_appdefined = YES;
4357           ns_send_appdefined (-1);
4359           [NSApp run];
4360         }
4362       nevents = n_emacs_events_pending;
4363       n_emacs_events_pending = 0;
4364       ns_finish_events ();
4365       q_event_ptr = NULL;
4366       unblock_input ();
4367     }
4368   else
4369     return -1;
4371   return nevents;
4376 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4377            fd_set *exceptfds, struct timespec *timeout,
4378            sigset_t *sigmask)
4379 /* --------------------------------------------------------------------------
4380      Replacement for select, checking for events
4381    -------------------------------------------------------------------------- */
4383   int result;
4384   int t, k, nr = 0;
4385   struct input_event event;
4386   char c;
4388   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4390 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4391   check_native_fs ();
4392 #endif
4394   if (hold_event_q.nr > 0)
4395     {
4396       /* We already have events pending. */
4397       raise (SIGIO);
4398       errno = EINTR;
4399       return -1;
4400     }
4402   for (k = 0; k < nfds+1; k++)
4403     {
4404       if (readfds && FD_ISSET(k, readfds)) ++nr;
4405       if (writefds && FD_ISSET(k, writefds)) ++nr;
4406     }
4408   if (NSApp == nil
4409       || ![NSThread isMainThread]
4410       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4411     return thread_select(pselect, nfds, readfds, writefds,
4412                          exceptfds, timeout, sigmask);
4413   else
4414     {
4415       struct timespec t = {0, 0};
4416       thread_select(pselect, 0, NULL, NULL, NULL, &t, sigmask);
4417     }
4419   [outerpool release];
4420   outerpool = [[NSAutoreleasePool alloc] init];
4423   send_appdefined = YES;
4424   if (nr > 0)
4425     {
4426       pthread_mutex_lock (&select_mutex);
4427       select_nfds = nfds;
4428       select_valid = 0;
4429       if (readfds)
4430         {
4431           select_readfds = *readfds;
4432           select_valid += SELECT_HAVE_READ;
4433         }
4434       if (writefds)
4435         {
4436           select_writefds = *writefds;
4437           select_valid += SELECT_HAVE_WRITE;
4438         }
4440       if (timeout)
4441         {
4442           select_timeout = *timeout;
4443           select_valid += SELECT_HAVE_TMO;
4444         }
4446       pthread_mutex_unlock (&select_mutex);
4448       /* Inform fd_handler that select should be called */
4449       c = 'g';
4450       emacs_write_sig (selfds[1], &c, 1);
4451     }
4452   else if (nr == 0 && timeout)
4453     {
4454       /* No file descriptor, just a timeout, no need to wake fd_handler  */
4455       double time = timespectod (*timeout);
4456       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4457                                                       target: NSApp
4458                                                     selector:
4459                                   @selector (timeout_handler:)
4460                                                     userInfo: 0
4461                                                      repeats: NO]
4462                       retain];
4463     }
4464   else /* No timeout and no file descriptors, can this happen?  */
4465     {
4466       /* Send appdefined so we exit from the loop */
4467       ns_send_appdefined (-1);
4468     }
4470   block_input ();
4471   ns_init_events (&event);
4473   [NSApp run];
4475   ns_finish_events ();
4476   if (nr > 0 && readfds)
4477     {
4478       c = 's';
4479       emacs_write_sig (selfds[1], &c, 1);
4480     }
4481   unblock_input ();
4483   t = last_appdefined_event_data;
4485   if (t != NO_APPDEFINED_DATA)
4486     {
4487       last_appdefined_event_data = NO_APPDEFINED_DATA;
4489       if (t == -2)
4490         {
4491           /* The NX_APPDEFINED event we received was a timeout. */
4492           result = 0;
4493         }
4494       else if (t == -1)
4495         {
4496           /* The NX_APPDEFINED event we received was the result of
4497              at least one real input event arriving.  */
4498           errno = EINTR;
4499           result = -1;
4500         }
4501       else
4502         {
4503           /* Received back from select () in fd_handler; copy the results */
4504           pthread_mutex_lock (&select_mutex);
4505           if (readfds) *readfds = select_readfds;
4506           if (writefds) *writefds = select_writefds;
4507           pthread_mutex_unlock (&select_mutex);
4508           result = t;
4509         }
4510     }
4511   else
4512     {
4513       errno = EINTR;
4514       result = -1;
4515     }
4517   return result;
4520 #ifdef HAVE_PTHREAD
4521 void
4522 ns_run_loop_break ()
4523 /* Break out of the NS run loop in ns_select or ns_read_socket. */
4525   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_run_loop_break");
4527   /* If we don't have a GUI, don't send the event. */
4528   if (NSApp != NULL)
4529     ns_send_appdefined(-1);
4531 #endif
4534 /* ==========================================================================
4536     Scrollbar handling
4538    ========================================================================== */
4541 static void
4542 ns_set_vertical_scroll_bar (struct window *window,
4543                            int portion, int whole, int position)
4544 /* --------------------------------------------------------------------------
4545       External (hook): Update or add scrollbar
4546    -------------------------------------------------------------------------- */
4548   Lisp_Object win;
4549   NSRect r, v;
4550   struct frame *f = XFRAME (WINDOW_FRAME (window));
4551   EmacsView *view = FRAME_NS_VIEW (f);
4552   EmacsScroller *bar;
4553   int window_y, window_height;
4554   int top, left, height, width;
4555   BOOL update_p = YES;
4557   /* optimization; display engine sends WAY too many of these.. */
4558   if (!NILP (window->vertical_scroll_bar))
4559     {
4560       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4561       if ([bar checkSamePosition: position portion: portion whole: whole])
4562         {
4563           if (view->scrollbarsNeedingUpdate == 0)
4564             {
4565               if (!windows_or_buffers_changed)
4566                   return;
4567             }
4568           else
4569             view->scrollbarsNeedingUpdate--;
4570           update_p = NO;
4571         }
4572     }
4574   NSTRACE ("ns_set_vertical_scroll_bar");
4576   /* Get dimensions.  */
4577   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4578   top = window_y;
4579   height = window_height;
4580   width = NS_SCROLL_BAR_WIDTH (f);
4581   left = WINDOW_SCROLL_BAR_AREA_X (window);
4583   r = NSMakeRect (left, top, width, height);
4584   /* the parent view is flipped, so we need to flip y value */
4585   v = [view frame];
4586   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4588   XSETWINDOW (win, window);
4589   block_input ();
4591   /* we want at least 5 lines to display a scrollbar */
4592   if (WINDOW_TOTAL_LINES (window) < 5)
4593     {
4594       if (!NILP (window->vertical_scroll_bar))
4595         {
4596           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4597           [bar removeFromSuperview];
4598           wset_vertical_scroll_bar (window, Qnil);
4599           [bar release];
4600         }
4601       ns_clear_frame_area (f, left, top, width, height);
4602       unblock_input ();
4603       return;
4604     }
4606   if (NILP (window->vertical_scroll_bar))
4607     {
4608       if (width > 0 && height > 0)
4609         ns_clear_frame_area (f, left, top, width, height);
4611       bar = [[EmacsScroller alloc] initFrame: r window: win];
4612       wset_vertical_scroll_bar (window, make_save_ptr (bar));
4613       update_p = YES;
4614     }
4615   else
4616     {
4617       NSRect oldRect;
4618       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4619       oldRect = [bar frame];
4620       r.size.width = oldRect.size.width;
4621       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4622         {
4623           if (oldRect.origin.x != r.origin.x)
4624               ns_clear_frame_area (f, left, top, width, height);
4625           [bar setFrame: r];
4626         }
4627     }
4629   if (update_p)
4630     [bar setPosition: position portion: portion whole: whole];
4631   unblock_input ();
4635 static void
4636 ns_set_horizontal_scroll_bar (struct window *window,
4637                               int portion, int whole, int position)
4638 /* --------------------------------------------------------------------------
4639       External (hook): Update or add scrollbar
4640    -------------------------------------------------------------------------- */
4642   Lisp_Object win;
4643   NSRect r, v;
4644   struct frame *f = XFRAME (WINDOW_FRAME (window));
4645   EmacsView *view = FRAME_NS_VIEW (f);
4646   EmacsScroller *bar;
4647   int top, height, left, width;
4648   int window_x, window_width;
4649   BOOL update_p = YES;
4651   /* optimization; display engine sends WAY too many of these.. */
4652   if (!NILP (window->horizontal_scroll_bar))
4653     {
4654       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4655       if ([bar checkSamePosition: position portion: portion whole: whole])
4656         {
4657           if (view->scrollbarsNeedingUpdate == 0)
4658             {
4659               if (!windows_or_buffers_changed)
4660                   return;
4661             }
4662           else
4663             view->scrollbarsNeedingUpdate--;
4664           update_p = NO;
4665         }
4666     }
4668   NSTRACE ("ns_set_horizontal_scroll_bar");
4670   /* Get dimensions.  */
4671   window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4672   left = window_x;
4673   width = window_width;
4674   height = NS_SCROLL_BAR_HEIGHT (f);
4675   top = WINDOW_SCROLL_BAR_AREA_Y (window);
4677   r = NSMakeRect (left, top, width, height);
4678   /* the parent view is flipped, so we need to flip y value */
4679   v = [view frame];
4680   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4682   XSETWINDOW (win, window);
4683   block_input ();
4685   if (NILP (window->horizontal_scroll_bar))
4686     {
4687       if (width > 0 && height > 0)
4688         ns_clear_frame_area (f, left, top, width, height);
4690       bar = [[EmacsScroller alloc] initFrame: r window: win];
4691       wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4692       update_p = YES;
4693     }
4694   else
4695     {
4696       NSRect oldRect;
4697       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4698       oldRect = [bar frame];
4699       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4700         {
4701           if (oldRect.origin.y != r.origin.y)
4702             ns_clear_frame_area (f, left, top, width, height);
4703           [bar setFrame: r];
4704           update_p = YES;
4705         }
4706     }
4708   /* If there are both horizontal and vertical scroll-bars they leave
4709      a square that belongs to neither. We need to clear it otherwise
4710      it fills with junk. */
4711   if (!NILP (window->vertical_scroll_bar))
4712     ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4713                          NS_SCROLL_BAR_HEIGHT (f), height);
4715   if (update_p)
4716     [bar setPosition: position portion: portion whole: whole];
4717   unblock_input ();
4721 static void
4722 ns_condemn_scroll_bars (struct frame *f)
4723 /* --------------------------------------------------------------------------
4724      External (hook): arrange for all frame's scrollbars to be removed
4725      at next call to judge_scroll_bars, except for those redeemed.
4726    -------------------------------------------------------------------------- */
4728   int i;
4729   id view;
4730   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4732   NSTRACE ("ns_condemn_scroll_bars");
4734   for (i =[subviews count]-1; i >= 0; i--)
4735     {
4736       view = [subviews objectAtIndex: i];
4737       if ([view isKindOfClass: [EmacsScroller class]])
4738         [view condemn];
4739     }
4743 static void
4744 ns_redeem_scroll_bar (struct window *window)
4745 /* --------------------------------------------------------------------------
4746      External (hook): arrange to spare this window's scrollbar
4747      at next call to judge_scroll_bars.
4748    -------------------------------------------------------------------------- */
4750   id bar;
4751   NSTRACE ("ns_redeem_scroll_bar");
4752   if (!NILP (window->vertical_scroll_bar)
4753       && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4754     {
4755       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4756       [bar reprieve];
4757     }
4759   if (!NILP (window->horizontal_scroll_bar)
4760       && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4761     {
4762       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4763       [bar reprieve];
4764     }
4768 static void
4769 ns_judge_scroll_bars (struct frame *f)
4770 /* --------------------------------------------------------------------------
4771      External (hook): destroy all scrollbars on frame that weren't
4772      redeemed after call to condemn_scroll_bars.
4773    -------------------------------------------------------------------------- */
4775   int i;
4776   id view;
4777   EmacsView *eview = FRAME_NS_VIEW (f);
4778   NSArray *subviews = [[eview superview] subviews];
4779   BOOL removed = NO;
4781   NSTRACE ("ns_judge_scroll_bars");
4782   for (i = [subviews count]-1; i >= 0; --i)
4783     {
4784       view = [subviews objectAtIndex: i];
4785       if (![view isKindOfClass: [EmacsScroller class]]) continue;
4786       if ([view judge])
4787         removed = YES;
4788     }
4790   if (removed)
4791     [eview updateFrameSize: NO];
4794 /* ==========================================================================
4796     Initialization
4798    ========================================================================== */
4801 x_display_pixel_height (struct ns_display_info *dpyinfo)
4803   NSArray *screens = [NSScreen screens];
4804   NSEnumerator *enumerator = [screens objectEnumerator];
4805   NSScreen *screen;
4806   NSRect frame;
4808   frame = NSZeroRect;
4809   while ((screen = [enumerator nextObject]) != nil)
4810     frame = NSUnionRect (frame, [screen frame]);
4812   return NSHeight (frame);
4816 x_display_pixel_width (struct ns_display_info *dpyinfo)
4818   NSArray *screens = [NSScreen screens];
4819   NSEnumerator *enumerator = [screens objectEnumerator];
4820   NSScreen *screen;
4821   NSRect frame;
4823   frame = NSZeroRect;
4824   while ((screen = [enumerator nextObject]) != nil)
4825     frame = NSUnionRect (frame, [screen frame]);
4827   return NSWidth (frame);
4831 static Lisp_Object ns_string_to_lispmod (const char *s)
4832 /* --------------------------------------------------------------------------
4833      Convert modifier name to lisp symbol
4834    -------------------------------------------------------------------------- */
4836   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4837     return Qmeta;
4838   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4839     return Qsuper;
4840   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4841     return Qcontrol;
4842   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4843     return Qalt;
4844   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4845     return Qhyper;
4846   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4847     return Qnone;
4848   else
4849     return Qnil;
4853 static void
4854 ns_default (const char *parameter, Lisp_Object *result,
4855            Lisp_Object yesval, Lisp_Object noval,
4856            BOOL is_float, BOOL is_modstring)
4857 /* --------------------------------------------------------------------------
4858       Check a parameter value in user's preferences
4859    -------------------------------------------------------------------------- */
4861   const char *value = ns_get_defaults_value (parameter);
4863   if (value)
4864     {
4865       double f;
4866       char *pos;
4867       if (c_strcasecmp (value, "YES") == 0)
4868         *result = yesval;
4869       else if (c_strcasecmp (value, "NO") == 0)
4870         *result = noval;
4871       else if (is_float && (f = strtod (value, &pos), pos != value))
4872         *result = make_float (f);
4873       else if (is_modstring && value)
4874         *result = ns_string_to_lispmod (value);
4875       else fprintf (stderr,
4876                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4877     }
4881 static void
4882 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4883 /* --------------------------------------------------------------------------
4884       Initialize global info and storage for display.
4885    -------------------------------------------------------------------------- */
4887     NSScreen *screen = [NSScreen mainScreen];
4888     NSWindowDepth depth = [screen depth];
4890     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4891     dpyinfo->resy = 72.27;
4892     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4893                                                   NSColorSpaceFromDepth (depth)]
4894                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4895                                                  NSColorSpaceFromDepth (depth)];
4896     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4897     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4898     dpyinfo->color_table->colors = NULL;
4899     dpyinfo->root_window = 42; /* a placeholder.. */
4900     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4901     dpyinfo->n_fonts = 0;
4902     dpyinfo->smallest_font_height = 1;
4903     dpyinfo->smallest_char_width = 1;
4905     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4909 /* This and next define (many of the) public functions in this file. */
4910 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4911          with using despite presence in the "system dependent" redisplay
4912          interface.  In addition, many of the ns_ methods have code that is
4913          shared with all terms, indicating need for further refactoring. */
4914 extern frame_parm_handler ns_frame_parm_handlers[];
4915 static struct redisplay_interface ns_redisplay_interface =
4917   ns_frame_parm_handlers,
4918   x_produce_glyphs,
4919   x_write_glyphs,
4920   x_insert_glyphs,
4921   x_clear_end_of_line,
4922   ns_scroll_run,
4923   ns_after_update_window_line,
4924   ns_update_window_begin,
4925   ns_update_window_end,
4926   0, /* flush_display */
4927   x_clear_window_mouse_face,
4928   x_get_glyph_overhangs,
4929   x_fix_overlapping_area,
4930   ns_draw_fringe_bitmap,
4931   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4932   0, /* destroy_fringe_bitmap */
4933   ns_compute_glyph_string_overhangs,
4934   ns_draw_glyph_string,
4935   ns_define_frame_cursor,
4936   ns_clear_frame_area,
4937   ns_draw_window_cursor,
4938   ns_draw_vertical_window_border,
4939   ns_draw_window_divider,
4940   ns_shift_glyphs_for_insert,
4941   ns_show_hourglass,
4942   ns_hide_hourglass
4946 static void
4947 ns_delete_display (struct ns_display_info *dpyinfo)
4949   /* TODO... */
4953 /* This function is called when the last frame on a display is deleted. */
4954 static void
4955 ns_delete_terminal (struct terminal *terminal)
4957   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4959   NSTRACE ("ns_delete_terminal");
4961   /* Protect against recursive calls.  delete_frame in
4962      delete_terminal calls us back when it deletes our last frame.  */
4963   if (!terminal->name)
4964     return;
4966   block_input ();
4968   x_destroy_all_bitmaps (dpyinfo);
4969   ns_delete_display (dpyinfo);
4970   unblock_input ();
4974 static struct terminal *
4975 ns_create_terminal (struct ns_display_info *dpyinfo)
4976 /* --------------------------------------------------------------------------
4977       Set up use of NS before we make the first connection.
4978    -------------------------------------------------------------------------- */
4980   struct terminal *terminal;
4982   NSTRACE ("ns_create_terminal");
4984   terminal = create_terminal (output_ns, &ns_redisplay_interface);
4986   terminal->display_info.ns = dpyinfo;
4987   dpyinfo->terminal = terminal;
4989   terminal->clear_frame_hook = ns_clear_frame;
4990   terminal->ring_bell_hook = ns_ring_bell;
4991   terminal->update_begin_hook = ns_update_begin;
4992   terminal->update_end_hook = ns_update_end;
4993   terminal->read_socket_hook = ns_read_socket;
4994   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4995   terminal->mouse_position_hook = ns_mouse_position;
4996   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4997   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4998   terminal->fullscreen_hook = ns_fullscreen_hook;
4999   terminal->menu_show_hook = ns_menu_show;
5000   terminal->popup_dialog_hook = ns_popup_dialog;
5001   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
5002   terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
5003   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
5004   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
5005   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
5006   terminal->delete_frame_hook = x_destroy_window;
5007   terminal->delete_terminal_hook = ns_delete_terminal;
5008   /* Other hooks are NULL by default.  */
5010   return terminal;
5014 struct ns_display_info *
5015 ns_term_init (Lisp_Object display_name)
5016 /* --------------------------------------------------------------------------
5017      Start the Application and get things rolling.
5018    -------------------------------------------------------------------------- */
5020   struct terminal *terminal;
5021   struct ns_display_info *dpyinfo;
5022   static int ns_initialized = 0;
5023   Lisp_Object tmp;
5025   if (ns_initialized) return x_display_list;
5026   ns_initialized = 1;
5028   block_input ();
5030   NSTRACE ("ns_term_init");
5032   [outerpool release];
5033   outerpool = [[NSAutoreleasePool alloc] init];
5035   /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */
5036   /*GSDebugAllocationActive (YES); */
5037   block_input ();
5039   baud_rate = 38400;
5040   Fset_input_interrupt_mode (Qnil);
5042   if (selfds[0] == -1)
5043     {
5044       if (emacs_pipe (selfds) != 0)
5045         {
5046           fprintf (stderr, "Failed to create pipe: %s\n",
5047                    emacs_strerror (errno));
5048           emacs_abort ();
5049         }
5051       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
5052       FD_ZERO (&select_readfds);
5053       FD_ZERO (&select_writefds);
5054       pthread_mutex_init (&select_mutex, NULL);
5055     }
5057   ns_pending_files = [[NSMutableArray alloc] init];
5058   ns_pending_service_names = [[NSMutableArray alloc] init];
5059   ns_pending_service_args = [[NSMutableArray alloc] init];
5061 /* Start app and create the main menu, window, view.
5062      Needs to be here because ns_initialize_display_info () uses AppKit classes.
5063      The view will then ask the NSApp to stop and return to Emacs. */
5064   [EmacsApp sharedApplication];
5065   if (NSApp == nil)
5066     return NULL;
5067   [NSApp setDelegate: NSApp];
5069   /* Start the select thread.  */
5070   [NSThread detachNewThreadSelector:@selector (fd_handler:)
5071                            toTarget:NSApp
5072                          withObject:nil];
5074   /* debugging: log all notifications */
5075   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
5076                                          selector: @selector (logNotification:)
5077                                              name: nil object: nil]; */
5079   dpyinfo = xzalloc (sizeof *dpyinfo);
5081   ns_initialize_display_info (dpyinfo);
5082   terminal = ns_create_terminal (dpyinfo);
5084   terminal->kboard = allocate_kboard (Qns);
5085   /* Don't let the initial kboard remain current longer than necessary.
5086      That would cause problems if a file loaded on startup tries to
5087      prompt in the mini-buffer.  */
5088   if (current_kboard == initial_kboard)
5089     current_kboard = terminal->kboard;
5090   terminal->kboard->reference_count++;
5092   dpyinfo->next = x_display_list;
5093   x_display_list = dpyinfo;
5095   dpyinfo->name_list_element = Fcons (display_name, Qnil);
5097   terminal->name = xlispstrdup (display_name);
5099   unblock_input ();
5101   if (!inhibit_x_resources)
5102     {
5103       ns_default ("GSFontAntiAlias", &ns_antialias_text,
5104                  Qt, Qnil, NO, NO);
5105       tmp = Qnil;
5106       /* this is a standard variable */
5107       ns_default ("AppleAntiAliasingThreshold", &tmp,
5108                  make_float (10.0), make_float (6.0), YES, NO);
5109       ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp);
5110     }
5112   NSTRACE_MSG ("Colors");
5114   {
5115     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
5117     if ( cl == nil )
5118       {
5119         Lisp_Object color_file, color_map, color;
5120         unsigned long c;
5121         char *name;
5123         color_file = Fexpand_file_name (build_string ("rgb.txt"),
5124                          Fsymbol_value (intern ("data-directory")));
5126         color_map = Fx_load_color_file (color_file);
5127         if (NILP (color_map))
5128           fatal ("Could not read %s.\n", SDATA (color_file));
5130         cl = [[NSColorList alloc] initWithName: @"Emacs"];
5131         for ( ; CONSP (color_map); color_map = XCDR (color_map))
5132           {
5133             color = XCAR (color_map);
5134             name = SSDATA (XCAR (color));
5135             c = XINT (XCDR (color));
5136             [cl setColor:
5137                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
5138                                       green: GREEN_FROM_ULONG (c) / 255.0
5139                                        blue: BLUE_FROM_ULONG (c) / 255.0
5140                                       alpha: 1.0]
5141                   forKey: [NSString stringWithUTF8String: name]];
5142           }
5143         [cl writeToFile: nil];
5144       }
5145   }
5147   NSTRACE_MSG ("Versions");
5149   {
5150 #ifdef NS_IMPL_GNUSTEP
5151     Vwindow_system_version = build_string (gnustep_base_version);
5152 #else
5153     /*PSnextrelease (128, c); */
5154     char c[DBL_BUFSIZE_BOUND];
5155     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
5156     Vwindow_system_version = make_unibyte_string (c, len);
5157 #endif
5158   }
5160   delete_keyboard_wait_descriptor (0);
5162   ns_app_name = [[NSProcessInfo processInfo] processName];
5164   /* Set up macOS app menu */
5166   NSTRACE_MSG ("Menu init");
5168 #ifdef NS_IMPL_COCOA
5169   {
5170     NSMenu *appMenu;
5171     NSMenuItem *item;
5172     /* set up the application menu */
5173     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
5174     [svcsMenu setAutoenablesItems: NO];
5175     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
5176     [appMenu setAutoenablesItems: NO];
5177     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
5178     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
5180     [appMenu insertItemWithTitle: @"About Emacs"
5181                           action: @selector (orderFrontStandardAboutPanel:)
5182                    keyEquivalent: @""
5183                          atIndex: 0];
5184     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
5185     [appMenu insertItemWithTitle: @"Preferences..."
5186                           action: @selector (showPreferencesWindow:)
5187                    keyEquivalent: @","
5188                          atIndex: 2];
5189     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
5190     item = [appMenu insertItemWithTitle: @"Services"
5191                                  action: @selector (menuDown:)
5192                           keyEquivalent: @""
5193                                 atIndex: 4];
5194     [appMenu setSubmenu: svcsMenu forItem: item];
5195     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
5196     [appMenu insertItemWithTitle: @"Hide Emacs"
5197                           action: @selector (hide:)
5198                    keyEquivalent: @"h"
5199                          atIndex: 6];
5200     item =  [appMenu insertItemWithTitle: @"Hide Others"
5201                           action: @selector (hideOtherApplications:)
5202                    keyEquivalent: @"h"
5203                          atIndex: 7];
5204     [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption];
5205     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
5206     [appMenu insertItemWithTitle: @"Quit Emacs"
5207                           action: @selector (terminate:)
5208                    keyEquivalent: @"q"
5209                          atIndex: 9];
5211     item = [mainMenu insertItemWithTitle: ns_app_name
5212                                   action: @selector (menuDown:)
5213                            keyEquivalent: @""
5214                                  atIndex: 0];
5215     [mainMenu setSubmenu: appMenu forItem: item];
5216     [dockMenu insertItemWithTitle: @"New Frame"
5217                            action: @selector (newFrame:)
5218                     keyEquivalent: @""
5219                           atIndex: 0];
5221     [NSApp setMainMenu: mainMenu];
5222     [NSApp setAppleMenu: appMenu];
5223     [NSApp setServicesMenu: svcsMenu];
5224     /* Needed at least on Cocoa, to get dock menu to show windows */
5225     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5227     [[NSNotificationCenter defaultCenter]
5228       addObserver: mainMenu
5229          selector: @selector (trackingNotification:)
5230              name: NSMenuDidBeginTrackingNotification object: mainMenu];
5231     [[NSNotificationCenter defaultCenter]
5232       addObserver: mainMenu
5233          selector: @selector (trackingNotification:)
5234              name: NSMenuDidEndTrackingNotification object: mainMenu];
5235   }
5236 #endif /* macOS menu setup */
5238   /* Register our external input/output types, used for determining
5239      applicable services and also drag/drop eligibility. */
5241   NSTRACE_MSG ("Input/output types");
5243   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5244   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5245                       retain];
5246   ns_drag_types = [[NSArray arrayWithObjects:
5247                             NSStringPboardType,
5248                             NSTabularTextPboardType,
5249                             NSFilenamesPboardType,
5250                             NSURLPboardType, nil] retain];
5252   /* If fullscreen is in init/default-frame-alist, focus isn't set
5253      right for fullscreen windows, so set this.  */
5254   [NSApp activateIgnoringOtherApps:YES];
5256   NSTRACE_MSG ("Call NSApp run");
5258   [NSApp run];
5259   ns_do_open_file = YES;
5261 #ifdef NS_IMPL_GNUSTEP
5262   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5263      We must re-catch it so subprocess works.  */
5264   catch_child_signal ();
5265 #endif
5267   NSTRACE_MSG ("ns_term_init done");
5269   unblock_input ();
5271   return dpyinfo;
5275 void
5276 ns_term_shutdown (int sig)
5278   [[NSUserDefaults standardUserDefaults] synchronize];
5280   /* code not reached in emacs.c after this is called by shut_down_emacs: */
5281   if (STRINGP (Vauto_save_list_file_name))
5282     unlink (SSDATA (Vauto_save_list_file_name));
5284   if (sig == 0 || sig == SIGTERM)
5285     {
5286       [NSApp terminate: NSApp];
5287     }
5288   else // force a stack trace to happen
5289     {
5290       emacs_abort ();
5291     }
5295 /* ==========================================================================
5297     EmacsApp implementation
5299    ========================================================================== */
5302 @implementation EmacsApp
5304 - (id)init
5306   NSTRACE ("[EmacsApp init]");
5308   if ((self = [super init]))
5309     {
5310 #ifdef NS_IMPL_COCOA
5311       self->isFirst = YES;
5312 #endif
5313 #ifdef NS_IMPL_GNUSTEP
5314       self->applicationDidFinishLaunchingCalled = NO;
5315 #endif
5316     }
5318   return self;
5321 #ifdef NS_IMPL_COCOA
5322 - (void)run
5324   NSTRACE ("[EmacsApp run]");
5326 #ifndef NSAppKitVersionNumber10_9
5327 #define NSAppKitVersionNumber10_9 1265
5328 #endif
5330     if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5331       {
5332         [super run];
5333         return;
5334       }
5336   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5338   if (isFirst) [self finishLaunching];
5339   isFirst = NO;
5341   shouldKeepRunning = YES;
5342   do
5343     {
5344       [pool release];
5345       pool = [[NSAutoreleasePool alloc] init];
5347       NSEvent *event =
5348         [self nextEventMatchingMask:NSEventMaskAny
5349                           untilDate:[NSDate distantFuture]
5350                              inMode:NSDefaultRunLoopMode
5351                             dequeue:YES];
5353       [self sendEvent:event];
5354       [self updateWindows];
5355     } while (shouldKeepRunning);
5357   [pool release];
5360 - (void)stop: (id)sender
5362   NSTRACE ("[EmacsApp stop:]");
5364     shouldKeepRunning = NO;
5365     // Stop possible dialog also.  Noop if no dialog present.
5366     // The file dialog still leaks 7k - 10k on 10.9 though.
5367     [super stop:sender];
5369 #endif /* NS_IMPL_COCOA */
5371 - (void)logNotification: (NSNotification *)notification
5373   NSTRACE ("[EmacsApp logNotification:]");
5375   const char *name = [[notification name] UTF8String];
5376   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5377       && !strstr (name, "WindowNumber"))
5378     NSLog (@"notification: '%@'", [notification name]);
5382 - (void)sendEvent: (NSEvent *)theEvent
5383 /* --------------------------------------------------------------------------
5384      Called when NSApp is running for each event received.  Used to stop
5385      the loop when we choose, since there's no way to just run one iteration.
5386    -------------------------------------------------------------------------- */
5388   int type = [theEvent type];
5389   NSWindow *window = [theEvent window];
5391   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5392   NSTRACE_MSG ("Type: %d", type);
5394 #ifdef NS_IMPL_GNUSTEP
5395   // Keyboard events aren't propagated to file dialogs for some reason.
5396   if ([NSApp modalWindow] != nil &&
5397       (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged))
5398     {
5399       [[NSApp modalWindow] sendEvent: theEvent];
5400       return;
5401     }
5402 #endif
5404   if (represented_filename != nil && represented_frame)
5405     {
5406       NSString *fstr = represented_filename;
5407       NSView *view = FRAME_NS_VIEW (represented_frame);
5408 #ifdef NS_IMPL_COCOA
5409       /* work around a bug observed on 10.3 and later where
5410          setTitleWithRepresentedFilename does not clear out previous state
5411          if given filename does not exist */
5412       if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5413         [[view window] setRepresentedFilename: @""];
5414 #endif
5415       [[view window] setRepresentedFilename: fstr];
5416       [represented_filename release];
5417       represented_filename = nil;
5418       represented_frame = NULL;
5419     }
5421   if (type == NSEventTypeApplicationDefined)
5422     {
5423       switch ([theEvent data2])
5424         {
5425 #ifdef NS_IMPL_COCOA
5426         case NSAPP_DATA2_RUNASSCRIPT:
5427           ns_run_ascript ();
5428           [self stop: self];
5429           return;
5430 #endif
5431         case NSAPP_DATA2_RUNFILEDIALOG:
5432           ns_run_file_dialog ();
5433           [self stop: self];
5434           return;
5435         }
5436     }
5438   if (type == NSEventTypeCursorUpdate && window == nil)
5439     {
5440       fprintf (stderr, "Dropping external cursor update event.\n");
5441       return;
5442     }
5444   if (type == NSEventTypeApplicationDefined)
5445     {
5446       /* Events posted by ns_send_appdefined interrupt the run loop here.
5447          But, if a modal window is up, an appdefined can still come through,
5448          (e.g., from a makeKeyWindow event) but stopping self also stops the
5449          modal loop. Just defer it until later. */
5450       if ([NSApp modalWindow] == nil)
5451         {
5452           last_appdefined_event_data = [theEvent data1];
5453           [self stop: self];
5454         }
5455       else
5456         {
5457           send_appdefined = YES;
5458         }
5459     }
5462 #ifdef NS_IMPL_COCOA
5463   /* If no dialog and none of our frames have focus and it is a move, skip it.
5464      It is a mouse move in an auxiliary menu, i.e. on the top right on macOS,
5465      such as Wifi, sound, date or similar.
5466      This prevents "spooky" highlighting in the frame under the menu.  */
5467   if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil)
5468     {
5469       struct ns_display_info *di;
5470       BOOL has_focus = NO;
5471       for (di = x_display_list; ! has_focus && di; di = di->next)
5472         has_focus = di->x_focus_frame != 0;
5473       if (! has_focus)
5474         return;
5475     }
5476 #endif
5478   NSTRACE_UNSILENCE();
5480   [super sendEvent: theEvent];
5484 - (void)showPreferencesWindow: (id)sender
5486   struct frame *emacsframe = SELECTED_FRAME ();
5487   NSEvent *theEvent = [NSApp currentEvent];
5489   if (!emacs_event)
5490     return;
5491   emacs_event->kind = NS_NONKEY_EVENT;
5492   emacs_event->code = KEY_NS_SHOW_PREFS;
5493   emacs_event->modifiers = 0;
5494   EV_TRAILER (theEvent);
5498 - (void)newFrame: (id)sender
5500   NSTRACE ("[EmacsApp newFrame:]");
5502   struct frame *emacsframe = SELECTED_FRAME ();
5503   NSEvent *theEvent = [NSApp currentEvent];
5505   if (!emacs_event)
5506     return;
5507   emacs_event->kind = NS_NONKEY_EVENT;
5508   emacs_event->code = KEY_NS_NEW_FRAME;
5509   emacs_event->modifiers = 0;
5510   EV_TRAILER (theEvent);
5514 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5515 - (BOOL) openFile: (NSString *)fileName
5517   NSTRACE ("[EmacsApp openFile:]");
5519   struct frame *emacsframe = SELECTED_FRAME ();
5520   NSEvent *theEvent = [NSApp currentEvent];
5522   if (!emacs_event)
5523     return NO;
5525   emacs_event->kind = NS_NONKEY_EVENT;
5526   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5527   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5528   ns_input_line = Qnil; /* can be start or cons start,end */
5529   emacs_event->modifiers =0;
5530   EV_TRAILER (theEvent);
5532   return YES;
5536 /* **************************************************************************
5538       EmacsApp delegate implementation
5540    ************************************************************************** */
5542 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5543 /* --------------------------------------------------------------------------
5544      When application is loaded, terminate event loop in ns_term_init
5545    -------------------------------------------------------------------------- */
5547   NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5549 #ifdef NS_IMPL_GNUSTEP
5550   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5551 #endif
5552   [NSApp setServicesProvider: NSApp];
5554   [self antialiasThresholdDidChange:nil];
5555 #ifdef NS_IMPL_COCOA
5556   [[NSNotificationCenter defaultCenter]
5557     addObserver:self
5558        selector:@selector(antialiasThresholdDidChange:)
5559            name:NSAntialiasThresholdChangedNotification
5560          object:nil];
5561 #endif
5563 #ifdef NS_IMPL_COCOA
5564   if ([NSApp activationPolicy] == NSApplicationActivationPolicyProhibited) {
5565     /* Set the app's activation policy to regular when we run outside
5566        of a bundle.  This is already done for us by Info.plist when we
5567        run inside a bundle. */
5568     [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
5569     [NSApp setApplicationIconImage:
5570              [EmacsImage
5571                allocInitFromFile:
5572                  build_string("icons/hicolor/128x128/apps/emacs.png")]];
5573   }
5574 #endif
5576   ns_send_appdefined (-2);
5579 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5581 #ifdef NS_IMPL_COCOA
5582   macfont_update_antialias_threshold ();
5583 #endif
5587 /* Termination sequences:
5588     C-x C-c:
5589     Cmd-Q:
5590     MenuBar | File | Exit:
5591     Select Quit from App menubar:
5592         -terminate
5593         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5594         ns_term_shutdown()
5596     Select Quit from Dock menu:
5597     Logout attempt:
5598         -appShouldTerminate
5599           Cancel -> Nothing else
5600           Accept ->
5602           -terminate
5603           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5604           ns_term_shutdown()
5608 - (void) terminate: (id)sender
5610   NSTRACE ("[EmacsApp terminate:]");
5612   struct frame *emacsframe = SELECTED_FRAME ();
5614   if (!emacs_event)
5615     return;
5617   emacs_event->kind = NS_NONKEY_EVENT;
5618   emacs_event->code = KEY_NS_POWER_OFF;
5619   emacs_event->arg = Qt; /* mark as non-key event */
5620   EV_TRAILER ((id)nil);
5623 static bool
5624 runAlertPanel(NSString *title,
5625               NSString *msgFormat,
5626               NSString *defaultButton,
5627               NSString *alternateButton)
5629 #ifdef NS_IMPL_GNUSTEP
5630   return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5631     == NSAlertDefaultReturn;
5632 #else
5633   NSAlert *alert = [[NSAlert alloc] init];
5634   [alert setAlertStyle: NSAlertStyleCritical];
5635   [alert setMessageText: msgFormat];
5636   [alert addButtonWithTitle: defaultButton];
5637   [alert addButtonWithTitle: alternateButton];
5638   NSInteger ret = [alert runModal];
5639   [alert release];
5640   return ret == NSAlertFirstButtonReturn;
5641 #endif
5645 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5647   NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5649   bool ret;
5651   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
5652     return NSTerminateNow;
5654   ret = runAlertPanel(ns_app_name,
5655                       @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
5656                       @"Save Buffers and Exit", @"Cancel");
5658   return ret ? NSTerminateNow : NSTerminateCancel;
5661 static int
5662 not_in_argv (NSString *arg)
5664   int k;
5665   const char *a = [arg UTF8String];
5666   for (k = 1; k < initial_argc; ++k)
5667     if (strcmp (a, initial_argv[k]) == 0) return 0;
5668   return 1;
5671 /*   Notification from the Workspace to open a file */
5672 - (BOOL)application: sender openFile: (NSString *)file
5674   if (ns_do_open_file || not_in_argv (file))
5675     [ns_pending_files addObject: file];
5676   return YES;
5680 /*   Open a file as a temporary file */
5681 - (BOOL)application: sender openTempFile: (NSString *)file
5683   if (ns_do_open_file || not_in_argv (file))
5684     [ns_pending_files addObject: file];
5685   return YES;
5689 /*   Notification from the Workspace to open a file noninteractively (?) */
5690 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5692   if (ns_do_open_file || not_in_argv (file))
5693     [ns_pending_files addObject: file];
5694   return YES;
5697 /*   Notification from the Workspace to open multiple files */
5698 - (void)application: sender openFiles: (NSArray *)fileList
5700   NSEnumerator *files = [fileList objectEnumerator];
5701   NSString *file;
5702   /* Don't open files from the command line unconditionally,
5703      Cocoa parses the command line wrong, --option value tries to open value
5704      if --option is the last option.  */
5705   while ((file = [files nextObject]) != nil)
5706     if (ns_do_open_file || not_in_argv (file))
5707       [ns_pending_files addObject: file];
5709   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5714 /* Handle dock menu requests.  */
5715 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5717   return dockMenu;
5721 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5722 - (void)applicationWillBecomeActive: (NSNotification *)notification
5724   NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5725   //ns_app_active=YES;
5728 - (void)applicationDidBecomeActive: (NSNotification *)notification
5730   NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5732 #ifdef NS_IMPL_GNUSTEP
5733   if (! applicationDidFinishLaunchingCalled)
5734     [self applicationDidFinishLaunching:notification];
5735 #endif
5736   //ns_app_active=YES;
5738   ns_update_auto_hide_menu_bar ();
5739   // No constraining takes place when the application is not active.
5740   ns_constrain_all_frames ();
5742 - (void)applicationDidResignActive: (NSNotification *)notification
5744   NSTRACE ("[EmacsApp applicationDidResignActive:]");
5746   //ns_app_active=NO;
5747   ns_send_appdefined (-1);
5752 /* ==========================================================================
5754     EmacsApp aux handlers for managing event loop
5756    ========================================================================== */
5759 - (void)timeout_handler: (NSTimer *)timedEntry
5760 /* --------------------------------------------------------------------------
5761      The timeout specified to ns_select has passed.
5762    -------------------------------------------------------------------------- */
5764   /*NSTRACE ("timeout_handler"); */
5765   ns_send_appdefined (-2);
5768 - (void)sendFromMainThread:(id)unused
5770   ns_send_appdefined (nextappdefined);
5773 - (void)fd_handler:(id)unused
5774 /* --------------------------------------------------------------------------
5775      Check data waiting on file descriptors and terminate if so
5776    -------------------------------------------------------------------------- */
5778   int result;
5779   int waiting = 1, nfds;
5780   char c;
5782   fd_set readfds, writefds, *wfds;
5783   struct timespec timeout, *tmo;
5784   NSAutoreleasePool *pool = nil;
5786   /* NSTRACE ("fd_handler"); */
5788   for (;;)
5789     {
5790       [pool release];
5791       pool = [[NSAutoreleasePool alloc] init];
5793       if (waiting)
5794         {
5795           fd_set fds;
5796           FD_ZERO (&fds);
5797           FD_SET (selfds[0], &fds);
5798           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5799           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5800             waiting = 0;
5801         }
5802       else
5803         {
5804           pthread_mutex_lock (&select_mutex);
5805           nfds = select_nfds;
5807           if (select_valid & SELECT_HAVE_READ)
5808             readfds = select_readfds;
5809           else
5810             FD_ZERO (&readfds);
5812           if (select_valid & SELECT_HAVE_WRITE)
5813             {
5814               writefds = select_writefds;
5815               wfds = &writefds;
5816             }
5817           else
5818             wfds = NULL;
5819           if (select_valid & SELECT_HAVE_TMO)
5820             {
5821               timeout = select_timeout;
5822               tmo = &timeout;
5823             }
5824           else
5825             tmo = NULL;
5827           pthread_mutex_unlock (&select_mutex);
5829           FD_SET (selfds[0], &readfds);
5830           if (selfds[0] >= nfds) nfds = selfds[0]+1;
5832           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5834           if (result == 0)
5835             ns_send_appdefined (-2);
5836           else if (result > 0)
5837             {
5838               if (FD_ISSET (selfds[0], &readfds))
5839                 {
5840                   if (read (selfds[0], &c, 1) == 1 && c == 's')
5841                     waiting = 1;
5842                 }
5843               else
5844                 {
5845                   pthread_mutex_lock (&select_mutex);
5846                   if (select_valid & SELECT_HAVE_READ)
5847                     select_readfds = readfds;
5848                   if (select_valid & SELECT_HAVE_WRITE)
5849                     select_writefds = writefds;
5850                   if (select_valid & SELECT_HAVE_TMO)
5851                     select_timeout = timeout;
5852                   pthread_mutex_unlock (&select_mutex);
5854                   ns_send_appdefined (result);
5855                 }
5856             }
5857           waiting = 1;
5858         }
5859     }
5864 /* ==========================================================================
5866     Service provision
5868    ========================================================================== */
5870 /* called from system: queue for next pass through event loop */
5871 - (void)requestService: (NSPasteboard *)pboard
5872               userData: (NSString *)userData
5873                  error: (NSString **)error
5875   [ns_pending_service_names addObject: userData];
5876   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5877       SSDATA (ns_string_from_pasteboard (pboard))]];
5881 /* called from ns_read_socket to clear queue */
5882 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5884   struct frame *emacsframe = SELECTED_FRAME ();
5885   NSEvent *theEvent = [NSApp currentEvent];
5887   NSTRACE ("[EmacsApp fulfillService:withArg:]");
5889   if (!emacs_event)
5890     return NO;
5892   emacs_event->kind = NS_NONKEY_EVENT;
5893   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5894   ns_input_spi_name = build_string ([name UTF8String]);
5895   ns_input_spi_arg = build_string ([arg UTF8String]);
5896   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5897   EV_TRAILER (theEvent);
5899   return YES;
5903 @end  /* EmacsApp */
5907 /* ==========================================================================
5909     EmacsView implementation
5911    ========================================================================== */
5914 @implementation EmacsView
5916 /* needed to inform when window closed from LISP */
5917 - (void) setWindowClosing: (BOOL)closing
5919   NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5921   windowClosing = closing;
5925 - (void)dealloc
5927   NSTRACE ("[EmacsView dealloc]");
5928   [toolbar release];
5929   if (fs_state == FULLSCREEN_BOTH)
5930     [nonfs_window release];
5931   [super dealloc];
5935 /* called on font panel selection */
5936 - (void)changeFont: (id)sender
5938   NSEvent *e = [[self window] currentEvent];
5939   struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID);
5940   struct font *font = face->font;
5941   id newFont;
5942   CGFloat size;
5943   NSFont *nsfont;
5945   NSTRACE ("[EmacsView changeFont:]");
5947   if (!emacs_event)
5948     return;
5950 #ifdef NS_IMPL_GNUSTEP
5951   nsfont = ((struct nsfont_info *)font)->nsfont;
5952 #endif
5953 #ifdef NS_IMPL_COCOA
5954   nsfont = (NSFont *) macfont_get_nsctfont (font);
5955 #endif
5957   if ((newFont = [sender convertFont: nsfont]))
5958     {
5959       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5961       emacs_event->kind = NS_NONKEY_EVENT;
5962       emacs_event->modifiers = 0;
5963       emacs_event->code = KEY_NS_CHANGE_FONT;
5965       size = [newFont pointSize];
5966       ns_input_fontsize = make_number (lrint (size));
5967       ns_input_font = build_string ([[newFont familyName] UTF8String]);
5968       EV_TRAILER (e);
5969     }
5973 - (BOOL)acceptsFirstResponder
5975   NSTRACE ("[EmacsView acceptsFirstResponder]");
5976   return YES;
5980 - (void)resetCursorRects
5982   NSRect visible = [self visibleRect];
5983   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5984   NSTRACE ("[EmacsView resetCursorRects]");
5986   if (currentCursor == nil)
5987     currentCursor = [NSCursor arrowCursor];
5989   if (!NSIsEmptyRect (visible))
5990     [self addCursorRect: visible cursor: currentCursor];
5991   [currentCursor setOnMouseEntered: YES];
5996 /*****************************************************************************/
5997 /* Keyboard handling. */
5998 #define NS_KEYLOG 0
6000 - (void)keyDown: (NSEvent *)theEvent
6002   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6003   int code;
6004   unsigned fnKeysym = 0;
6005   static NSMutableArray *nsEvArray;
6006   int left_is_none;
6007   unsigned int flags = [theEvent modifierFlags];
6009   NSTRACE ("[EmacsView keyDown:]");
6011   /* Rhapsody and macOS give up and down events for the arrow keys */
6012   if (ns_fake_keydown == YES)
6013     ns_fake_keydown = NO;
6014   else if ([theEvent type] != NSEventTypeKeyDown)
6015     return;
6017   if (!emacs_event)
6018     return;
6020  if (![[self window] isKeyWindow]
6021      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
6022      /* we must avoid an infinite loop here. */
6023      && (EmacsView *)[[theEvent window] delegate] != self)
6024    {
6025      /* XXX: There is an occasional condition in which, when Emacs display
6026          updates a different frame from the current one, and temporarily
6027          selects it, then processes some interrupt-driven input
6028          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
6029          for some reason that window has its first responder set to the NSView
6030          most recently updated (I guess), which is not the correct one. */
6031      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
6032      return;
6033    }
6035   if (nsEvArray == nil)
6036     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
6038   [NSCursor setHiddenUntilMouseMoves: YES];
6040   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
6041     {
6042       clear_mouse_face (hlinfo);
6043       hlinfo->mouse_face_hidden = 1;
6044     }
6046   if (!processingCompose)
6047     {
6048       /* When using screen sharing, no left or right information is sent,
6049          so use Left key in those cases.  */
6050       int is_left_key, is_right_key;
6052       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
6053         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
6055       /* (Carbon way: [theEvent keyCode]) */
6057       /* is it a "function key"? */
6058       /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad
6059          flag set (this is probably a bug in the OS).
6060       */
6061       if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad))
6062         {
6063           fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad);
6064         }
6065       if (fnKeysym == 0)
6066         {
6067           fnKeysym = ns_convert_key (code);
6068         }
6070       if (fnKeysym)
6071         {
6072           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
6073              because Emacs treats Delete and KP-Delete same (in simple.el). */
6074           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
6075 #ifdef NS_IMPL_GNUSTEP
6076               /*  GNUstep uses incompatible keycodes, even for those that are
6077                   supposed to be hardware independent.  Just check for delete.
6078                   Keypad delete does not have keysym 0xFFFF.
6079                   See http://savannah.gnu.org/bugs/?25395
6080               */
6081               || (fnKeysym == 0xFFFF && code == 127)
6082 #endif
6083             )
6084             code = 0xFF08; /* backspace */
6085           else
6086             code = fnKeysym;
6087         }
6089       /* are there modifiers? */
6090       emacs_event->modifiers = 0;
6092       if (flags & NSEventModifierFlagHelp)
6093           emacs_event->modifiers |= hyper_modifier;
6095       if (flags & NSEventModifierFlagShift)
6096         emacs_event->modifiers |= shift_modifier;
6098       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
6099       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
6100         || (! is_right_key && (flags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand);
6102       if (is_right_key)
6103         emacs_event->modifiers |= parse_solitary_modifier
6104           (EQ (ns_right_command_modifier, Qleft)
6105            ? ns_command_modifier
6106            : ns_right_command_modifier);
6108       if (is_left_key)
6109         {
6110           emacs_event->modifiers |= parse_solitary_modifier
6111             (ns_command_modifier);
6113           /* if super (default), take input manager's word so things like
6114              dvorak / qwerty layout work */
6115           if (EQ (ns_command_modifier, Qsuper)
6116               && !fnKeysym
6117               && [[theEvent characters] length] != 0)
6118             {
6119               /* XXX: the code we get will be unshifted, so if we have
6120                  a shift modifier, must convert ourselves */
6121               if (!(flags & NSEventModifierFlagShift))
6122                 code = [[theEvent characters] characterAtIndex: 0];
6123 #if 0
6124               /* this is ugly and also requires linking w/Carbon framework
6125                  (for LMGetKbdType) so for now leave this rare (?) case
6126                  undealt with.. in future look into CGEvent methods */
6127               else
6128                 {
6129                   long smv = GetScriptManagerVariable (smKeyScript);
6130                   Handle uchrHandle = GetResource
6131                     ('uchr', GetScriptVariable (smv, smScriptKeys));
6132                   UInt32 dummy = 0;
6133                   UCKeyTranslate ((UCKeyboardLayout *) *uchrHandle,
6134                                  [[theEvent characters] characterAtIndex: 0],
6135                                  kUCKeyActionDisplay,
6136                                  (flags & ~NSEventModifierFlagCommand) >> 8,
6137                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
6138                                  &dummy, 1, &dummy, &code);
6139                   code &= 0xFF;
6140                 }
6141 #endif
6142             }
6143         }
6145       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
6146       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
6147         || (! is_right_key && (flags & NSEventModifierFlagControl) == NSEventModifierFlagControl);
6149       if (is_right_key)
6150           emacs_event->modifiers |= parse_solitary_modifier
6151               (EQ (ns_right_control_modifier, Qleft)
6152                ? ns_control_modifier
6153                : ns_right_control_modifier);
6155       if (is_left_key)
6156         emacs_event->modifiers |= parse_solitary_modifier
6157           (ns_control_modifier);
6159       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
6160           emacs_event->modifiers |=
6161             parse_solitary_modifier (ns_function_modifier);
6163       left_is_none = NILP (ns_alternate_modifier)
6164         || EQ (ns_alternate_modifier, Qnone);
6166       is_right_key = (flags & NSRightAlternateKeyMask)
6167         == NSRightAlternateKeyMask;
6168       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
6169         || (! is_right_key
6170             && (flags & NSEventModifierFlagOption) == NSEventModifierFlagOption);
6172       if (is_right_key)
6173         {
6174           if ((NILP (ns_right_alternate_modifier)
6175                || EQ (ns_right_alternate_modifier, Qnone)
6176                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
6177               && !fnKeysym)
6178             {   /* accept pre-interp alt comb */
6179               if ([[theEvent characters] length] > 0)
6180                 code = [[theEvent characters] characterAtIndex: 0];
6181               /*HACK: clear lone shift modifier to stop next if from firing */
6182               if (emacs_event->modifiers == shift_modifier)
6183                 emacs_event->modifiers = 0;
6184             }
6185           else
6186             emacs_event->modifiers |= parse_solitary_modifier
6187               (EQ (ns_right_alternate_modifier, Qleft)
6188                ? ns_alternate_modifier
6189                : ns_right_alternate_modifier);
6190         }
6192       if (is_left_key) /* default = meta */
6193         {
6194           if (left_is_none && !fnKeysym)
6195             {   /* accept pre-interp alt comb */
6196               if ([[theEvent characters] length] > 0)
6197                 code = [[theEvent characters] characterAtIndex: 0];
6198               /*HACK: clear lone shift modifier to stop next if from firing */
6199               if (emacs_event->modifiers == shift_modifier)
6200                 emacs_event->modifiers = 0;
6201             }
6202           else
6203               emacs_event->modifiers |=
6204                 parse_solitary_modifier (ns_alternate_modifier);
6205         }
6207   if (NS_KEYLOG)
6208     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6209              (unsigned) code, fnKeysym, flags, emacs_event->modifiers);
6211       /* if it was a function key or had modifiers, pass it directly to emacs */
6212       if (fnKeysym || (emacs_event->modifiers
6213                        && (emacs_event->modifiers != shift_modifier)
6214                        && [[theEvent charactersIgnoringModifiers] length] > 0))
6215 /*[[theEvent characters] length] */
6216         {
6217           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6218           if (code < 0x20)
6219             code |= (1<<28)|(3<<16);
6220           else if (code == 0x7f)
6221             code |= (1<<28)|(3<<16);
6222           else if (!fnKeysym)
6223             emacs_event->kind = code > 0xFF
6224               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6226           emacs_event->code = code;
6227           EV_TRAILER (theEvent);
6228           processingCompose = NO;
6229           return;
6230         }
6231     }
6234   if (NS_KEYLOG && !processingCompose)
6235     fprintf (stderr, "keyDown: Begin compose sequence.\n");
6237   processingCompose = YES;
6238   [nsEvArray addObject: theEvent];
6239   [self interpretKeyEvents: nsEvArray];
6240   [nsEvArray removeObject: theEvent];
6244 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6247 /* <NSTextInput>: called when done composing;
6248    NOTE: also called when we delete over working text, followed immed.
6249          by doCommandBySelector: deleteBackward: */
6250 - (void)insertText: (id)aString
6252   int code;
6253   int len = [(NSString *)aString length];
6254   int i;
6256   NSTRACE ("[EmacsView insertText:]");
6258   if (NS_KEYLOG)
6259     NSLog (@"insertText '%@'\tlen = %d", aString, len);
6260   processingCompose = NO;
6262   if (!emacs_event)
6263     return;
6265   /* first, clear any working text */
6266   if (workingText != nil)
6267     [self deleteWorkingText];
6269   /* now insert the string as keystrokes */
6270   for (i =0; i<len; i++)
6271     {
6272       code = [aString characterAtIndex: i];
6273       /* TODO: still need this? */
6274       if (code == 0x2DC)
6275         code = '~'; /* 0x7E */
6276       if (code != 32) /* Space */
6277         emacs_event->modifiers = 0;
6278       emacs_event->kind
6279         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6280       emacs_event->code = code;
6281       EV_TRAILER ((id)nil);
6282     }
6286 /* <NSTextInput>: inserts display of composing characters */
6287 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6289   NSString *str = [aString respondsToSelector: @selector (string)] ?
6290     [aString string] : aString;
6292   NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6294   if (NS_KEYLOG)
6295     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6296            str, (unsigned long)[str length],
6297            (unsigned long)selRange.length,
6298            (unsigned long)selRange.location);
6300   if (workingText != nil)
6301     [self deleteWorkingText];
6302   if ([str length] == 0)
6303     return;
6305   if (!emacs_event)
6306     return;
6308   processingCompose = YES;
6309   workingText = [str copy];
6310   ns_working_text = build_string ([workingText UTF8String]);
6312   emacs_event->kind = NS_TEXT_EVENT;
6313   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6314   EV_TRAILER ((id)nil);
6318 /* delete display of composing characters [not in <NSTextInput>] */
6319 - (void)deleteWorkingText
6321   NSTRACE ("[EmacsView deleteWorkingText]");
6323   if (workingText == nil)
6324     return;
6325   if (NS_KEYLOG)
6326     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6327   [workingText release];
6328   workingText = nil;
6329   processingCompose = NO;
6331   if (!emacs_event)
6332     return;
6334   emacs_event->kind = NS_TEXT_EVENT;
6335   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6336   EV_TRAILER ((id)nil);
6340 - (BOOL)hasMarkedText
6342   NSTRACE ("[EmacsView hasMarkedText]");
6344   return workingText != nil;
6348 - (NSRange)markedRange
6350   NSTRACE ("[EmacsView markedRange]");
6352   NSRange rng = workingText != nil
6353     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6354   if (NS_KEYLOG)
6355     NSLog (@"markedRange request");
6356   return rng;
6360 - (void)unmarkText
6362   NSTRACE ("[EmacsView unmarkText]");
6364   if (NS_KEYLOG)
6365     NSLog (@"unmark (accept) text");
6366   [self deleteWorkingText];
6367   processingCompose = NO;
6371 /* used to position char selection windows, etc. */
6372 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6374   NSRect rect;
6375   NSPoint pt;
6376   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6378   NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6380   if (NS_KEYLOG)
6381     NSLog (@"firstRectForCharRange request");
6383   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6384   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6385   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6386   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6387                                        +FRAME_LINE_HEIGHT (emacsframe));
6389   pt = [self convertPoint: pt toView: nil];
6391 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6392 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6393   if ([[self window] respondsToSelector: @selector(convertRectToScreen:)])
6394     {
6395 #endif
6396       rect.origin = pt;
6397       rect = [(EmacsWindow *) [self window] convertRectToScreen: rect];
6398 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6399     }
6400   else
6401 #endif
6402 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6403 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
6404   || defined (NS_IMPL_GNUSTEP)
6405     {
6406       pt = [[self window] convertBaseToScreen: pt];
6407       rect.origin = pt;
6408     }
6409 #endif
6411   return rect;
6415 - (NSInteger)conversationIdentifier
6417   return (NSInteger)self;
6421 - (void)doCommandBySelector: (SEL)aSelector
6423   NSTRACE ("[EmacsView doCommandBySelector:]");
6425   if (NS_KEYLOG)
6426     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6428   processingCompose = NO;
6429   if (aSelector == @selector (deleteBackward:))
6430     {
6431       /* happens when user backspaces over an ongoing composition:
6432          throw a 'delete' into the event queue */
6433       if (!emacs_event)
6434         return;
6435       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6436       emacs_event->code = 0xFF08;
6437       EV_TRAILER ((id)nil);
6438     }
6441 - (NSArray *)validAttributesForMarkedText
6443   static NSArray *arr = nil;
6444   if (arr == nil) arr = [NSArray new];
6445  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6446   return arr;
6449 - (NSRange)selectedRange
6451   if (NS_KEYLOG)
6452     NSLog (@"selectedRange request");
6453   return NSMakeRange (NSNotFound, 0);
6456 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6457     GNUSTEP_GUI_MINOR_VERSION > 22
6458 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6459 #else
6460 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6461 #endif
6463   if (NS_KEYLOG)
6464     NSLog (@"characterIndexForPoint request");
6465   return 0;
6468 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6470   static NSAttributedString *str = nil;
6471   if (str == nil) str = [NSAttributedString new];
6472   if (NS_KEYLOG)
6473     NSLog (@"attributedSubstringFromRange request");
6474   return str;
6477 /* End <NSTextInput> impl. */
6478 /*****************************************************************************/
6481 /* This is what happens when the user presses a mouse button.  */
6482 - (void)mouseDown: (NSEvent *)theEvent
6484   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6485   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6487   NSTRACE ("[EmacsView mouseDown:]");
6489   [self deleteWorkingText];
6491   if (!emacs_event)
6492     return;
6494   dpyinfo->last_mouse_frame = emacsframe;
6495   /* appears to be needed to prevent spurious movement events generated on
6496      button clicks */
6497   emacsframe->mouse_moved = 0;
6499   if ([theEvent type] == NSEventTypeScrollWheel)
6500     {
6501       CGFloat delta = [theEvent deltaY];
6502       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6503       if (delta == 0)
6504         {
6505           delta = [theEvent deltaX];
6506           if (delta == 0)
6507             {
6508               NSTRACE_MSG ("deltaIsZero");
6509               return;
6510             }
6511           emacs_event->kind = HORIZ_WHEEL_EVENT;
6512         }
6513       else
6514         emacs_event->kind = WHEEL_EVENT;
6516       emacs_event->code = 0;
6517       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6518         ((delta > 0) ? up_modifier : down_modifier);
6519     }
6520   else
6521     {
6522       emacs_event->kind = MOUSE_CLICK_EVENT;
6523       emacs_event->code = EV_BUTTON (theEvent);
6524       emacs_event->modifiers = EV_MODIFIERS (theEvent)
6525                              | EV_UDMODIFIERS (theEvent);
6526     }
6527   XSETINT (emacs_event->x, lrint (p.x));
6528   XSETINT (emacs_event->y, lrint (p.y));
6529   EV_TRAILER (theEvent);
6533 - (void)rightMouseDown: (NSEvent *)theEvent
6535   NSTRACE ("[EmacsView rightMouseDown:]");
6536   [self mouseDown: theEvent];
6540 - (void)otherMouseDown: (NSEvent *)theEvent
6542   NSTRACE ("[EmacsView otherMouseDown:]");
6543   [self mouseDown: theEvent];
6547 - (void)mouseUp: (NSEvent *)theEvent
6549   NSTRACE ("[EmacsView mouseUp:]");
6550   [self mouseDown: theEvent];
6554 - (void)rightMouseUp: (NSEvent *)theEvent
6556   NSTRACE ("[EmacsView rightMouseUp:]");
6557   [self mouseDown: theEvent];
6561 - (void)otherMouseUp: (NSEvent *)theEvent
6563   NSTRACE ("[EmacsView otherMouseUp:]");
6564   [self mouseDown: theEvent];
6568 - (void) scrollWheel: (NSEvent *)theEvent
6570   NSTRACE ("[EmacsView scrollWheel:]");
6571   [self mouseDown: theEvent];
6575 /* Tell emacs the mouse has moved. */
6576 - (void)mouseMoved: (NSEvent *)e
6578   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6579   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6580   Lisp_Object frame;
6581   NSPoint pt;
6583   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6585   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6586   pt = [self convertPoint: [e locationInWindow] fromView: nil];
6587   dpyinfo->last_mouse_motion_x = pt.x;
6588   dpyinfo->last_mouse_motion_y = pt.y;
6590   /* update any mouse face */
6591   if (hlinfo->mouse_face_hidden)
6592     {
6593       hlinfo->mouse_face_hidden = 0;
6594       clear_mouse_face (hlinfo);
6595     }
6597   /* tooltip handling */
6598   previous_help_echo_string = help_echo_string;
6599   help_echo_string = Qnil;
6601   if (!NILP (Vmouse_autoselect_window))
6602     {
6603       NSTRACE_MSG ("mouse_autoselect_window");
6604       static Lisp_Object last_mouse_window;
6605       Lisp_Object window
6606         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6608       if (WINDOWP (window)
6609           && !EQ (window, last_mouse_window)
6610           && !EQ (window, selected_window)
6611           && (!NILP (focus_follows_mouse)
6612               || (EQ (XWINDOW (window)->frame,
6613                       XWINDOW (selected_window)->frame))))
6614         {
6615           NSTRACE_MSG ("in_window");
6616           emacs_event->kind = SELECT_WINDOW_EVENT;
6617           emacs_event->frame_or_window = window;
6618           EV_TRAILER2 (e);
6619         }
6620       /* Remember the last window where we saw the mouse.  */
6621       last_mouse_window = window;
6622     }
6624   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6625     help_echo_string = previous_help_echo_string;
6627   XSETFRAME (frame, emacsframe);
6628   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6629     {
6630       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6631          (note_mouse_highlight), which is called through the
6632          note_mouse_movement () call above */
6633       any_help_event_p = YES;
6634       gen_help_event (help_echo_string, frame, help_echo_window,
6635                       help_echo_object, help_echo_pos);
6636     }
6638   if (emacsframe->mouse_moved && send_appdefined)
6639     ns_send_appdefined (-1);
6643 - (void)mouseDragged: (NSEvent *)e
6645   NSTRACE ("[EmacsView mouseDragged:]");
6646   [self mouseMoved: e];
6650 - (void)rightMouseDragged: (NSEvent *)e
6652   NSTRACE ("[EmacsView rightMouseDragged:]");
6653   [self mouseMoved: e];
6657 - (void)otherMouseDragged: (NSEvent *)e
6659   NSTRACE ("[EmacsView otherMouseDragged:]");
6660   [self mouseMoved: e];
6664 - (BOOL)windowShouldClose: (id)sender
6666   NSEvent *e =[[self window] currentEvent];
6668   NSTRACE ("[EmacsView windowShouldClose:]");
6669   windowClosing = YES;
6670   if (!emacs_event)
6671     return NO;
6672   emacs_event->kind = DELETE_WINDOW_EVENT;
6673   emacs_event->modifiers = 0;
6674   emacs_event->code = 0;
6675   EV_TRAILER (e);
6676   /* Don't close this window, let this be done from lisp code.  */
6677   return NO;
6680 - (void) updateFrameSize: (BOOL) delay
6682   NSWindow *window = [self window];
6683   NSRect wr = [window frame];
6684   int extra = 0;
6685   int oldc = cols, oldr = rows;
6686   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6687   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6688   int neww, newh;
6690   NSTRACE ("[EmacsView updateFrameSize:]");
6691   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6692   NSTRACE_RECT ("Original frame", wr);
6693   NSTRACE_MSG  ("Original columns: %d", cols);
6694   NSTRACE_MSG  ("Original rows: %d", rows);
6696   if (! [self isFullscreen])
6697     {
6698 #ifdef NS_IMPL_GNUSTEP
6699       // GNUstep does not always update the tool bar height.  Force it.
6700       if (toolbar && [toolbar isVisible])
6701           update_frame_tool_bar (emacsframe);
6702 #endif
6704       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6705         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6706     }
6708   if (wait_for_tool_bar)
6709     {
6710       /* The toolbar height is always 0 in fullscreen, so don't wait
6711          for it to become available. */
6712       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0
6713           && ! [self isFullscreen])
6714         {
6715           NSTRACE_MSG ("Waiting for toolbar");
6716           return;
6717         }
6718       wait_for_tool_bar = NO;
6719     }
6721   neww = (int)wr.size.width - emacsframe->border_width;
6722   newh = (int)wr.size.height - extra;
6724   NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6725   NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
6726   NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
6728   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6729   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6731   if (cols < MINWIDTH)
6732     cols = MINWIDTH;
6734   if (rows < MINHEIGHT)
6735     rows = MINHEIGHT;
6737   NSTRACE_MSG ("New columns: %d", cols);
6738   NSTRACE_MSG ("New rows: %d", rows);
6740   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6741     {
6742       NSView *view = FRAME_NS_VIEW (emacsframe);
6744       change_frame_size (emacsframe,
6745                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6746                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6747                          0, delay, 0, 1);
6748       SET_FRAME_GARBAGED (emacsframe);
6749       cancel_mouse_face (emacsframe);
6751       /* The next two lines appear to be setting the frame to the same
6752          size as it already is.  Why are they there? */
6753       // wr = NSMakeRect (0, 0, neww, newh);
6755       // [view setFrame: wr];
6757       // to do: consider using [NSNotificationCenter postNotificationName:].
6758       [self windowDidMove: // Update top/left.
6759               [NSNotification notificationWithName:NSWindowDidMoveNotification
6760                                             object:[view window]]];
6761     }
6762   else
6763     {
6764       NSTRACE_MSG ("No change");
6765     }
6768 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6769 /* normalize frame to gridded text size */
6771   int extra = 0;
6773   NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6774            NSTRACE_ARG_SIZE (frameSize));
6775   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6776   NSTRACE_FSTYPE ("fs_state", fs_state);
6778   if (fs_state == FULLSCREEN_MAXIMIZED
6779       && (maximized_width != (int)frameSize.width
6780           || maximized_height != (int)frameSize.height))
6781     [self setFSValue: FULLSCREEN_NONE];
6782   else if (fs_state == FULLSCREEN_WIDTH
6783            && maximized_width != (int)frameSize.width)
6784     [self setFSValue: FULLSCREEN_NONE];
6785   else if (fs_state == FULLSCREEN_HEIGHT
6786            && maximized_height != (int)frameSize.height)
6787     [self setFSValue: FULLSCREEN_NONE];
6789   if (fs_state == FULLSCREEN_NONE)
6790     maximized_width = maximized_height = -1;
6792   if (! [self isFullscreen])
6793     {
6794       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6795         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6796     }
6798   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6799   if (cols < MINWIDTH)
6800     cols = MINWIDTH;
6802   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6803                                            frameSize.height - extra);
6804   if (rows < MINHEIGHT)
6805     rows = MINHEIGHT;
6806 #ifdef NS_IMPL_COCOA
6807   {
6808     /* this sets window title to have size in it; the wm does this under GS */
6809     NSRect r = [[self window] frame];
6810     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6811       {
6812         if (old_title != 0)
6813           {
6814             xfree (old_title);
6815             old_title = 0;
6816           }
6817       }
6818     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
6819              && [[self window] title] != NULL)
6820       {
6821         char *size_title;
6822         NSWindow *window = [self window];
6823         if (old_title == 0)
6824           {
6825             char *t = strdup ([[[self window] title] UTF8String]);
6826             char *pos = strstr (t, "  â€”  ");
6827             if (pos)
6828               *pos = '\0';
6829             old_title = t;
6830           }
6831         size_title = xmalloc (strlen (old_title) + 40);
6832         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
6833         [window setTitle: [NSString stringWithUTF8String: size_title]];
6834         [window display];
6835         xfree (size_title);
6836       }
6837   }
6838 #endif /* NS_IMPL_COCOA */
6840   NSTRACE_MSG ("cols: %d  rows: %d", cols, rows);
6842   /* Restrict the new size to the text gird.
6844      Don't restrict the width if the user only adjusted the height, and
6845      vice versa.  (Without this, the frame would shrink, and move
6846      slightly, if the window was resized by dragging one of its
6847      borders.) */
6848   if (!frame_resize_pixelwise)
6849     {
6850       NSRect r = [[self window] frame];
6852       if (r.size.width != frameSize.width)
6853         {
6854           frameSize.width =
6855             FRAME_TEXT_COLS_TO_PIXEL_WIDTH  (emacsframe, cols);
6856         }
6858       if (r.size.height != frameSize.height)
6859         {
6860           frameSize.height =
6861             FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6862         }
6863     }
6865   NSTRACE_RETURN_SIZE (frameSize);
6867   return frameSize;
6871 - (void)windowDidResize: (NSNotification *)notification
6873   NSTRACE ("[EmacsView windowDidResize:]");
6874   if (!FRAME_LIVE_P (emacsframe))
6875     {
6876       NSTRACE_MSG ("Ignored (frame dead)");
6877       return;
6878     }
6879   if (emacsframe->output_data.ns->in_animation)
6880     {
6881       NSTRACE_MSG ("Ignored (in animation)");
6882       return;
6883     }
6885   if (! [self fsIsNative])
6886     {
6887       NSWindow *theWindow = [notification object];
6888       /* We can get notification on the non-FS window when in
6889          fullscreen mode.  */
6890       if ([self window] != theWindow) return;
6891     }
6893   NSTRACE_RECT ("frame", [[notification object] frame]);
6895 #ifdef NS_IMPL_GNUSTEP
6896   NSWindow *theWindow = [notification object];
6898    /* In GNUstep, at least currently, it's possible to get a didResize
6899       without getting a willResize.. therefore we need to act as if we got
6900       the willResize now */
6901   NSSize sz = [theWindow frame].size;
6902   sz = [self windowWillResize: theWindow toSize: sz];
6903 #endif /* NS_IMPL_GNUSTEP */
6905   if (cols > 0 && rows > 0)
6906     {
6907       [self updateFrameSize: YES];
6908     }
6910   ns_send_appdefined (-1);
6913 #ifdef NS_IMPL_COCOA
6914 - (void)viewDidEndLiveResize
6916   NSTRACE ("[EmacsView viewDidEndLiveResize]");
6918   [super viewDidEndLiveResize];
6919   if (old_title != 0)
6920     {
6921       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6922       xfree (old_title);
6923       old_title = 0;
6924     }
6925   maximizing_resize = NO;
6927 #endif /* NS_IMPL_COCOA */
6930 - (void)windowDidBecomeKey: (NSNotification *)notification
6931 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6933   [self windowDidBecomeKey];
6937 - (void)windowDidBecomeKey      /* for direct calls */
6939   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6940   struct frame *old_focus = dpyinfo->x_focus_frame;
6942   NSTRACE ("[EmacsView windowDidBecomeKey]");
6944   if (emacsframe != old_focus)
6945     dpyinfo->x_focus_frame = emacsframe;
6947   ns_frame_rehighlight (emacsframe);
6949   if (emacs_event)
6950     {
6951       emacs_event->kind = FOCUS_IN_EVENT;
6952       EV_TRAILER ((id)nil);
6953     }
6957 - (void)windowDidResignKey: (NSNotification *)notification
6958 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6960   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6961   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6962   NSTRACE ("[EmacsView windowDidResignKey:]");
6964   if (is_focus_frame)
6965     dpyinfo->x_focus_frame = 0;
6967   emacsframe->mouse_moved = 0;
6968   ns_frame_rehighlight (emacsframe);
6970   /* FIXME: for some reason needed on second and subsequent clicks away
6971             from sole-frame Emacs to get hollow box to show */
6972   if (!windowClosing && [[self window] isVisible] == YES)
6973     {
6974       x_update_cursor (emacsframe, 1);
6975       x_set_frame_alpha (emacsframe);
6976     }
6978   if (any_help_event_p)
6979     {
6980       Lisp_Object frame;
6981       XSETFRAME (frame, emacsframe);
6982       help_echo_string = Qnil;
6983       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6984     }
6986   if (emacs_event && is_focus_frame)
6987     {
6988       [self deleteWorkingText];
6989       emacs_event->kind = FOCUS_OUT_EVENT;
6990       EV_TRAILER ((id)nil);
6991     }
6995 - (void)windowWillMiniaturize: sender
6997   NSTRACE ("[EmacsView windowWillMiniaturize:]");
7001 - (void)setFrame:(NSRect)frameRect
7003   NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
7004            NSTRACE_ARG_RECT (frameRect));
7006   [super setFrame:(NSRect)frameRect];
7010 - (BOOL)isFlipped
7012   return YES;
7016 - (BOOL)isOpaque
7018   return NO;
7022 - (void)createToolbar: (struct frame *)f
7024   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
7025   NSWindow *window = [view window];
7027   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
7028                    [NSString stringWithFormat: @"Emacs Frame %d",
7029                              ns_window_num]];
7030   [toolbar setVisible: NO];
7031   [window setToolbar: toolbar];
7033   /* Don't set frame garbaged until tool bar is up to date?
7034      This avoids an extra clear and redraw (flicker) at frame creation.  */
7035   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
7036   else wait_for_tool_bar = NO;
7039 #ifdef NS_IMPL_COCOA
7040   {
7041     NSButton *toggleButton;
7042     toggleButton = [window standardWindowButton: NSWindowToolbarButton];
7043     [toggleButton setTarget: self];
7044     [toggleButton setAction: @selector (toggleToolbar: )];
7045   }
7046 #endif
7050 - (instancetype) initFrameFromEmacs: (struct frame *)f
7052   NSRect r, wr;
7053   Lisp_Object tem;
7054   NSWindow *win;
7055   NSColor *col;
7056   NSString *name;
7058   NSTRACE ("[EmacsView initFrameFromEmacs:]");
7059   NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
7061   windowClosing = NO;
7062   processingCompose = NO;
7063   scrollbarsNeedingUpdate = 0;
7064   fs_state = FULLSCREEN_NONE;
7065   fs_before_fs = next_maximized = -1;
7067   fs_is_native = NO;
7068 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7069 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7070   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7071 #endif
7072     fs_is_native = ns_use_native_fullscreen;
7073 #endif
7075   maximized_width = maximized_height = -1;
7076   nonfs_window = nil;
7078   ns_userRect = NSMakeRect (0, 0, 0, 0);
7079   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
7080                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
7081   [self initWithFrame: r];
7082   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
7084   FRAME_NS_VIEW (f) = self;
7085   emacsframe = f;
7086 #ifdef NS_IMPL_COCOA
7087   old_title = 0;
7088   maximizing_resize = NO;
7089 #endif
7091   win = [[EmacsWindow alloc]
7092             initWithContentRect: r
7093                       styleMask: (FRAME_UNDECORATED (f)
7094                                   ? FRAME_UNDECORATED_FLAGS
7095                                   : FRAME_DECORATED_FLAGS
7096 #ifdef NS_IMPL_COCOA
7097                                   | NSWindowStyleMaskResizable
7098                                   | NSWindowStyleMaskMiniaturizable
7099                                   | NSWindowStyleMaskClosable
7100 #endif
7101                                   )
7102                         backing: NSBackingStoreBuffered
7103                           defer: YES];
7105 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7106 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7107   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7108 #endif
7109     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
7110 #endif
7112   wr = [win frame];
7113   bwidth = f->border_width = wr.size.width - r.size.width;
7115   [win setAcceptsMouseMovedEvents: YES];
7116   [win setDelegate: self];
7117 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7118 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7119   if ([win respondsToSelector: @selector(useOptimizedDrawing:)])
7120 #endif
7121     [win useOptimizedDrawing: YES];
7122 #endif
7124   [[win contentView] addSubview: self];
7126   if (ns_drag_types)
7127     [self registerForDraggedTypes: ns_drag_types];
7129   tem = f->name;
7130   name = [NSString stringWithUTF8String:
7131                    NILP (tem) ? "Emacs" : SSDATA (tem)];
7132   [win setTitle: name];
7134   /* toolbar support */
7135   if (! FRAME_UNDECORATED (f))
7136     [self createToolbar: f];
7138 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
7139 #ifndef NSAppKitVersionNumber10_9
7140 #define NSAppKitVersionNumber10_9 1265
7141 #endif
7143   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_9
7144       && FRAME_NS_APPEARANCE (f) != ns_appearance_aqua)
7145     win.appearance = [NSAppearance
7146                           appearanceNamed: NSAppearanceNameVibrantDark];
7147 #endif
7149 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7150   if ([win respondsToSelector: @selector(titlebarAppearsTransparent)])
7151     win.titlebarAppearsTransparent = FRAME_NS_TRANSPARENT_TITLEBAR (f);
7152 #endif
7154   tem = f->icon_name;
7155   if (!NILP (tem))
7156     [win setMiniwindowTitle:
7157            [NSString stringWithUTF8String: SSDATA (tem)]];
7159   if (FRAME_PARENT_FRAME (f) != NULL)
7160     {
7161       NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
7162       [parent addChildWindow: win
7163                      ordered: NSWindowAbove];
7164     }
7166   if (FRAME_Z_GROUP (f) != z_group_none)
7167       win.level = NSNormalWindowLevel
7168         + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
7170   {
7171     NSScreen *screen = [win screen];
7173     if (screen != 0)
7174       {
7175         NSPoint pt = NSMakePoint
7176           (IN_BOUND (-SCREENMAX, f->left_pos
7177                      + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7178            IN_BOUND (-SCREENMAX,
7179                      NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7180                      SCREENMAX));
7182         [win setFrameTopLeftPoint: pt];
7184         NSTRACE_RECT ("new frame", [win frame]);
7185       }
7186   }
7188   [win makeFirstResponder: self];
7190   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7191                                  (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7192                                  emacsframe);
7193   [win setBackgroundColor: col];
7194   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7195     [win setOpaque: NO];
7197 #if !defined (NS_IMPL_COCOA) \
7198   || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7199 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7200   if ([self respondsToSelector: @selector(allocateGState)])
7201 #endif
7202     [self allocateGState];
7203 #endif
7204   [NSApp registerServicesMenuSendTypes: ns_send_types
7205                            returnTypes: [NSArray array]];
7207   /* macOS Sierra automatically enables tabbed windows.  We can't
7208      allow this to be enabled until it's available on a Free system.
7209      Currently it only happens by accident and is buggy anyway. */
7210 #if defined (NS_IMPL_COCOA) \
7211   && MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
7212 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
7213   if ([win respondsToSelector: @selector(setTabbingMode:)])
7214 #endif
7215     [win setTabbingMode: NSWindowTabbingModeDisallowed];
7216 #endif
7218   ns_window_num++;
7219   return self;
7223 - (void)windowDidMove: sender
7225   NSWindow *win = [self window];
7226   NSRect r = [win frame];
7227   NSArray *screens = [NSScreen screens];
7228   NSScreen *screen = [screens objectAtIndex: 0];
7230   NSTRACE ("[EmacsView windowDidMove:]");
7232   if (!emacsframe->output_data.ns)
7233     return;
7234   if (screen != nil)
7235     {
7236       emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7237       emacsframe->top_pos =
7238         NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7240       if (emacs_event)
7241         {
7242           emacs_event->kind = MOVE_FRAME_EVENT;
7243           EV_TRAILER ((id)nil);
7244         }
7245     }
7249 /* Called AFTER method below, but before our windowWillResize call there leads
7250    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
7251    location so set_window_size moves the frame. */
7252 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7254   NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7255             NSTRACE_FMT_RETURN "YES"),
7256            NSTRACE_ARG_RECT (newFrame));
7258   emacsframe->output_data.ns->zooming = 1;
7259   return YES;
7263 /* Override to do something slightly nonstandard, but nice.  First click on
7264    zoom button will zoom vertically.  Second will zoom completely.  Third
7265    returns to original. */
7266 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7267                         defaultFrame:(NSRect)defaultFrame
7269   // TODO: Rename to "currentFrame" and assign "result" properly in
7270   // all paths.
7271   NSRect result = [sender frame];
7273   NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7274             NSTRACE_FMT_RECT "]"),
7275            NSTRACE_ARG_RECT (defaultFrame));
7276   NSTRACE_FSTYPE ("fs_state", fs_state);
7277   NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7278   NSTRACE_FSTYPE ("next_maximized", next_maximized);
7279   NSTRACE_RECT   ("ns_userRect", ns_userRect);
7280   NSTRACE_RECT   ("[sender frame]", [sender frame]);
7282   if (fs_before_fs != -1) /* Entering fullscreen */
7283     {
7284       NSTRACE_MSG ("Entering fullscreen");
7285       result = defaultFrame;
7286     }
7287   else
7288     {
7289       // Save the window size and position (frame) before the resize.
7290       if (fs_state != FULLSCREEN_MAXIMIZED
7291           && fs_state != FULLSCREEN_WIDTH)
7292         {
7293           ns_userRect.size.width = result.size.width;
7294           ns_userRect.origin.x   = result.origin.x;
7295         }
7297       if (fs_state != FULLSCREEN_MAXIMIZED
7298           && fs_state != FULLSCREEN_HEIGHT)
7299         {
7300           ns_userRect.size.height = result.size.height;
7301           ns_userRect.origin.y    = result.origin.y;
7302         }
7304       NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7306       if (next_maximized == FULLSCREEN_HEIGHT
7307           || (next_maximized == -1
7308               && abs ((int)(defaultFrame.size.height - result.size.height))
7309               > FRAME_LINE_HEIGHT (emacsframe)))
7310         {
7311           /* first click */
7312           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7313           maximized_height = result.size.height = defaultFrame.size.height;
7314           maximized_width = -1;
7315           result.origin.y = defaultFrame.origin.y;
7316           if (ns_userRect.size.height != 0)
7317             {
7318               result.origin.x = ns_userRect.origin.x;
7319               result.size.width = ns_userRect.size.width;
7320             }
7321           [self setFSValue: FULLSCREEN_HEIGHT];
7322 #ifdef NS_IMPL_COCOA
7323           maximizing_resize = YES;
7324 #endif
7325         }
7326       else if (next_maximized == FULLSCREEN_WIDTH)
7327         {
7328           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7329           maximized_width = result.size.width = defaultFrame.size.width;
7330           maximized_height = -1;
7331           result.origin.x = defaultFrame.origin.x;
7332           if (ns_userRect.size.width != 0)
7333             {
7334               result.origin.y = ns_userRect.origin.y;
7335               result.size.height = ns_userRect.size.height;
7336             }
7337           [self setFSValue: FULLSCREEN_WIDTH];
7338         }
7339       else if (next_maximized == FULLSCREEN_MAXIMIZED
7340                || (next_maximized == -1
7341                    && abs ((int)(defaultFrame.size.width - result.size.width))
7342                    > FRAME_COLUMN_WIDTH (emacsframe)))
7343         {
7344           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7346           result = defaultFrame;  /* second click */
7347           maximized_width = result.size.width;
7348           maximized_height = result.size.height;
7349           [self setFSValue: FULLSCREEN_MAXIMIZED];
7350 #ifdef NS_IMPL_COCOA
7351           maximizing_resize = YES;
7352 #endif
7353         }
7354       else
7355         {
7356           /* restore */
7357           NSTRACE_MSG ("Restore");
7358           result = ns_userRect.size.height ? ns_userRect : result;
7359           NSTRACE_RECT ("restore (2)", result);
7360           ns_userRect = NSMakeRect (0, 0, 0, 0);
7361 #ifdef NS_IMPL_COCOA
7362           maximizing_resize = fs_state != FULLSCREEN_NONE;
7363 #endif
7364           [self setFSValue: FULLSCREEN_NONE];
7365           maximized_width = maximized_height = -1;
7366         }
7367     }
7369   if (fs_before_fs == -1) next_maximized = -1;
7371   NSTRACE_RECT   ("Final ns_userRect", ns_userRect);
7372   NSTRACE_MSG    ("Final maximized_width: %d", maximized_width);
7373   NSTRACE_MSG    ("Final maximized_height: %d", maximized_height);
7374   NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7376   [self windowWillResize: sender toSize: result.size];
7378   NSTRACE_RETURN_RECT (result);
7380   return result;
7384 - (void)windowDidDeminiaturize: sender
7386   NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7387   if (!emacsframe->output_data.ns)
7388     return;
7390   SET_FRAME_ICONIFIED (emacsframe, 0);
7391   SET_FRAME_VISIBLE (emacsframe, 1);
7392   windows_or_buffers_changed = 63;
7394   if (emacs_event)
7395     {
7396       emacs_event->kind = DEICONIFY_EVENT;
7397       EV_TRAILER ((id)nil);
7398     }
7402 - (void)windowDidExpose: sender
7404   NSTRACE ("[EmacsView windowDidExpose:]");
7405   if (!emacsframe->output_data.ns)
7406     return;
7408   SET_FRAME_VISIBLE (emacsframe, 1);
7409   SET_FRAME_GARBAGED (emacsframe);
7411   if (send_appdefined)
7412     ns_send_appdefined (-1);
7416 - (void)windowDidMiniaturize: sender
7418   NSTRACE ("[EmacsView windowDidMiniaturize:]");
7419   if (!emacsframe->output_data.ns)
7420     return;
7422   SET_FRAME_ICONIFIED (emacsframe, 1);
7423   SET_FRAME_VISIBLE (emacsframe, 0);
7425   if (emacs_event)
7426     {
7427       emacs_event->kind = ICONIFY_EVENT;
7428       EV_TRAILER ((id)nil);
7429     }
7432 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7433 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7434       willUseFullScreenPresentationOptions:
7435   (NSApplicationPresentationOptions)proposedOptions
7437   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7439 #endif
7441 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7443   NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7444   [self windowWillEnterFullScreen];
7446 - (void)windowWillEnterFullScreen /* provided for direct calls */
7448   NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7449   fs_before_fs = fs_state;
7452 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7454   NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7455   [self windowDidEnterFullScreen];
7458 - (void)windowDidEnterFullScreen /* provided for direct calls */
7460   NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7461   [self setFSValue: FULLSCREEN_BOTH];
7462   if (! [self fsIsNative])
7463     {
7464       [self windowDidBecomeKey];
7465       [nonfs_window orderOut:self];
7466     }
7467   else
7468     {
7469       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7470 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \
7471   && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
7472       unsigned val = (unsigned)[NSApp presentationOptions];
7474       // Mac OS X 10.7 bug fix, the menu won't appear without this.
7475       // val is non-zero on other macOS versions.
7476       if (val == 0)
7477         {
7478           NSApplicationPresentationOptions options
7479             = NSApplicationPresentationAutoHideDock
7480             | NSApplicationPresentationAutoHideMenuBar
7481             | NSApplicationPresentationFullScreen
7482             | NSApplicationPresentationAutoHideToolbar;
7484           [NSApp setPresentationOptions: options];
7485         }
7486 #endif
7487       [toolbar setVisible:tbar_visible];
7488     }
7491 - (void)windowWillExitFullScreen:(NSNotification *)notification
7493   NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7494   [self windowWillExitFullScreen];
7497 - (void)windowWillExitFullScreen /* provided for direct calls */
7499   NSTRACE ("[EmacsView windowWillExitFullScreen]");
7500   if (!FRAME_LIVE_P (emacsframe))
7501     {
7502       NSTRACE_MSG ("Ignored (frame dead)");
7503       return;
7504     }
7505   if (next_maximized != -1)
7506     fs_before_fs = next_maximized;
7509 - (void)windowDidExitFullScreen:(NSNotification *)notification
7511   NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7512   [self windowDidExitFullScreen];
7515 - (void)windowDidExitFullScreen /* provided for direct calls */
7517   NSTRACE ("[EmacsView windowDidExitFullScreen]");
7518   if (!FRAME_LIVE_P (emacsframe))
7519     {
7520       NSTRACE_MSG ("Ignored (frame dead)");
7521       return;
7522     }
7523   [self setFSValue: fs_before_fs];
7524   fs_before_fs = -1;
7525 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7526   [self updateCollectionBehavior];
7527 #endif
7528   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7529     {
7530       [toolbar setVisible:YES];
7531       update_frame_tool_bar (emacsframe);
7532       [self updateFrameSize:YES];
7533       [[self window] display];
7534     }
7535   else
7536     [toolbar setVisible:NO];
7538   if (next_maximized != -1)
7539     [[self window] performZoom:self];
7542 - (BOOL)fsIsNative
7544   return fs_is_native;
7547 - (BOOL)isFullscreen
7549   BOOL res;
7551   if (! fs_is_native)
7552     {
7553       res = (nonfs_window != nil);
7554     }
7555   else
7556     {
7557 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7558       res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7559 #else
7560       res = NO;
7561 #endif
7562     }
7564   NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7565            (int) res);
7567   return res;
7570 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7571 - (void)updateCollectionBehavior
7573   NSTRACE ("[EmacsView updateCollectionBehavior]");
7575   if (! [self isFullscreen])
7576     {
7577       NSWindow *win = [self window];
7578       NSWindowCollectionBehavior b = [win collectionBehavior];
7579       if (ns_use_native_fullscreen)
7580         b |= NSWindowCollectionBehaviorFullScreenPrimary;
7581       else
7582         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7584       [win setCollectionBehavior: b];
7585 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7586       if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7587 #endif
7588         fs_is_native = ns_use_native_fullscreen;
7589     }
7591 #endif
7593 - (void)toggleFullScreen: (id)sender
7595   NSWindow *w, *fw;
7596   BOOL onFirstScreen;
7597   struct frame *f;
7598   NSRect r, wr;
7599   NSColor *col;
7601   NSTRACE ("[EmacsView toggleFullScreen:]");
7603   if (fs_is_native)
7604     {
7605 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7606 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7607       if ([[self window] respondsToSelector: @selector(toggleFullScreen:)])
7608 #endif
7609         [[self window] toggleFullScreen:sender];
7610 #endif
7611       return;
7612     }
7614   w = [self window];
7615   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7616   f = emacsframe;
7617   wr = [w frame];
7618   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7619                                  (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7620                                  f);
7622   if (fs_state != FULLSCREEN_BOTH)
7623     {
7624       NSScreen *screen = [w screen];
7626 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
7627       /* Hide ghost menu bar on secondary monitor? */
7628       if (! onFirstScreen
7629 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
7630           && [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)]
7631 #endif
7632           )
7633         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7634 #endif
7635       /* Hide dock and menubar if we are on the primary screen.  */
7636       if (onFirstScreen)
7637         {
7638 #ifdef NS_IMPL_COCOA
7639           NSApplicationPresentationOptions options
7640             = NSApplicationPresentationAutoHideDock
7641             | NSApplicationPresentationAutoHideMenuBar;
7643           [NSApp setPresentationOptions: options];
7644 #else
7645           [NSMenu setMenuBarVisible:NO];
7646 #endif
7647         }
7649       fw = [[EmacsFSWindow alloc]
7650                        initWithContentRect:[w contentRectForFrameRect:wr]
7651                                  styleMask:NSWindowStyleMaskBorderless
7652                                    backing:NSBackingStoreBuffered
7653                                      defer:YES
7654                                     screen:screen];
7656       [fw setContentView:[w contentView]];
7657       [fw setTitle:[w title]];
7658       [fw setDelegate:self];
7659       [fw setAcceptsMouseMovedEvents: YES];
7660 #if !defined (NS_IMPL_COCOA) \
7661   || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7662 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7663       if ([fw respondsToSelector: @selector(useOptimizedDrawing:)])
7664 #endif
7665         [fw useOptimizedDrawing: YES];
7666 #endif
7667       [fw setBackgroundColor: col];
7668       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7669         [fw setOpaque: NO];
7671       f->border_width = 0;
7673       nonfs_window = w;
7675       [self windowWillEnterFullScreen];
7676       [fw makeKeyAndOrderFront:NSApp];
7677       [fw makeFirstResponder:self];
7678       [w orderOut:self];
7679       r = [fw frameRectForContentRect:[screen frame]];
7680       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7681       [self windowDidEnterFullScreen];
7682       [fw display];
7683     }
7684   else
7685     {
7686       fw = w;
7687       w = nonfs_window;
7688       nonfs_window = nil;
7690       if (onFirstScreen)
7691         {
7692 #ifdef NS_IMPL_COCOA
7693           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7694 #else
7695           [NSMenu setMenuBarVisible:YES];
7696 #endif
7697         }
7699       [w setContentView:[fw contentView]];
7700       [w setBackgroundColor: col];
7701       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7702         [w setOpaque: NO];
7704       f->border_width = bwidth;
7706       // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7708       [self windowWillExitFullScreen];
7709       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7710       [fw close];
7711       [w makeKeyAndOrderFront:NSApp];
7712       [self windowDidExitFullScreen];
7713       [self updateFrameSize:YES];
7714     }
7717 - (void)handleFS
7719   NSTRACE ("[EmacsView handleFS]");
7721   if (fs_state != emacsframe->want_fullscreen)
7722     {
7723       if (fs_state == FULLSCREEN_BOTH)
7724         {
7725           NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7726           [self toggleFullScreen:self];
7727         }
7729       switch (emacsframe->want_fullscreen)
7730         {
7731         case FULLSCREEN_BOTH:
7732           NSTRACE_MSG ("FULLSCREEN_BOTH");
7733           [self toggleFullScreen:self];
7734           break;
7735         case FULLSCREEN_WIDTH:
7736           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7737           next_maximized = FULLSCREEN_WIDTH;
7738           if (fs_state != FULLSCREEN_BOTH)
7739             [[self window] performZoom:self];
7740           break;
7741         case FULLSCREEN_HEIGHT:
7742           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7743           next_maximized = FULLSCREEN_HEIGHT;
7744           if (fs_state != FULLSCREEN_BOTH)
7745             [[self window] performZoom:self];
7746           break;
7747         case FULLSCREEN_MAXIMIZED:
7748           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7749           next_maximized = FULLSCREEN_MAXIMIZED;
7750           if (fs_state != FULLSCREEN_BOTH)
7751             [[self window] performZoom:self];
7752           break;
7753         case FULLSCREEN_NONE:
7754           NSTRACE_MSG ("FULLSCREEN_NONE");
7755           if (fs_state != FULLSCREEN_BOTH)
7756             {
7757               next_maximized = FULLSCREEN_NONE;
7758               [[self window] performZoom:self];
7759             }
7760           break;
7761         }
7763       emacsframe->want_fullscreen = FULLSCREEN_NONE;
7764     }
7768 - (void) setFSValue: (int)value
7770   NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7771            NSTRACE_ARG_FSTYPE(value));
7773   Lisp_Object lval = Qnil;
7774   switch (value)
7775     {
7776     case FULLSCREEN_BOTH:
7777       lval = Qfullboth;
7778       break;
7779     case FULLSCREEN_WIDTH:
7780       lval = Qfullwidth;
7781       break;
7782     case FULLSCREEN_HEIGHT:
7783       lval = Qfullheight;
7784       break;
7785     case FULLSCREEN_MAXIMIZED:
7786       lval = Qmaximized;
7787       break;
7788     }
7789   store_frame_param (emacsframe, Qfullscreen, lval);
7790   fs_state = value;
7793 - (void)mouseEntered: (NSEvent *)theEvent
7795   NSTRACE ("[EmacsView mouseEntered:]");
7796   if (emacsframe)
7797     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7798       = EV_TIMESTAMP (theEvent);
7802 - (void)mouseExited: (NSEvent *)theEvent
7804   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7806   NSTRACE ("[EmacsView mouseExited:]");
7808   if (!hlinfo)
7809     return;
7811   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7812     = EV_TIMESTAMP (theEvent);
7814   if (emacsframe == hlinfo->mouse_face_mouse_frame)
7815     {
7816       clear_mouse_face (hlinfo);
7817       hlinfo->mouse_face_mouse_frame = 0;
7818     }
7822 - (instancetype)menuDown: sender
7824   NSTRACE ("[EmacsView menuDown:]");
7825   if (context_menu_value == -1)
7826     context_menu_value = [sender tag];
7827   else
7828     {
7829       NSInteger tag = [sender tag];
7830       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7831                                     emacsframe->menu_bar_vector,
7832                                     (void *)tag);
7833     }
7835   ns_send_appdefined (-1);
7836   return self;
7840 - (EmacsToolbar *)toolbar
7842   return toolbar;
7846 /* this gets called on toolbar button click */
7847 - (instancetype)toolbarClicked: (id)item
7849   NSEvent *theEvent;
7850   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7852   NSTRACE ("[EmacsView toolbarClicked:]");
7854   if (!emacs_event)
7855     return self;
7857   /* send first event (for some reason two needed) */
7858   theEvent = [[self window] currentEvent];
7859   emacs_event->kind = TOOL_BAR_EVENT;
7860   XSETFRAME (emacs_event->arg, emacsframe);
7861   EV_TRAILER (theEvent);
7863   emacs_event->kind = TOOL_BAR_EVENT;
7864 /*   XSETINT (emacs_event->code, 0); */
7865   emacs_event->arg = AREF (emacsframe->tool_bar_items,
7866                            idx + TOOL_BAR_ITEM_KEY);
7867   emacs_event->modifiers = EV_MODIFIERS (theEvent);
7868   EV_TRAILER (theEvent);
7869   return self;
7873 - (instancetype)toggleToolbar: (id)sender
7875   NSTRACE ("[EmacsView toggleToolbar:]");
7877   if (!emacs_event)
7878     return self;
7880   emacs_event->kind = NS_NONKEY_EVENT;
7881   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7882   EV_TRAILER ((id)nil);
7883   return self;
7887 - (void)drawRect: (NSRect)rect
7889   int x = NSMinX (rect), y = NSMinY (rect);
7890   int width = NSWidth (rect), height = NSHeight (rect);
7892   NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7893            NSTRACE_ARG_RECT(rect));
7895   if (!emacsframe || !emacsframe->output_data.ns)
7896     return;
7898   ns_clear_frame_area (emacsframe, x, y, width, height);
7899   block_input ();
7900   expose_frame (emacsframe, x, y, width, height);
7901   unblock_input ();
7903   /*
7904     drawRect: may be called (at least in Mac OS X 10.5) for invisible
7905     views as well for some reason.  Thus, do not infer visibility
7906     here.
7908     emacsframe->async_visible = 1;
7909     emacsframe->async_iconified = 0;
7910   */
7914 /* NSDraggingDestination protocol methods.  Actually this is not really a
7915    protocol, but a category of Object.  O well...  */
7917 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7919   NSTRACE ("[EmacsView draggingEntered:]");
7920   return NSDragOperationGeneric;
7924 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7926   return YES;
7930 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7932   id pb;
7933   int x, y;
7934   NSString *type;
7935   NSEvent *theEvent = [[self window] currentEvent];
7936   NSPoint position;
7937   NSDragOperation op = [sender draggingSourceOperationMask];
7938   int modifiers = 0;
7940   NSTRACE ("[EmacsView performDragOperation:]");
7942   if (!emacs_event)
7943     return NO;
7945   position = [self convertPoint: [sender draggingLocation] fromView: nil];
7946   x = lrint (position.x);  y = lrint (position.y);
7948   pb = [sender draggingPasteboard];
7949   type = [pb availableTypeFromArray: ns_drag_types];
7951   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7952       // URL drags contain all operations (0xf), don't allow all to be set.
7953       (op & 0xf) != 0xf)
7954     {
7955       if (op & NSDragOperationLink)
7956         modifiers |= NSEventModifierFlagControl;
7957       if (op & NSDragOperationCopy)
7958         modifiers |= NSEventModifierFlagOption;
7959       if (op & NSDragOperationGeneric)
7960         modifiers |= NSEventModifierFlagCommand;
7961     }
7963   modifiers = EV_MODIFIERS2 (modifiers);
7964   if (type == 0)
7965     {
7966       return NO;
7967     }
7968   else if ([type isEqualToString: NSFilenamesPboardType])
7969     {
7970       NSArray *files;
7971       NSEnumerator *fenum;
7972       NSString *file;
7974       if (!(files = [pb propertyListForType: type]))
7975         return NO;
7977       fenum = [files objectEnumerator];
7978       while ( (file = [fenum nextObject]) )
7979         {
7980           emacs_event->kind = DRAG_N_DROP_EVENT;
7981           XSETINT (emacs_event->x, x);
7982           XSETINT (emacs_event->y, y);
7983           ns_input_file = append2 (ns_input_file,
7984                                    build_string ([file UTF8String]));
7985           emacs_event->modifiers = modifiers;
7986           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
7987           EV_TRAILER (theEvent);
7988         }
7989       return YES;
7990     }
7991   else if ([type isEqualToString: NSURLPboardType])
7992     {
7993       NSURL *url = [NSURL URLFromPasteboard: pb];
7994       if (url == nil) return NO;
7996       emacs_event->kind = DRAG_N_DROP_EVENT;
7997       XSETINT (emacs_event->x, x);
7998       XSETINT (emacs_event->y, y);
7999       emacs_event->modifiers = modifiers;
8000       emacs_event->arg =  list2 (Qurl,
8001                                  build_string ([[url absoluteString]
8002                                                  UTF8String]));
8003       EV_TRAILER (theEvent);
8005       if ([url isFileURL] != NO)
8006         {
8007           NSString *file = [url path];
8008           ns_input_file = append2 (ns_input_file,
8009                                    build_string ([file UTF8String]));
8010         }
8011       return YES;
8012     }
8013   else if ([type isEqualToString: NSStringPboardType]
8014            || [type isEqualToString: NSTabularTextPboardType])
8015     {
8016       NSString *data;
8018       if (! (data = [pb stringForType: type]))
8019         return NO;
8021       emacs_event->kind = DRAG_N_DROP_EVENT;
8022       XSETINT (emacs_event->x, x);
8023       XSETINT (emacs_event->y, y);
8024       emacs_event->modifiers = modifiers;
8025       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
8026       EV_TRAILER (theEvent);
8027       return YES;
8028     }
8029   else
8030     {
8031       fprintf (stderr, "Invalid data type in dragging pasteboard");
8032       return NO;
8033     }
8037 - (id) validRequestorForSendType: (NSString *)typeSent
8038                       returnType: (NSString *)typeReturned
8040   NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
8041   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
8042       && typeReturned == nil)
8043     {
8044       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
8045         return self;
8046     }
8048   return [super validRequestorForSendType: typeSent
8049                                returnType: typeReturned];
8053 /* The next two methods are part of NSServicesRequests informal protocol,
8054    supposedly called when a services menu item is chosen from this app.
8055    But this should not happen because we override the services menu with our
8056    own entries which call ns-perform-service.
8057    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
8058    So let's at least stub them out until further investigation can be done. */
8060 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
8062   /* we could call ns_string_from_pasteboard(pboard) here but then it should
8063      be written into the buffer in place of the existing selection..
8064      ordinary service calls go through functions defined in ns-win.el */
8065   return NO;
8068 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
8070   NSArray *typesDeclared;
8071   Lisp_Object val;
8073   NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
8075   /* We only support NSStringPboardType */
8076   if ([types containsObject:NSStringPboardType] == NO) {
8077     return NO;
8078   }
8080   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8081   if (CONSP (val) && SYMBOLP (XCAR (val)))
8082     {
8083       val = XCDR (val);
8084       if (CONSP (val) && NILP (XCDR (val)))
8085         val = XCAR (val);
8086     }
8087   if (! STRINGP (val))
8088     return NO;
8090   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
8091   [pb declareTypes:typesDeclared owner:nil];
8092   ns_string_to_pasteboard (pb, val);
8093   return YES;
8097 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
8098    (gives a miniaturized version of the window); currently we use the latter for
8099    frames whose active buffer doesn't correspond to any file
8100    (e.g., '*scratch*') */
8101 - (instancetype)setMiniwindowImage: (BOOL) setMini
8103   id image = [[self window] miniwindowImage];
8104   NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
8106   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
8107      about "AppleDockIconEnabled" notwithstanding, however the set message
8108      below has its effect nonetheless. */
8109   if (image != emacsframe->output_data.ns->miniimage)
8110     {
8111       if (image && [image isKindOfClass: [EmacsImage class]])
8112         [image release];
8113       [[self window] setMiniwindowImage:
8114                        setMini ? emacsframe->output_data.ns->miniimage : nil];
8115     }
8117   return self;
8121 - (void) setRows: (int) r andColumns: (int) c
8123   NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
8124   rows = r;
8125   cols = c;
8128 - (int) fullscreenState
8130   return fs_state;
8133 @end  /* EmacsView */
8137 /* ==========================================================================
8139     EmacsWindow implementation
8141    ========================================================================== */
8143 @implementation EmacsWindow
8145 #ifdef NS_IMPL_COCOA
8146 - (id)accessibilityAttributeValue:(NSString *)attribute
8148   Lisp_Object str = Qnil;
8149   struct frame *f = SELECTED_FRAME ();
8150   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
8152   NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
8154   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
8155     return NSAccessibilityTextFieldRole;
8157   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
8158       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
8159     {
8160       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8161     }
8162   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
8163     {
8164       if (! NILP (BVAR (curbuf, mark_active)))
8165           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8167       if (NILP (str))
8168         {
8169           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
8170           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
8171           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
8173           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
8174             str = make_uninit_multibyte_string (range, byte_range);
8175           else
8176             str = make_uninit_string (range);
8177           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
8178              Is this a problem?  */
8179           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
8180         }
8181     }
8184   if (! NILP (str))
8185     {
8186       if (CONSP (str) && SYMBOLP (XCAR (str)))
8187         {
8188           str = XCDR (str);
8189           if (CONSP (str) && NILP (XCDR (str)))
8190             str = XCAR (str);
8191         }
8192       if (STRINGP (str))
8193         {
8194           const char *utfStr = SSDATA (str);
8195           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8196           return nsStr;
8197         }
8198     }
8200   return [super accessibilityAttributeValue:attribute];
8202 #endif /* NS_IMPL_COCOA */
8204 /* Constrain size and placement of a frame.
8206    By returning the original "frameRect", the frame is not
8207    constrained. This can lead to unwanted situations where, for
8208    example, the menu bar covers the frame.
8210    The default implementation (accessed using "super") constrains the
8211    frame to the visible area of SCREEN, minus the menu bar (if
8212    present) and the Dock.  Note that default implementation also calls
8213    windowWillResize, with the frame it thinks should have.  (This can
8214    make the frame exit maximized mode.)
8216    Note that this should work in situations where multiple monitors
8217    are present.  Common configurations are side-by-side monitors and a
8218    monitor on top of another (e.g. when a laptop is placed under a
8219    large screen). */
8220 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8222   NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8223              NSTRACE_ARG_RECT (frameRect));
8225 #ifdef NS_IMPL_COCOA
8226 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
8227   // If separate spaces is on, it is like each screen is independent.  There is
8228   // no spanning of frames across screens.
8229   if (
8230 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
8231       [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)] &&
8232 #endif
8233       [NSScreen screensHaveSeparateSpaces])
8234     {
8235       NSTRACE_MSG ("Screens have separate spaces");
8236       frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8237       NSTRACE_RETURN_RECT (frameRect);
8238       return frameRect;
8239     }
8240   else
8241 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */
8243     // Check that the proposed frameRect is visible in at least one
8244     // screen.  If it is not, ask the system to reposition it (only
8245     // for non-child windows).
8247     if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe))
8248     {
8249       NSArray *screens = [NSScreen screens];
8250       NSUInteger nr_screens = [screens count];
8252       int i;
8253       BOOL frame_on_screen = NO;
8255       for (i = 0; i < nr_screens; ++i)
8256         {
8257           NSScreen *s = [screens objectAtIndex: i];
8258           NSRect scrRect = [s frame];
8260           if (NSIntersectsRect(frameRect, scrRect))
8261             {
8262               frame_on_screen = YES;
8263               break;
8264             }
8265         }
8267       if (!frame_on_screen)
8268         {
8269           NSTRACE_MSG ("Frame outside screens; constraining");
8270           frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8271           NSTRACE_RETURN_RECT (frameRect);
8272           return frameRect;
8273         }
8274     }
8275 #endif
8277   return constrain_frame_rect(frameRect,
8278                               [(EmacsView *)[self delegate] isFullscreen]);
8282 - (void)performZoom:(id)sender
8284   NSTRACE ("[EmacsWindow performZoom:]");
8286   return [super performZoom:sender];
8289 - (void)zoom:(id)sender
8291   NSTRACE ("[EmacsWindow zoom:]");
8293   ns_update_auto_hide_menu_bar();
8295   // Below are three zoom implementations.  In the final commit, the
8296   // idea is that the last should be included.
8298 #if 0
8299   // Native zoom done using the standard zoom animation.  Size of the
8300   // resulting frame reduced to accommodate the Dock and, if present,
8301   // the menu-bar.
8302   [super zoom:sender];
8304 #elif 0
8305   // Native zoom done using the standard zoom animation, plus an
8306   // explicit resize to cover the full screen, except the menu-bar and
8307   // dock, if present.
8308   [super zoom:sender];
8310   // After the native zoom, resize the resulting frame to fill the
8311   // entire screen, except the menu-bar.
8312   //
8313   // This works for all practical purposes.  (The only minor oddity is
8314   // when transiting from full-height frame to a maximized, the
8315   // animation reduces the height of the frame slightly (to the 4
8316   // pixels needed to accommodate the Doc) before it snaps back into
8317   // full height.  The user would need a very trained eye to spot
8318   // this.)
8319   NSScreen * screen = [self screen];
8320   if (screen != nil)
8321     {
8322       int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8324       NSTRACE_FSTYPE ("fullscreenState", fs_state);
8326       NSRect sr = [screen frame];
8327       struct EmacsMargins margins
8328         = ns_screen_margins_ignoring_hidden_dock(screen);
8330       NSRect wr = [self frame];
8331       NSTRACE_RECT ("Rect after zoom", wr);
8333       NSRect newWr = wr;
8335       if (fs_state == FULLSCREEN_MAXIMIZED
8336           || fs_state == FULLSCREEN_HEIGHT)
8337         {
8338           newWr.origin.y = sr.origin.y + margins.bottom;
8339           newWr.size.height = sr.size.height - margins.top - margins.bottom;
8340         }
8342       if (fs_state == FULLSCREEN_MAXIMIZED
8343           || fs_state == FULLSCREEN_WIDTH)
8344         {
8345           newWr.origin.x = sr.origin.x + margins.left;
8346           newWr.size.width = sr.size.width - margins.right - margins.left;
8347         }
8349       if (newWr.size.width     != wr.size.width
8350           || newWr.size.height != wr.size.height
8351           || newWr.origin.x    != wr.origin.x
8352           || newWr.origin.y    != wr.origin.y)
8353         {
8354           NSTRACE_MSG ("New frame different");
8355           [self setFrame: newWr display: NO];
8356         }
8357     }
8358 #else
8359   // Non-native zoom which is done instantaneously.  The resulting
8360   // frame covers the entire screen, except the menu-bar and dock, if
8361   // present.
8362   NSScreen * screen = [self screen];
8363   if (screen != nil)
8364     {
8365       NSRect sr = [screen frame];
8366       struct EmacsMargins margins
8367         = ns_screen_margins_ignoring_hidden_dock(screen);
8369       sr.size.height -= (margins.top + margins.bottom);
8370       sr.size.width  -= (margins.left + margins.right);
8371       sr.origin.x += margins.left;
8372       sr.origin.y += margins.bottom;
8374       sr = [[self delegate] windowWillUseStandardFrame:self
8375                                           defaultFrame:sr];
8376       [self setFrame: sr display: NO];
8377     }
8378 #endif
8381 - (void)setFrame:(NSRect)windowFrame
8382          display:(BOOL)displayViews
8384   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8385            NSTRACE_ARG_RECT (windowFrame), displayViews);
8387   [super setFrame:windowFrame display:displayViews];
8390 - (void)setFrame:(NSRect)windowFrame
8391          display:(BOOL)displayViews
8392          animate:(BOOL)performAnimation
8394   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8395            " display:%d performAnimation:%d]",
8396            NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8398   [super setFrame:windowFrame display:displayViews animate:performAnimation];
8401 - (void)setFrameTopLeftPoint:(NSPoint)point
8403   NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8404            NSTRACE_ARG_POINT (point));
8406   [super setFrameTopLeftPoint:point];
8409 - (BOOL)canBecomeKeyWindow
8411   return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8413 @end /* EmacsWindow */
8416 @implementation EmacsFSWindow
8418 - (BOOL)canBecomeKeyWindow
8420   return YES;
8423 - (BOOL)canBecomeMainWindow
8425   return YES;
8428 @end
8430 /* ==========================================================================
8432     EmacsScroller implementation
8434    ========================================================================== */
8437 @implementation EmacsScroller
8439 /* for repeat button push */
8440 #define SCROLL_BAR_FIRST_DELAY 0.5
8441 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8443 + (CGFloat) scrollerWidth
8445   /* TODO: if we want to allow variable widths, this is the place to do it,
8446            however neither GNUstep nor Cocoa support it very well */
8447   CGFloat r;
8448 #if defined (NS_IMPL_COCOA) \
8449   && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
8450 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8451   if ([NSScroller respondsToSelector:
8452                     @selector(scrollerWidthForControlSize:scrollerStyle:)])
8453 #endif
8454     r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8455                                   scrollerStyle: NSScrollerStyleLegacy];
8456 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8457   else
8458 #endif
8459 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
8460 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
8461   || defined (NS_IMPL_GNUSTEP)
8462     r = [NSScroller scrollerWidth];
8463 #endif
8464   return r;
8467 - (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin
8469   NSTRACE ("[EmacsScroller initFrame: window:]");
8471   if (r.size.width > r.size.height)
8472       horizontal = YES;
8473   else
8474       horizontal = NO;
8476   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8477   [self setContinuous: YES];
8478   [self setEnabled: YES];
8480   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8481      locked against the top and bottom edges, and right edge on macOS, where
8482      scrollers are on right. */
8483 #ifdef NS_IMPL_GNUSTEP
8484   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8485 #else
8486   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8487 #endif
8489   window = XWINDOW (nwin);
8490   condemned = NO;
8491   if (horizontal)
8492     pixel_length = NSWidth (r);
8493   else
8494     pixel_length = NSHeight (r);
8495   if (pixel_length == 0) pixel_length = 1;
8496   min_portion = 20 / pixel_length;
8498   frame = XFRAME (window->frame);
8499   if (FRAME_LIVE_P (frame))
8500     {
8501       int i;
8502       EmacsView *view = FRAME_NS_VIEW (frame);
8503       NSView *sview = [[view window] contentView];
8504       NSArray *subs = [sview subviews];
8506       /* disable optimization stopping redraw of other scrollbars */
8507       view->scrollbarsNeedingUpdate = 0;
8508       for (i =[subs count]-1; i >= 0; i--)
8509         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8510           view->scrollbarsNeedingUpdate++;
8511       [sview addSubview: self];
8512     }
8514 /*  [self setFrame: r]; */
8516   return self;
8520 - (void)setFrame: (NSRect)newRect
8522   NSTRACE ("[EmacsScroller setFrame:]");
8524 /*  block_input (); */
8525   if (horizontal)
8526     pixel_length = NSWidth (newRect);
8527   else
8528     pixel_length = NSHeight (newRect);
8529   if (pixel_length == 0) pixel_length = 1;
8530   min_portion = 20 / pixel_length;
8531   [super setFrame: newRect];
8532 /*  unblock_input (); */
8536 - (void)dealloc
8538   NSTRACE ("[EmacsScroller dealloc]");
8539   if (window)
8540     {
8541       if (horizontal)
8542         wset_horizontal_scroll_bar (window, Qnil);
8543       else
8544         wset_vertical_scroll_bar (window, Qnil);
8545     }
8546   window = 0;
8547   [super dealloc];
8551 - (instancetype)condemn
8553   NSTRACE ("[EmacsScroller condemn]");
8554   condemned =YES;
8555   return self;
8559 - (instancetype)reprieve
8561   NSTRACE ("[EmacsScroller reprieve]");
8562   condemned =NO;
8563   return self;
8567 -(bool)judge
8569   NSTRACE ("[EmacsScroller judge]");
8570   bool ret = condemned;
8571   if (condemned)
8572     {
8573       EmacsView *view;
8574       block_input ();
8575       /* ensure other scrollbar updates after deletion */
8576       view = (EmacsView *)FRAME_NS_VIEW (frame);
8577       if (view != nil)
8578         view->scrollbarsNeedingUpdate++;
8579       if (window)
8580         {
8581           if (horizontal)
8582             wset_horizontal_scroll_bar (window, Qnil);
8583           else
8584             wset_vertical_scroll_bar (window, Qnil);
8585         }
8586       window = 0;
8587       [self removeFromSuperview];
8588       [self release];
8589       unblock_input ();
8590     }
8591   return ret;
8595 - (void)resetCursorRects
8597   NSRect visible = [self visibleRect];
8598   NSTRACE ("[EmacsScroller resetCursorRects]");
8600   if (!NSIsEmptyRect (visible))
8601     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8602   [[NSCursor arrowCursor] setOnMouseEntered: YES];
8606 - (int) checkSamePosition: (int) position portion: (int) portion
8607                     whole: (int) whole
8609   return em_position ==position && em_portion ==portion && em_whole ==whole
8610     && portion != whole; /* needed for resize empty buf */
8614 - (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole
8616   NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8618   em_position = position;
8619   em_portion = portion;
8620   em_whole = whole;
8622   if (portion >= whole)
8623     {
8624 #ifdef NS_IMPL_COCOA
8625       [self setKnobProportion: 1.0];
8626       [self setDoubleValue: 1.0];
8627 #else
8628       [self setFloatValue: 0.0 knobProportion: 1.0];
8629 #endif
8630     }
8631   else
8632     {
8633       float pos;
8634       CGFloat por;
8635       portion = max ((float)whole*min_portion/pixel_length, portion);
8636       pos = (float)position / (whole - portion);
8637       por = (CGFloat)portion/whole;
8638 #ifdef NS_IMPL_COCOA
8639       [self setKnobProportion: por];
8640       [self setDoubleValue: pos];
8641 #else
8642       [self setFloatValue: pos knobProportion: por];
8643 #endif
8644     }
8646   return self;
8649 /* set up emacs_event */
8650 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8652   Lisp_Object win;
8654   NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8656   if (!emacs_event)
8657     return;
8659   emacs_event->part = last_hit_part;
8660   emacs_event->code = 0;
8661   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8662   XSETWINDOW (win, window);
8663   emacs_event->frame_or_window = win;
8664   emacs_event->timestamp = EV_TIMESTAMP (e);
8665   emacs_event->arg = Qnil;
8667   if (horizontal)
8668     {
8669       emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8670       XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8671       XSETINT (emacs_event->y, em_whole);
8672     }
8673   else
8674     {
8675       emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8676       XSETINT (emacs_event->x, loc);
8677       XSETINT (emacs_event->y, pixel_length-20);
8678     }
8680   if (q_event_ptr)
8681     {
8682       n_emacs_events_pending++;
8683       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8684     }
8685   else
8686     hold_event (emacs_event);
8687   EVENT_INIT (*emacs_event);
8688   ns_send_appdefined (-1);
8692 /* called manually thru timer to implement repeated button action w/hold-down */
8693 - (instancetype)repeatScroll: (NSTimer *)scrollEntry
8695   NSEvent *e = [[self window] currentEvent];
8696   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
8697   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8699   NSTRACE ("[EmacsScroller repeatScroll:]");
8701   /* clear timer if need be */
8702   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8703     {
8704         [scroll_repeat_entry invalidate];
8705         [scroll_repeat_entry release];
8706         scroll_repeat_entry = nil;
8708         if (inKnob)
8709           return self;
8711         scroll_repeat_entry
8712           = [[NSTimer scheduledTimerWithTimeInterval:
8713                         SCROLL_BAR_CONTINUOUS_DELAY
8714                                             target: self
8715                                           selector: @selector (repeatScroll:)
8716                                           userInfo: 0
8717                                            repeats: YES]
8718               retain];
8719     }
8721   [self sendScrollEventAtLoc: 0 fromEvent: e];
8722   return self;
8726 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
8727    mouseDragged events without going into a modal loop. */
8728 - (void)mouseDown: (NSEvent *)e
8730   NSRect sr, kr;
8731   /* hitPart is only updated AFTER event is passed on */
8732   NSScrollerPart part = [self testPart: [e locationInWindow]];
8733   CGFloat loc, kloc, pos UNINIT;
8734   int edge = 0;
8736   NSTRACE ("[EmacsScroller mouseDown:]");
8738   switch (part)
8739     {
8740     case NSScrollerDecrementPage:
8741       last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
8742     case NSScrollerIncrementPage:
8743       last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
8744     case NSScrollerDecrementLine:
8745       last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
8746     case NSScrollerIncrementLine:
8747       last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
8748     case NSScrollerKnob:
8749       last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
8750     case NSScrollerKnobSlot:  /* GNUstep-only */
8751       last_hit_part = scroll_bar_move_ratio; break;
8752     default:  /* NSScrollerNoPart? */
8753       fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
8754                (long) part);
8755       return;
8756     }
8758   if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
8759     {
8760       /* handle, or on GNUstep possibly slot */
8761       NSEvent *fake_event;
8762       int length;
8764       /* compute float loc in slot and mouse offset on knob */
8765       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8766                       toView: nil];
8767       if (horizontal)
8768         {
8769           length = NSWidth (sr);
8770           loc = ([e locationInWindow].x - NSMinX (sr));
8771         }
8772       else
8773         {
8774           length = NSHeight (sr);
8775           loc = length - ([e locationInWindow].y - NSMinY (sr));
8776         }
8778       if (loc <= 0.0)
8779         {
8780           loc = 0.0;
8781           edge = -1;
8782         }
8783       else if (loc >= length)
8784         {
8785           loc = length;
8786           edge = 1;
8787         }
8789       if (edge)
8790         kloc = 0.5 * edge;
8791       else
8792         {
8793           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8794                           toView: nil];
8795           if (horizontal)
8796             kloc = ([e locationInWindow].x - NSMinX (kr));
8797           else
8798             kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8799         }
8800       last_mouse_offset = kloc;
8802       if (part != NSScrollerKnob)
8803         /* this is a slot click on GNUstep: go straight there */
8804         pos = loc;
8806       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8807       fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
8808                                       location: [e locationInWindow]
8809                                  modifierFlags: [e modifierFlags]
8810                                      timestamp: [e timestamp]
8811                                   windowNumber: [e windowNumber]
8812                                        context: nil
8813                                    eventNumber: [e eventNumber]
8814                                     clickCount: [e clickCount]
8815                                       pressure: [e pressure]];
8816       [super mouseUp: fake_event];
8817     }
8818   else
8819     {
8820       pos = 0;      /* ignored */
8822       /* set a timer to repeat, as we can't let superclass do this modally */
8823       scroll_repeat_entry
8824         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8825                                             target: self
8826                                           selector: @selector (repeatScroll:)
8827                                           userInfo: 0
8828                                            repeats: YES]
8829             retain];
8830     }
8832   if (part != NSScrollerKnob)
8833     [self sendScrollEventAtLoc: pos fromEvent: e];
8837 /* Called as we manually track scroller drags, rather than superclass. */
8838 - (void)mouseDragged: (NSEvent *)e
8840     NSRect sr;
8841     double loc, pos;
8842     int length;
8844     NSTRACE ("[EmacsScroller mouseDragged:]");
8846       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8847                       toView: nil];
8849       if (horizontal)
8850         {
8851           length = NSWidth (sr);
8852           loc = ([e locationInWindow].x - NSMinX (sr));
8853         }
8854       else
8855         {
8856           length = NSHeight (sr);
8857           loc = length - ([e locationInWindow].y - NSMinY (sr));
8858         }
8860       if (loc <= 0.0)
8861         {
8862           loc = 0.0;
8863         }
8864       else if (loc >= length + last_mouse_offset)
8865         {
8866           loc = length + last_mouse_offset;
8867         }
8869       pos = (loc - last_mouse_offset);
8870       [self sendScrollEventAtLoc: pos fromEvent: e];
8874 - (void)mouseUp: (NSEvent *)e
8876   NSTRACE ("[EmacsScroller mouseUp:]");
8878   if (scroll_repeat_entry)
8879     {
8880       [scroll_repeat_entry invalidate];
8881       [scroll_repeat_entry release];
8882       scroll_repeat_entry = nil;
8883     }
8884   last_hit_part = scroll_bar_above_handle;
8888 /* treat scrollwheel events in the bar as though they were in the main window */
8889 - (void) scrollWheel: (NSEvent *)theEvent
8891   NSTRACE ("[EmacsScroller scrollWheel:]");
8893   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8894   [view mouseDown: theEvent];
8897 @end  /* EmacsScroller */
8900 #ifdef NS_IMPL_GNUSTEP
8901 /* Dummy class to get rid of startup warnings.  */
8902 @implementation EmacsDocument
8904 @end
8905 #endif
8908 /* ==========================================================================
8910    Font-related functions; these used to be in nsfaces.m
8912    ========================================================================== */
8915 Lisp_Object
8916 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8918   struct font *font = XFONT_OBJECT (font_object);
8919   EmacsView *view = FRAME_NS_VIEW (f);
8920   int font_ascent, font_descent;
8922   if (fontset < 0)
8923     fontset = fontset_from_font (font_object);
8924   FRAME_FONTSET (f) = fontset;
8926   if (FRAME_FONT (f) == font)
8927     /* This font is already set in frame F.  There's nothing more to
8928        do.  */
8929     return font_object;
8931   FRAME_FONT (f) = font;
8933   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8934   FRAME_COLUMN_WIDTH (f) = font->average_width;
8935   get_font_ascent_descent (font, &font_ascent, &font_descent);
8936   FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8938   /* Compute the scroll bar width in character columns.  */
8939   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8940     {
8941       int wid = FRAME_COLUMN_WIDTH (f);
8942       FRAME_CONFIG_SCROLL_BAR_COLS (f)
8943         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8944     }
8945   else
8946     {
8947       int wid = FRAME_COLUMN_WIDTH (f);
8948       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8949     }
8951   /* Compute the scroll bar height in character lines.  */
8952   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8953     {
8954       int height = FRAME_LINE_HEIGHT (f);
8955       FRAME_CONFIG_SCROLL_BAR_LINES (f)
8956         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8957     }
8958   else
8959     {
8960       int height = FRAME_LINE_HEIGHT (f);
8961       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8962     }
8964   /* Now make the frame display the given font.  */
8965   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8966     adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8967                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8968                        false, Qfont);
8970   return font_object;
8974 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8975 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8976          in 1.43. */
8978 const char *
8979 ns_xlfd_to_fontname (const char *xlfd)
8980 /* --------------------------------------------------------------------------
8981     Convert an X font name (XLFD) to an NS font name.
8982     Only family is used.
8983     The string returned is temporarily allocated.
8984    -------------------------------------------------------------------------- */
8986   char *name = xmalloc (180);
8987   int i, len;
8988   const char *ret;
8990   if (!strncmp (xlfd, "--", 2))
8991     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8992   else
8993     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8995   /* stopgap for malformed XLFD input */
8996   if (strlen (name) == 0)
8997     strcpy (name, "Monaco");
8999   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
9000      also uppercase after '-' or ' ' */
9001   name[0] = c_toupper (name[0]);
9002   for (len =strlen (name), i =0; i<len; i++)
9003     {
9004       if (name[i] == '$')
9005         {
9006           name[i] = '-';
9007           if (i+1<len)
9008             name[i+1] = c_toupper (name[i+1]);
9009         }
9010       else if (name[i] == '_')
9011         {
9012           name[i] = ' ';
9013           if (i+1<len)
9014             name[i+1] = c_toupper (name[i+1]);
9015         }
9016     }
9017 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
9018   ret = [[NSString stringWithUTF8String: name] UTF8String];
9019   xfree (name);
9020   return ret;
9024 void
9025 syms_of_nsterm (void)
9027   NSTRACE ("syms_of_nsterm");
9029   ns_antialias_threshold = 10.0;
9031   /* from 23+ we need to tell emacs what modifiers there are.. */
9032   DEFSYM (Qmodifier_value, "modifier-value");
9033   DEFSYM (Qalt, "alt");
9034   DEFSYM (Qhyper, "hyper");
9035   DEFSYM (Qmeta, "meta");
9036   DEFSYM (Qsuper, "super");
9037   DEFSYM (Qcontrol, "control");
9038   DEFSYM (QUTF8_STRING, "UTF8_STRING");
9040   DEFSYM (Qfile, "file");
9041   DEFSYM (Qurl, "url");
9043   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
9044   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
9045   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
9046   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
9047   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
9049   DEFVAR_LISP ("ns-input-file", ns_input_file,
9050               "The file specified in the last NS event.");
9051   ns_input_file =Qnil;
9053   DEFVAR_LISP ("ns-working-text", ns_working_text,
9054               "String for visualizing working composition sequence.");
9055   ns_working_text =Qnil;
9057   DEFVAR_LISP ("ns-input-font", ns_input_font,
9058               "The font specified in the last NS event.");
9059   ns_input_font =Qnil;
9061   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
9062               "The fontsize specified in the last NS event.");
9063   ns_input_fontsize =Qnil;
9065   DEFVAR_LISP ("ns-input-line", ns_input_line,
9066                "The line specified in the last NS event.");
9067   ns_input_line =Qnil;
9069   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
9070                "The service name specified in the last NS event.");
9071   ns_input_spi_name =Qnil;
9073   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
9074                "The service argument specified in the last NS event.");
9075   ns_input_spi_arg =Qnil;
9077   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
9078                "This variable describes the behavior of the alternate or option key.\n\
9079 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9080 that key.\n\
9081 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9082 at all, allowing it to be used at a lower level for accented character entry.");
9083   ns_alternate_modifier = Qmeta;
9085   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
9086                "This variable describes the behavior of the right alternate or option key.\n\
9087 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9088 that key.\n\
9089 Set to left means be the same key as `ns-alternate-modifier'.\n\
9090 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9091 at all, allowing it to be used at a lower level for accented character entry.");
9092   ns_right_alternate_modifier = Qleft;
9094   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
9095                "This variable describes the behavior of the command key.\n\
9096 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9097 that key.");
9098   ns_command_modifier = Qsuper;
9100   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
9101                "This variable describes the behavior of the right command key.\n\
9102 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9103 that key.\n\
9104 Set to left means be the same key as `ns-command-modifier'.\n\
9105 Set to none means that the command / option key is not interpreted by Emacs\n\
9106 at all, allowing it to be used at a lower level for accented character entry.");
9107   ns_right_command_modifier = Qleft;
9109   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
9110                "This variable describes the behavior of the control key.\n\
9111 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9112 that key.");
9113   ns_control_modifier = Qcontrol;
9115   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
9116                "This variable describes the behavior of the right control key.\n\
9117 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9118 that key.\n\
9119 Set to left means be the same key as `ns-control-modifier'.\n\
9120 Set to none means that the control / option key is not interpreted by Emacs\n\
9121 at all, allowing it to be used at a lower level for accented character entry.");
9122   ns_right_control_modifier = Qleft;
9124   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
9125                "This variable describes the behavior of the function key (on laptops).\n\
9126 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9127 that key.\n\
9128 Set to none means that the function key is not interpreted by Emacs at all,\n\
9129 allowing it to be used at a lower level for accented character entry.");
9130   ns_function_modifier = Qnone;
9132   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
9133                "Non-nil (the default) means to render text antialiased.");
9134   ns_antialias_text = Qt;
9136   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
9137                "Whether to confirm application quit using dialog.");
9138   ns_confirm_quit = Qnil;
9140   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
9141                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
9142 Only works on Mac OS X 10.6 or later.  */);
9143   ns_auto_hide_menu_bar = Qnil;
9145   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
9146      doc: /*Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
9147 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
9148 multiple monitors, but lacks tool bar.  This variable is ignored on
9149 Mac OS X < 10.7.  Default is t.  */);
9150   ns_use_native_fullscreen = YES;
9151   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
9153   DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
9154      doc: /*Non-nil means use animation on non-native fullscreen.
9155 For native fullscreen, this does nothing.
9156 Default is nil.  */);
9157   ns_use_fullscreen_animation = NO;
9159   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
9160      doc: /*Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
9161 Note that this does not apply to images.
9162 This variable is ignored on Mac OS X < 10.7 and GNUstep.  */);
9163   ns_use_srgb_colorspace = YES;
9165   /* TODO: move to common code */
9166   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
9167                doc: /* Which toolkit scroll bars Emacs uses, if any.
9168 A value of nil means Emacs doesn't use toolkit scroll bars.
9169 With the X Window system, the value is a symbol describing the
9170 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
9171 With MS Windows or Nextstep, the value is t.  */);
9172   Vx_toolkit_scroll_bars = Qt;
9174   DEFVAR_BOOL ("x-use-underline-position-properties",
9175                x_use_underline_position_properties,
9176      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
9177 A value of nil means ignore them.  If you encounter fonts with bogus
9178 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
9179 to 4.1, set this to nil. */);
9180   x_use_underline_position_properties = 0;
9182   DEFVAR_BOOL ("x-underline-at-descent-line",
9183                x_underline_at_descent_line,
9184      doc: /* Non-nil means to draw the underline at the same place as the descent line.
9185 A value of nil means to draw the underline according to the value of the
9186 variable `x-use-underline-position-properties', which is usually at the
9187 baseline level.  The default value is nil.  */);
9188   x_underline_at_descent_line = 0;
9190   /* Tell Emacs about this window system.  */
9191   Fprovide (Qns, Qnil);
9193   DEFSYM (Qcocoa, "cocoa");
9194   DEFSYM (Qgnustep, "gnustep");
9196 #ifdef NS_IMPL_COCOA
9197   Fprovide (Qcocoa, Qnil);
9198   syms_of_macfont ();
9199 #else
9200   Fprovide (Qgnustep, Qnil);
9201   syms_of_nsfont ();
9202 #endif