; Typo fixes, mostly repeated words
[emacs.git] / src / nsterm.m
blob0b43c04c0b75193a1737fc09f81ab77f282db08f
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 <https://www.gnu.org/licenses/>.  */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30    interpretation of even the system includes. */
31 #include <config.h>
33 #include <fcntl.h>
34 #include <math.h>
35 #include <pthread.h>
36 #include <sys/types.h>
37 #include <time.h>
38 #include <signal.h>
39 #include <unistd.h>
41 #include <c-ctype.h>
42 #include <c-strcase.h>
43 #include <ftoastr.h>
45 #include "lisp.h"
46 #include "blockinput.h"
47 #include "sysselect.h"
48 #include "nsterm.h"
49 #include "systime.h"
50 #include "character.h"
51 #include "fontset.h"
52 #include "composite.h"
53 #include "ccl.h"
55 #include "termhooks.h"
56 #include "termchar.h"
57 #include "menu.h"
58 #include "window.h"
59 #include "keyboard.h"
60 #include "buffer.h"
61 #include "font.h"
63 #ifdef NS_IMPL_GNUSTEP
64 #include "process.h"
65 #endif
67 #ifdef NS_IMPL_COCOA
68 #include "macfont.h"
69 #endif
71 static EmacsMenu *dockMenu;
72 #ifdef NS_IMPL_COCOA
73 static EmacsMenu *mainMenu;
74 #endif
76 /* ==========================================================================
78    NSTRACE, Trace support.
80    ========================================================================== */
82 #if NSTRACE_ENABLED
84 /* The following use "volatile" since they can be accessed from
85    parallel threads. */
86 volatile int nstrace_num = 0;
87 volatile int nstrace_depth = 0;
89 /* When 0, no trace is emitted.  This is used by NSTRACE_WHEN and
90    NSTRACE_UNLESS to silence functions called.
92    TODO: This should really be a thread-local variable, to avoid that
93    a function with disabled trace thread silence trace output in
94    another.  However, in practice this seldom is a problem. */
95 volatile int nstrace_enabled_global = 1;
97 /* Called when nstrace_enabled goes out of scope. */
98 void nstrace_leave(int * pointer_to_nstrace_enabled)
100   if (*pointer_to_nstrace_enabled)
101     {
102       --nstrace_depth;
103     }
107 /* Called when nstrace_saved_enabled_global goes out of scope. */
108 void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
110   nstrace_enabled_global = *pointer_to_saved_enabled_global;
114 char const * nstrace_fullscreen_type_name (int fs_type)
116   switch (fs_type)
117     {
118     case -1:                   return "-1";
119     case FULLSCREEN_NONE:      return "FULLSCREEN_NONE";
120     case FULLSCREEN_WIDTH:     return "FULLSCREEN_WIDTH";
121     case FULLSCREEN_HEIGHT:    return "FULLSCREEN_HEIGHT";
122     case FULLSCREEN_BOTH:      return "FULLSCREEN_BOTH";
123     case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
124     default:                   return "FULLSCREEN_?????";
125     }
127 #endif
130 /* ==========================================================================
132    NSColor, EmacsColor category.
134    ========================================================================== */
135 @implementation NSColor (EmacsColor)
136 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
137                          blue:(CGFloat)blue alpha:(CGFloat)alpha
139 #if defined (NS_IMPL_COCOA) \
140   && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
141   if (ns_use_srgb_colorspace
142 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
143       && [NSColor respondsToSelector:
144                     @selector(colorWithSRGBRed:green:blue:alpha:)]
145 #endif
146       )
147     return [NSColor colorWithSRGBRed: red
148                                green: green
149                                 blue: blue
150                                alpha: alpha];
151 #endif
152   return [NSColor colorWithCalibratedRed: red
153                                    green: green
154                                     blue: blue
155                                    alpha: alpha];
158 - (NSColor *)colorUsingDefaultColorSpace
160   /* FIXMES: We're checking for colorWithSRGBRed here so this will
161      only work in the same place as in the method above.  It should
162      really be a check whether we're on macOS 10.7 or above. */
163 #if defined (NS_IMPL_COCOA) \
164   && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
165   if (ns_use_srgb_colorspace
166 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
167       && [NSColor respondsToSelector:
168                     @selector(colorWithSRGBRed:green:blue:alpha:)]
169 #endif
170       )
171     return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
172 #endif
173   return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
176 @end
178 /* ==========================================================================
180     Local declarations
182    ========================================================================== */
184 /* Convert a symbol indexed with an NSxxx value to a value as defined
185    in keyboard.c (lispy_function_key). I hope this is a correct way
186    of doing things... */
187 static unsigned convert_ns_to_X_keysym[] =
189   NSHomeFunctionKey,            0x50,
190   NSLeftArrowFunctionKey,       0x51,
191   NSUpArrowFunctionKey,         0x52,
192   NSRightArrowFunctionKey,      0x53,
193   NSDownArrowFunctionKey,       0x54,
194   NSPageUpFunctionKey,          0x55,
195   NSPageDownFunctionKey,        0x56,
196   NSEndFunctionKey,             0x57,
197   NSBeginFunctionKey,           0x58,
198   NSSelectFunctionKey,          0x60,
199   NSPrintFunctionKey,           0x61,
200   NSClearLineFunctionKey,       0x0B,
201   NSExecuteFunctionKey,         0x62,
202   NSInsertFunctionKey,          0x63,
203   NSUndoFunctionKey,            0x65,
204   NSRedoFunctionKey,            0x66,
205   NSMenuFunctionKey,            0x67,
206   NSFindFunctionKey,            0x68,
207   NSHelpFunctionKey,            0x6A,
208   NSBreakFunctionKey,           0x6B,
210   NSF1FunctionKey,              0xBE,
211   NSF2FunctionKey,              0xBF,
212   NSF3FunctionKey,              0xC0,
213   NSF4FunctionKey,              0xC1,
214   NSF5FunctionKey,              0xC2,
215   NSF6FunctionKey,              0xC3,
216   NSF7FunctionKey,              0xC4,
217   NSF8FunctionKey,              0xC5,
218   NSF9FunctionKey,              0xC6,
219   NSF10FunctionKey,             0xC7,
220   NSF11FunctionKey,             0xC8,
221   NSF12FunctionKey,             0xC9,
222   NSF13FunctionKey,             0xCA,
223   NSF14FunctionKey,             0xCB,
224   NSF15FunctionKey,             0xCC,
225   NSF16FunctionKey,             0xCD,
226   NSF17FunctionKey,             0xCE,
227   NSF18FunctionKey,             0xCF,
228   NSF19FunctionKey,             0xD0,
229   NSF20FunctionKey,             0xD1,
230   NSF21FunctionKey,             0xD2,
231   NSF22FunctionKey,             0xD3,
232   NSF23FunctionKey,             0xD4,
233   NSF24FunctionKey,             0xD5,
235   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
236   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
237   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
239   NSTabCharacter,               0x09,
240   0x19,                         0x09,  /* left tab->regular since pass shift */
241   NSCarriageReturnCharacter,    0x0D,
242   NSNewlineCharacter,           0x0D,
243   NSEnterCharacter,             0x8D,
245   0x41|NSEventModifierFlagNumericPad,   0xAE,  /* KP_Decimal */
246   0x43|NSEventModifierFlagNumericPad,   0xAA,  /* KP_Multiply */
247   0x45|NSEventModifierFlagNumericPad,   0xAB,  /* KP_Add */
248   0x4B|NSEventModifierFlagNumericPad,   0xAF,  /* KP_Divide */
249   0x4E|NSEventModifierFlagNumericPad,   0xAD,  /* KP_Subtract */
250   0x51|NSEventModifierFlagNumericPad,   0xBD,  /* KP_Equal */
251   0x52|NSEventModifierFlagNumericPad,   0xB0,  /* KP_0 */
252   0x53|NSEventModifierFlagNumericPad,   0xB1,  /* KP_1 */
253   0x54|NSEventModifierFlagNumericPad,   0xB2,  /* KP_2 */
254   0x55|NSEventModifierFlagNumericPad,   0xB3,  /* KP_3 */
255   0x56|NSEventModifierFlagNumericPad,   0xB4,  /* KP_4 */
256   0x57|NSEventModifierFlagNumericPad,   0xB5,  /* KP_5 */
257   0x58|NSEventModifierFlagNumericPad,   0xB6,  /* KP_6 */
258   0x59|NSEventModifierFlagNumericPad,   0xB7,  /* KP_7 */
259   0x5B|NSEventModifierFlagNumericPad,   0xB8,  /* KP_8 */
260   0x5C|NSEventModifierFlagNumericPad,   0xB9,  /* KP_9 */
262   0x1B,                         0x1B   /* escape */
265 /* On macOS picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
266    the maximum font size to NOT antialias.  On GNUstep there is currently
267    no way to control this behavior. */
268 float ns_antialias_threshold;
270 NSArray *ns_send_types = 0, *ns_return_types = 0;
271 static NSArray *ns_drag_types = 0;
272 NSString *ns_app_name = @"Emacs";  /* default changed later */
274 /* Display variables */
275 struct ns_display_info *x_display_list; /* Chain of existing displays */
276 long context_menu_value = 0;
278 /* display update */
279 static struct frame *ns_updating_frame;
280 static NSView *focus_view = NULL;
281 static int ns_window_num = 0;
282 #ifdef NS_IMPL_GNUSTEP
283 static NSRect uRect;            // TODO: This is dead, remove it?
284 #endif
285 static BOOL gsaved = NO;
286 static BOOL ns_fake_keydown = NO;
287 #ifdef NS_IMPL_COCOA
288 static BOOL ns_menu_bar_is_hidden = NO;
289 #endif
290 /*static int debug_lock = 0; */
292 /* event loop */
293 static BOOL send_appdefined = YES;
294 #define NO_APPDEFINED_DATA (-8)
295 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
296 static NSTimer *timed_entry = 0;
297 static NSTimer *scroll_repeat_entry = nil;
298 static fd_set select_readfds, select_writefds;
299 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
300 static int select_nfds = 0, select_valid = 0;
301 static struct timespec select_timeout = { 0, 0 };
302 static int selfds[2] = { -1, -1 };
303 static pthread_mutex_t select_mutex;
304 static NSAutoreleasePool *outerpool;
305 static struct input_event *emacs_event = NULL;
306 static struct input_event *q_event_ptr = NULL;
307 static int n_emacs_events_pending = 0;
308 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
309   *ns_pending_service_args;
310 static BOOL ns_do_open_file = NO;
311 static BOOL ns_last_use_native_fullscreen;
313 /* Non-zero means that a HELP_EVENT has been generated since Emacs
314    start.  */
316 static BOOL any_help_event_p = NO;
318 static struct {
319   struct input_event *q;
320   int nr, cap;
321 } hold_event_q = {
322   NULL, 0, 0
325 static NSString *represented_filename = nil;
326 static struct frame *represented_frame = 0;
328 #ifdef NS_IMPL_COCOA
330  * State for pending menu activation:
331  * MENU_NONE     Normal state
332  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
333  *               run lisp to update the menu.
334  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
335  *               will open.
336  */
337 #define MENU_NONE 0
338 #define MENU_PENDING 1
339 #define MENU_OPENING 2
340 static int menu_will_open_state = MENU_NONE;
342 /* Saved position for menu click.  */
343 static CGPoint menu_mouse_point;
344 #endif
346 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
347 #define NS_FUNCTION_KEY_MASK 0x800000
348 #define NSLeftControlKeyMask    (0x000001 | NSEventModifierFlagControl)
349 #define NSRightControlKeyMask   (0x002000 | NSEventModifierFlagControl)
350 #define NSLeftCommandKeyMask    (0x000008 | NSEventModifierFlagCommand)
351 #define NSRightCommandKeyMask   (0x000010 | NSEventModifierFlagCommand)
352 #define NSLeftAlternateKeyMask  (0x000020 | NSEventModifierFlagOption)
353 #define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption)
354 #define EV_MODIFIERS2(flags)                          \
355     (((flags & NSEventModifierFlagHelp) ?           \
356            hyper_modifier : 0)                        \
357      | (!EQ (ns_right_alternate_modifier, Qleft) && \
358         ((flags & NSRightAlternateKeyMask) \
359          == NSRightAlternateKeyMask) ? \
360            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
361      | ((flags & NSEventModifierFlagOption) ?                 \
362            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
363      | ((flags & NSEventModifierFlagShift) ?     \
364            shift_modifier : 0)                        \
365      | (!EQ (ns_right_control_modifier, Qleft) && \
366         ((flags & NSRightControlKeyMask) \
367          == NSRightControlKeyMask) ? \
368            parse_solitary_modifier (ns_right_control_modifier) : 0) \
369      | ((flags & NSEventModifierFlagControl) ?      \
370            parse_solitary_modifier (ns_control_modifier) : 0)     \
371      | ((flags & NS_FUNCTION_KEY_MASK) ?  \
372            parse_solitary_modifier (ns_function_modifier) : 0)    \
373      | (!EQ (ns_right_command_modifier, Qleft) && \
374         ((flags & NSRightCommandKeyMask) \
375          == NSRightCommandKeyMask) ? \
376            parse_solitary_modifier (ns_right_command_modifier) : 0) \
377      | ((flags & NSEventModifierFlagCommand) ?      \
378            parse_solitary_modifier (ns_command_modifier):0))
379 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
381 #define EV_UDMODIFIERS(e)                                      \
382     ((([e type] == NSEventTypeLeftMouseDown) ? down_modifier : 0)       \
383      | (([e type] == NSEventTypeRightMouseDown) ? down_modifier : 0)    \
384      | (([e type] == NSEventTypeOtherMouseDown) ? down_modifier : 0)    \
385      | (([e type] == NSEventTypeLeftMouseDragged) ? down_modifier : 0)  \
386      | (([e type] == NSEventTypeRightMouseDragged) ? down_modifier : 0) \
387      | (([e type] == NSEventTypeOtherMouseDragged) ? down_modifier : 0) \
388      | (([e type] == NSEventTypeLeftMouseUp)   ? up_modifier   : 0)     \
389      | (([e type] == NSEventTypeRightMouseUp)   ? up_modifier   : 0)    \
390      | (([e type] == NSEventTypeOtherMouseUp)   ? up_modifier   : 0))
392 #define EV_BUTTON(e)                                                         \
393     ((([e type] == NSEventTypeLeftMouseDown) || ([e type] == NSEventTypeLeftMouseUp)) ? 0 :    \
394       (([e type] == NSEventTypeRightMouseDown) || ([e type] == NSEventTypeRightMouseUp)) ? 2 : \
395      [e buttonNumber] - 1)
397 /* Convert the time field to a timestamp in milliseconds. */
398 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
400 /* This is a piece of code which is common to all the event handling
401    methods.  Maybe it should even be a function.  */
402 #define EV_TRAILER(e)                                                   \
403   {                                                                     \
404     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
405     EV_TRAILER2 (e);                                                    \
406   }
408 #define EV_TRAILER2(e)                                                  \
409   {                                                                     \
410       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
411       if (q_event_ptr)                                                  \
412         {                                                               \
413           Lisp_Object tem = Vinhibit_quit;                              \
414           Vinhibit_quit = Qt;                                           \
415           n_emacs_events_pending++;                                     \
416           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
417           Vinhibit_quit = tem;                                          \
418         }                                                               \
419       else                                                              \
420         hold_event (emacs_event);                                       \
421       EVENT_INIT (*emacs_event);                                        \
422       ns_send_appdefined (-1);                                          \
423     }
426 /* 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 >= 101000
2044   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2045   NSWindow *window = [view window];
2047   NSTRACE ("ns_set_appearance");
2049 #ifndef NSAppKitVersionNumber10_10
2050 #define NSAppKitVersionNumber10_10 1343
2051 #endif
2053   if (NSAppKitVersionNumber < NSAppKitVersionNumber10_10)
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 >= 101000 */
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 https://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 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6502 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6503       if ([theEvent respondsToSelector:@selector(hasPreciseScrollingDeltas)])
6504         {
6505 #endif
6506           /* If the input device is a touchpad or similar, use precise
6507            * scrolling deltas.  These are measured in pixels, so we
6508            * have to add them up until they exceed one line height,
6509            * then we can send a scroll wheel event.
6510            *
6511            * If the device only has coarse scrolling deltas, like a
6512            * real mousewheel, the deltas represent a ratio of whole
6513            * lines, so round up the number of lines.  This means we
6514            * always send one scroll event per click, but can still
6515            * scroll more than one line if the OS tells us to.
6516            */
6517           bool horizontal;
6518           int lines = 0;
6519           int scrollUp = NO;
6521           /* FIXME: At the top or bottom of the buffer we should
6522            * ignore momentum-phase events.  */
6523           if (! ns_use_mwheel_momentum
6524               && [theEvent momentumPhase] != NSEventPhaseNone)
6525             return;
6527           if ([theEvent hasPreciseScrollingDeltas])
6528             {
6529               static int totalDeltaX, totalDeltaY;
6530               int lineHeight;
6532               if (NUMBERP (ns_mwheel_line_height))
6533                 lineHeight = XINT (ns_mwheel_line_height);
6534               else
6535                 {
6536                   /* FIXME: Use actual line height instead of the default.  */
6537                   lineHeight = default_line_pixel_height
6538                     (XWINDOW (FRAME_SELECTED_WINDOW (emacsframe)));
6539                 }
6541               if ([theEvent phase] == NSEventPhaseBegan)
6542                 {
6543                   totalDeltaX = 0;
6544                   totalDeltaY = 0;
6545                 }
6547               totalDeltaX += [theEvent scrollingDeltaX];
6548               totalDeltaY += [theEvent scrollingDeltaY];
6550               /* Calculate the number of lines, if any, to scroll, and
6551                * reset the total delta for the direction we're NOT
6552                * scrolling so that small movements don't add up.  */
6553               if (abs (totalDeltaX) > abs (totalDeltaY)
6554                   && abs (totalDeltaX) > lineHeight)
6555                 {
6556                   horizontal = YES;
6557                   scrollUp = totalDeltaX > 0;
6559                   lines = abs (totalDeltaX / lineHeight);
6560                   totalDeltaX = totalDeltaX % lineHeight;
6561                   totalDeltaY = 0;
6562                 }
6563               else if (abs (totalDeltaY) >= abs (totalDeltaX)
6564                        && abs (totalDeltaY) > lineHeight)
6565                 {
6566                   horizontal = NO;
6567                   scrollUp = totalDeltaY > 0;
6569                   lines = abs (totalDeltaY / lineHeight);
6570                   totalDeltaY = totalDeltaY % lineHeight;
6571                   totalDeltaX = 0;
6572                 }
6574               if (lines > 1 && ! ns_use_mwheel_acceleration)
6575                 lines = 1;
6576             }
6577           else
6578             {
6579               CGFloat delta;
6581               if ([theEvent scrollingDeltaY] == 0)
6582                 {
6583                   horizontal = YES;
6584                   delta = [theEvent scrollingDeltaX];
6585                 }
6586               else
6587                 {
6588                   horizontal = NO;
6589                   delta = [theEvent scrollingDeltaY];
6590                 }
6592               lines = (ns_use_mwheel_acceleration)
6593                 ? ceil (fabs (delta)) : 1;
6595               scrollUp = delta > 0;
6596             }
6598           if (lines == 0)
6599             return;
6601           emacs_event->kind = horizontal ? HORIZ_WHEEL_EVENT : WHEEL_EVENT;
6602           emacs_event->arg = (make_number (lines));
6604           emacs_event->code = 0;
6605           emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6606             (scrollUp ? up_modifier : down_modifier);
6607 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6608         }
6609       else
6610 #endif
6611 #endif /* defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6612 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6613         {
6614           CGFloat delta = [theEvent deltaY];
6615           /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6616           if (delta == 0)
6617             {
6618               delta = [theEvent deltaX];
6619               if (delta == 0)
6620                 {
6621                   NSTRACE_MSG ("deltaIsZero");
6622                   return;
6623                 }
6624               emacs_event->kind = HORIZ_WHEEL_EVENT;
6625             }
6626           else
6627             emacs_event->kind = WHEEL_EVENT;
6629           emacs_event->code = 0;
6630           emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6631             ((delta > 0) ? up_modifier : down_modifier);
6632         }
6633 #endif
6634     }
6635   else
6636     {
6637       emacs_event->kind = MOUSE_CLICK_EVENT;
6638       emacs_event->code = EV_BUTTON (theEvent);
6639       emacs_event->modifiers = EV_MODIFIERS (theEvent)
6640                              | EV_UDMODIFIERS (theEvent);
6641     }
6643   XSETINT (emacs_event->x, lrint (p.x));
6644   XSETINT (emacs_event->y, lrint (p.y));
6645   EV_TRAILER (theEvent);
6646   return;
6650 - (void)rightMouseDown: (NSEvent *)theEvent
6652   NSTRACE ("[EmacsView rightMouseDown:]");
6653   [self mouseDown: theEvent];
6657 - (void)otherMouseDown: (NSEvent *)theEvent
6659   NSTRACE ("[EmacsView otherMouseDown:]");
6660   [self mouseDown: theEvent];
6664 - (void)mouseUp: (NSEvent *)theEvent
6666   NSTRACE ("[EmacsView mouseUp:]");
6667   [self mouseDown: theEvent];
6671 - (void)rightMouseUp: (NSEvent *)theEvent
6673   NSTRACE ("[EmacsView rightMouseUp:]");
6674   [self mouseDown: theEvent];
6678 - (void)otherMouseUp: (NSEvent *)theEvent
6680   NSTRACE ("[EmacsView otherMouseUp:]");
6681   [self mouseDown: theEvent];
6685 - (void) scrollWheel: (NSEvent *)theEvent
6687   NSTRACE ("[EmacsView scrollWheel:]");
6688   [self mouseDown: theEvent];
6692 /* Tell emacs the mouse has moved. */
6693 - (void)mouseMoved: (NSEvent *)e
6695   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6696   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6697   Lisp_Object frame;
6698   NSPoint pt;
6700   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6702   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6703   pt = [self convertPoint: [e locationInWindow] fromView: nil];
6704   dpyinfo->last_mouse_motion_x = pt.x;
6705   dpyinfo->last_mouse_motion_y = pt.y;
6707   /* update any mouse face */
6708   if (hlinfo->mouse_face_hidden)
6709     {
6710       hlinfo->mouse_face_hidden = 0;
6711       clear_mouse_face (hlinfo);
6712     }
6714   /* tooltip handling */
6715   previous_help_echo_string = help_echo_string;
6716   help_echo_string = Qnil;
6718   if (!NILP (Vmouse_autoselect_window))
6719     {
6720       NSTRACE_MSG ("mouse_autoselect_window");
6721       static Lisp_Object last_mouse_window;
6722       Lisp_Object window
6723         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6725       if (WINDOWP (window)
6726           && !EQ (window, last_mouse_window)
6727           && !EQ (window, selected_window)
6728           && (!NILP (focus_follows_mouse)
6729               || (EQ (XWINDOW (window)->frame,
6730                       XWINDOW (selected_window)->frame))))
6731         {
6732           NSTRACE_MSG ("in_window");
6733           emacs_event->kind = SELECT_WINDOW_EVENT;
6734           emacs_event->frame_or_window = window;
6735           EV_TRAILER2 (e);
6736         }
6737       /* Remember the last window where we saw the mouse.  */
6738       last_mouse_window = window;
6739     }
6741   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6742     help_echo_string = previous_help_echo_string;
6744   XSETFRAME (frame, emacsframe);
6745   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6746     {
6747       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6748          (note_mouse_highlight), which is called through the
6749          note_mouse_movement () call above */
6750       any_help_event_p = YES;
6751       gen_help_event (help_echo_string, frame, help_echo_window,
6752                       help_echo_object, help_echo_pos);
6753     }
6755   if (emacsframe->mouse_moved && send_appdefined)
6756     ns_send_appdefined (-1);
6760 - (void)mouseDragged: (NSEvent *)e
6762   NSTRACE ("[EmacsView mouseDragged:]");
6763   [self mouseMoved: e];
6767 - (void)rightMouseDragged: (NSEvent *)e
6769   NSTRACE ("[EmacsView rightMouseDragged:]");
6770   [self mouseMoved: e];
6774 - (void)otherMouseDragged: (NSEvent *)e
6776   NSTRACE ("[EmacsView otherMouseDragged:]");
6777   [self mouseMoved: e];
6781 - (BOOL)windowShouldClose: (id)sender
6783   NSEvent *e =[[self window] currentEvent];
6785   NSTRACE ("[EmacsView windowShouldClose:]");
6786   windowClosing = YES;
6787   if (!emacs_event)
6788     return NO;
6789   emacs_event->kind = DELETE_WINDOW_EVENT;
6790   emacs_event->modifiers = 0;
6791   emacs_event->code = 0;
6792   EV_TRAILER (e);
6793   /* Don't close this window, let this be done from lisp code.  */
6794   return NO;
6797 - (void) updateFrameSize: (BOOL) delay
6799   NSWindow *window = [self window];
6800   NSRect wr = [window frame];
6801   int extra = 0;
6802   int oldc = cols, oldr = rows;
6803   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6804   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6805   int neww, newh;
6807   NSTRACE ("[EmacsView updateFrameSize:]");
6808   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6809   NSTRACE_RECT ("Original frame", wr);
6810   NSTRACE_MSG  ("Original columns: %d", cols);
6811   NSTRACE_MSG  ("Original rows: %d", rows);
6813   if (! [self isFullscreen])
6814     {
6815 #ifdef NS_IMPL_GNUSTEP
6816       // GNUstep does not always update the tool bar height.  Force it.
6817       if (toolbar && [toolbar isVisible])
6818           update_frame_tool_bar (emacsframe);
6819 #endif
6821       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6822         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6823     }
6825   if (wait_for_tool_bar)
6826     {
6827       /* The toolbar height is always 0 in fullscreen and undecorated
6828          frames, so don't wait for it to become available. */
6829       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0
6830           && FRAME_UNDECORATED (emacsframe) == false
6831           && ! [self isFullscreen])
6832         {
6833           NSTRACE_MSG ("Waiting for toolbar");
6834           return;
6835         }
6836       wait_for_tool_bar = NO;
6837     }
6839   neww = (int)wr.size.width - emacsframe->border_width;
6840   newh = (int)wr.size.height - extra;
6842   NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6843   NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
6844   NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
6846   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6847   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6849   if (cols < MINWIDTH)
6850     cols = MINWIDTH;
6852   if (rows < MINHEIGHT)
6853     rows = MINHEIGHT;
6855   NSTRACE_MSG ("New columns: %d", cols);
6856   NSTRACE_MSG ("New rows: %d", rows);
6858   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6859     {
6860       NSView *view = FRAME_NS_VIEW (emacsframe);
6862       change_frame_size (emacsframe,
6863                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6864                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6865                          0, delay, 0, 1);
6866       SET_FRAME_GARBAGED (emacsframe);
6867       cancel_mouse_face (emacsframe);
6869       /* The next two lines appear to be setting the frame to the same
6870          size as it already is.  Why are they there? */
6871       // wr = NSMakeRect (0, 0, neww, newh);
6873       // [view setFrame: wr];
6875       // to do: consider using [NSNotificationCenter postNotificationName:].
6876       [self windowDidMove: // Update top/left.
6877               [NSNotification notificationWithName:NSWindowDidMoveNotification
6878                                             object:[view window]]];
6879     }
6880   else
6881     {
6882       NSTRACE_MSG ("No change");
6883     }
6886 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6887 /* normalize frame to gridded text size */
6889   int extra = 0;
6891   NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6892            NSTRACE_ARG_SIZE (frameSize));
6893   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6894   NSTRACE_FSTYPE ("fs_state", fs_state);
6896   if (!FRAME_LIVE_P (emacsframe))
6897     return frameSize;
6899   if (fs_state == FULLSCREEN_MAXIMIZED
6900       && (maximized_width != (int)frameSize.width
6901           || maximized_height != (int)frameSize.height))
6902     [self setFSValue: FULLSCREEN_NONE];
6903   else if (fs_state == FULLSCREEN_WIDTH
6904            && maximized_width != (int)frameSize.width)
6905     [self setFSValue: FULLSCREEN_NONE];
6906   else if (fs_state == FULLSCREEN_HEIGHT
6907            && maximized_height != (int)frameSize.height)
6908     [self setFSValue: FULLSCREEN_NONE];
6910   if (fs_state == FULLSCREEN_NONE)
6911     maximized_width = maximized_height = -1;
6913   if (! [self isFullscreen])
6914     {
6915       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6916         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6917     }
6919   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6920   if (cols < MINWIDTH)
6921     cols = MINWIDTH;
6923   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6924                                            frameSize.height - extra);
6925   if (rows < MINHEIGHT)
6926     rows = MINHEIGHT;
6927 #ifdef NS_IMPL_COCOA
6928   {
6929     /* this sets window title to have size in it; the wm does this under GS */
6930     NSRect r = [[self window] frame];
6931     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6932       {
6933         if (old_title != 0)
6934           {
6935             xfree (old_title);
6936             old_title = 0;
6937           }
6938       }
6939     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
6940              && [[self window] title] != NULL)
6941       {
6942         char *size_title;
6943         NSWindow *window = [self window];
6944         if (old_title == 0)
6945           {
6946             char *t = strdup ([[[self window] title] UTF8String]);
6947             char *pos = strstr (t, "  â€”  ");
6948             if (pos)
6949               *pos = '\0';
6950             old_title = t;
6951           }
6952         size_title = xmalloc (strlen (old_title) + 40);
6953         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
6954         [window setTitle: [NSString stringWithUTF8String: size_title]];
6955         [window display];
6956         xfree (size_title);
6957       }
6958   }
6959 #endif /* NS_IMPL_COCOA */
6961   NSTRACE_MSG ("cols: %d  rows: %d", cols, rows);
6963   /* Restrict the new size to the text gird.
6965      Don't restrict the width if the user only adjusted the height, and
6966      vice versa.  (Without this, the frame would shrink, and move
6967      slightly, if the window was resized by dragging one of its
6968      borders.) */
6969   if (!frame_resize_pixelwise)
6970     {
6971       NSRect r = [[self window] frame];
6973       if (r.size.width != frameSize.width)
6974         {
6975           frameSize.width =
6976             FRAME_TEXT_COLS_TO_PIXEL_WIDTH  (emacsframe, cols);
6977         }
6979       if (r.size.height != frameSize.height)
6980         {
6981           frameSize.height =
6982             FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6983         }
6984     }
6986   NSTRACE_RETURN_SIZE (frameSize);
6988   return frameSize;
6992 - (void)windowDidResize: (NSNotification *)notification
6994   NSTRACE ("[EmacsView windowDidResize:]");
6995   if (!FRAME_LIVE_P (emacsframe))
6996     {
6997       NSTRACE_MSG ("Ignored (frame dead)");
6998       return;
6999     }
7000   if (emacsframe->output_data.ns->in_animation)
7001     {
7002       NSTRACE_MSG ("Ignored (in animation)");
7003       return;
7004     }
7006   if (! [self fsIsNative])
7007     {
7008       NSWindow *theWindow = [notification object];
7009       /* We can get notification on the non-FS window when in
7010          fullscreen mode.  */
7011       if ([self window] != theWindow) return;
7012     }
7014   NSTRACE_RECT ("frame", [[notification object] frame]);
7016 #ifdef NS_IMPL_GNUSTEP
7017   NSWindow *theWindow = [notification object];
7019    /* In GNUstep, at least currently, it's possible to get a didResize
7020       without getting a willResize.. therefore we need to act as if we got
7021       the willResize now */
7022   NSSize sz = [theWindow frame].size;
7023   sz = [self windowWillResize: theWindow toSize: sz];
7024 #endif /* NS_IMPL_GNUSTEP */
7026   if (cols > 0 && rows > 0)
7027     {
7028       [self updateFrameSize: YES];
7029     }
7031   ns_send_appdefined (-1);
7034 #ifdef NS_IMPL_COCOA
7035 - (void)viewDidEndLiveResize
7037   NSTRACE ("[EmacsView viewDidEndLiveResize]");
7039   [super viewDidEndLiveResize];
7040   if (old_title != 0)
7041     {
7042       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
7043       xfree (old_title);
7044       old_title = 0;
7045     }
7046   maximizing_resize = NO;
7048 #endif /* NS_IMPL_COCOA */
7051 - (void)windowDidBecomeKey: (NSNotification *)notification
7052 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
7054   [self windowDidBecomeKey];
7058 - (void)windowDidBecomeKey      /* for direct calls */
7060   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7061   struct frame *old_focus = dpyinfo->x_focus_frame;
7063   NSTRACE ("[EmacsView windowDidBecomeKey]");
7065   if (emacsframe != old_focus)
7066     dpyinfo->x_focus_frame = emacsframe;
7068   ns_frame_rehighlight (emacsframe);
7070   if (emacs_event)
7071     {
7072       emacs_event->kind = FOCUS_IN_EVENT;
7073       EV_TRAILER ((id)nil);
7074     }
7078 - (void)windowDidResignKey: (NSNotification *)notification
7079 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
7081   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7082   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
7083   NSTRACE ("[EmacsView windowDidResignKey:]");
7085   if (is_focus_frame)
7086     dpyinfo->x_focus_frame = 0;
7088   emacsframe->mouse_moved = 0;
7089   ns_frame_rehighlight (emacsframe);
7091   /* FIXME: for some reason needed on second and subsequent clicks away
7092             from sole-frame Emacs to get hollow box to show */
7093   if (!windowClosing && [[self window] isVisible] == YES)
7094     {
7095       x_update_cursor (emacsframe, 1);
7096       x_set_frame_alpha (emacsframe);
7097     }
7099   if (any_help_event_p)
7100     {
7101       Lisp_Object frame;
7102       XSETFRAME (frame, emacsframe);
7103       help_echo_string = Qnil;
7104       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
7105     }
7107   if (emacs_event && is_focus_frame)
7108     {
7109       [self deleteWorkingText];
7110       emacs_event->kind = FOCUS_OUT_EVENT;
7111       EV_TRAILER ((id)nil);
7112     }
7116 - (void)windowWillMiniaturize: sender
7118   NSTRACE ("[EmacsView windowWillMiniaturize:]");
7122 - (void)setFrame:(NSRect)frameRect
7124   NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
7125            NSTRACE_ARG_RECT (frameRect));
7127   [super setFrame:(NSRect)frameRect];
7131 - (BOOL)isFlipped
7133   return YES;
7137 - (BOOL)isOpaque
7139   return NO;
7143 - (void)createToolbar: (struct frame *)f
7145   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
7146   NSWindow *window = [view window];
7148   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
7149                    [NSString stringWithFormat: @"Emacs Frame %d",
7150                              ns_window_num]];
7151   [toolbar setVisible: NO];
7152   [window setToolbar: toolbar];
7154   /* Don't set frame garbaged until tool bar is up to date?
7155      This avoids an extra clear and redraw (flicker) at frame creation.  */
7156   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
7157   else wait_for_tool_bar = NO;
7160 #ifdef NS_IMPL_COCOA
7161   {
7162     NSButton *toggleButton;
7163     toggleButton = [window standardWindowButton: NSWindowToolbarButton];
7164     [toggleButton setTarget: self];
7165     [toggleButton setAction: @selector (toggleToolbar: )];
7166   }
7167 #endif
7171 - (instancetype) initFrameFromEmacs: (struct frame *)f
7173   NSRect r, wr;
7174   Lisp_Object tem;
7175   NSWindow *win;
7176   NSColor *col;
7177   NSString *name;
7179   NSTRACE ("[EmacsView initFrameFromEmacs:]");
7180   NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
7182   windowClosing = NO;
7183   processingCompose = NO;
7184   scrollbarsNeedingUpdate = 0;
7185   fs_state = FULLSCREEN_NONE;
7186   fs_before_fs = next_maximized = -1;
7188   fs_is_native = NO;
7189 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7190 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7191   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7192 #endif
7193     fs_is_native = ns_use_native_fullscreen;
7194 #endif
7196   maximized_width = maximized_height = -1;
7197   nonfs_window = nil;
7199   ns_userRect = NSMakeRect (0, 0, 0, 0);
7200   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
7201                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
7202   [self initWithFrame: r];
7203   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
7205   FRAME_NS_VIEW (f) = self;
7206   emacsframe = f;
7207 #ifdef NS_IMPL_COCOA
7208   old_title = 0;
7209   maximizing_resize = NO;
7210 #endif
7212   win = [[EmacsWindow alloc]
7213             initWithContentRect: r
7214                       styleMask: ((FRAME_UNDECORATED (f)
7215                                    ? FRAME_UNDECORATED_FLAGS
7216                                    : FRAME_DECORATED_FLAGS)
7217 #ifdef NS_IMPL_COCOA
7218                                   | NSWindowStyleMaskResizable
7219                                   | NSWindowStyleMaskMiniaturizable
7220                                   | NSWindowStyleMaskClosable
7221 #endif
7222                                   )
7223                         backing: NSBackingStoreBuffered
7224                           defer: YES];
7226 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7227 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7228   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7229 #endif
7230     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
7231 #endif
7233   wr = [win frame];
7234   bwidth = f->border_width = wr.size.width - r.size.width;
7236   [win setAcceptsMouseMovedEvents: YES];
7237   [win setDelegate: self];
7238 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7239 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7240   if ([win respondsToSelector: @selector(useOptimizedDrawing:)])
7241 #endif
7242     [win useOptimizedDrawing: YES];
7243 #endif
7245   [[win contentView] addSubview: self];
7247   if (ns_drag_types)
7248     [self registerForDraggedTypes: ns_drag_types];
7250   tem = f->name;
7251   name = [NSString stringWithUTF8String:
7252                    NILP (tem) ? "Emacs" : SSDATA (tem)];
7253   [win setTitle: name];
7255   /* toolbar support */
7256   if (! FRAME_UNDECORATED (f))
7257     [self createToolbar: f];
7259 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7260 #ifndef NSAppKitVersionNumber10_10
7261 #define NSAppKitVersionNumber10_10 1343
7262 #endif
7264   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_10
7265       && FRAME_NS_APPEARANCE (f) != ns_appearance_aqua)
7266     win.appearance = [NSAppearance
7267                           appearanceNamed: NSAppearanceNameVibrantDark];
7268 #endif
7270 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7271   if ([win respondsToSelector: @selector(titlebarAppearsTransparent)])
7272     win.titlebarAppearsTransparent = FRAME_NS_TRANSPARENT_TITLEBAR (f);
7273 #endif
7275   tem = f->icon_name;
7276   if (!NILP (tem))
7277     [win setMiniwindowTitle:
7278            [NSString stringWithUTF8String: SSDATA (tem)]];
7280   if (FRAME_PARENT_FRAME (f) != NULL)
7281     {
7282       NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
7283       [parent addChildWindow: win
7284                      ordered: NSWindowAbove];
7285     }
7287   if (FRAME_Z_GROUP (f) != z_group_none)
7288       win.level = NSNormalWindowLevel
7289         + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
7291   {
7292     NSScreen *screen = [win screen];
7294     if (screen != 0)
7295       {
7296         NSPoint pt = NSMakePoint
7297           (IN_BOUND (-SCREENMAX, f->left_pos
7298                      + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7299            IN_BOUND (-SCREENMAX,
7300                      NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7301                      SCREENMAX));
7303         [win setFrameTopLeftPoint: pt];
7305         NSTRACE_RECT ("new frame", [win frame]);
7306       }
7307   }
7309   [win makeFirstResponder: self];
7311   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7312                                  (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7313                                  emacsframe);
7314   [win setBackgroundColor: col];
7315   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7316     [win setOpaque: NO];
7318 #if !defined (NS_IMPL_COCOA) \
7319   || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7320 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7321   if ([self respondsToSelector: @selector(allocateGState)])
7322 #endif
7323     [self allocateGState];
7324 #endif
7325   [NSApp registerServicesMenuSendTypes: ns_send_types
7326                            returnTypes: [NSArray array]];
7328   /* macOS Sierra automatically enables tabbed windows.  We can't
7329      allow this to be enabled until it's available on a Free system.
7330      Currently it only happens by accident and is buggy anyway. */
7331 #if defined (NS_IMPL_COCOA) \
7332   && MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
7333 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
7334   if ([win respondsToSelector: @selector(setTabbingMode:)])
7335 #endif
7336     [win setTabbingMode: NSWindowTabbingModeDisallowed];
7337 #endif
7339   ns_window_num++;
7340   return self;
7344 - (void)windowDidMove: sender
7346   NSWindow *win = [self window];
7347   NSRect r = [win frame];
7348   NSArray *screens = [NSScreen screens];
7349   NSScreen *screen = [screens objectAtIndex: 0];
7351   NSTRACE ("[EmacsView windowDidMove:]");
7353   if (!emacsframe->output_data.ns)
7354     return;
7355   if (screen != nil)
7356     {
7357       emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7358       emacsframe->top_pos =
7359         NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7361       if (emacs_event)
7362         {
7363           emacs_event->kind = MOVE_FRAME_EVENT;
7364           EV_TRAILER ((id)nil);
7365         }
7366     }
7370 /* Called AFTER method below, but before our windowWillResize call there leads
7371    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
7372    location so set_window_size moves the frame. */
7373 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7375   NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7376             NSTRACE_FMT_RETURN "YES"),
7377            NSTRACE_ARG_RECT (newFrame));
7379   emacsframe->output_data.ns->zooming = 1;
7380   return YES;
7384 /* Override to do something slightly nonstandard, but nice.  First click on
7385    zoom button will zoom vertically.  Second will zoom completely.  Third
7386    returns to original. */
7387 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7388                         defaultFrame:(NSRect)defaultFrame
7390   // TODO: Rename to "currentFrame" and assign "result" properly in
7391   // all paths.
7392   NSRect result = [sender frame];
7394   NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7395             NSTRACE_FMT_RECT "]"),
7396            NSTRACE_ARG_RECT (defaultFrame));
7397   NSTRACE_FSTYPE ("fs_state", fs_state);
7398   NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7399   NSTRACE_FSTYPE ("next_maximized", next_maximized);
7400   NSTRACE_RECT   ("ns_userRect", ns_userRect);
7401   NSTRACE_RECT   ("[sender frame]", [sender frame]);
7403   if (fs_before_fs != -1) /* Entering fullscreen */
7404     {
7405       NSTRACE_MSG ("Entering fullscreen");
7406       result = defaultFrame;
7407     }
7408   else
7409     {
7410       // Save the window size and position (frame) before the resize.
7411       if (fs_state != FULLSCREEN_MAXIMIZED
7412           && fs_state != FULLSCREEN_WIDTH)
7413         {
7414           ns_userRect.size.width = result.size.width;
7415           ns_userRect.origin.x   = result.origin.x;
7416         }
7418       if (fs_state != FULLSCREEN_MAXIMIZED
7419           && fs_state != FULLSCREEN_HEIGHT)
7420         {
7421           ns_userRect.size.height = result.size.height;
7422           ns_userRect.origin.y    = result.origin.y;
7423         }
7425       NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7427       if (next_maximized == FULLSCREEN_HEIGHT
7428           || (next_maximized == -1
7429               && abs ((int)(defaultFrame.size.height - result.size.height))
7430               > FRAME_LINE_HEIGHT (emacsframe)))
7431         {
7432           /* first click */
7433           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7434           maximized_height = result.size.height = defaultFrame.size.height;
7435           maximized_width = -1;
7436           result.origin.y = defaultFrame.origin.y;
7437           if (ns_userRect.size.height != 0)
7438             {
7439               result.origin.x = ns_userRect.origin.x;
7440               result.size.width = ns_userRect.size.width;
7441             }
7442           [self setFSValue: FULLSCREEN_HEIGHT];
7443 #ifdef NS_IMPL_COCOA
7444           maximizing_resize = YES;
7445 #endif
7446         }
7447       else if (next_maximized == FULLSCREEN_WIDTH)
7448         {
7449           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7450           maximized_width = result.size.width = defaultFrame.size.width;
7451           maximized_height = -1;
7452           result.origin.x = defaultFrame.origin.x;
7453           if (ns_userRect.size.width != 0)
7454             {
7455               result.origin.y = ns_userRect.origin.y;
7456               result.size.height = ns_userRect.size.height;
7457             }
7458           [self setFSValue: FULLSCREEN_WIDTH];
7459         }
7460       else if (next_maximized == FULLSCREEN_MAXIMIZED
7461                || (next_maximized == -1
7462                    && abs ((int)(defaultFrame.size.width - result.size.width))
7463                    > FRAME_COLUMN_WIDTH (emacsframe)))
7464         {
7465           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7467           result = defaultFrame;  /* second click */
7468           maximized_width = result.size.width;
7469           maximized_height = result.size.height;
7470           [self setFSValue: FULLSCREEN_MAXIMIZED];
7471 #ifdef NS_IMPL_COCOA
7472           maximizing_resize = YES;
7473 #endif
7474         }
7475       else
7476         {
7477           /* restore */
7478           NSTRACE_MSG ("Restore");
7479           result = ns_userRect.size.height ? ns_userRect : result;
7480           NSTRACE_RECT ("restore (2)", result);
7481           ns_userRect = NSMakeRect (0, 0, 0, 0);
7482 #ifdef NS_IMPL_COCOA
7483           maximizing_resize = fs_state != FULLSCREEN_NONE;
7484 #endif
7485           [self setFSValue: FULLSCREEN_NONE];
7486           maximized_width = maximized_height = -1;
7487         }
7488     }
7490   if (fs_before_fs == -1) next_maximized = -1;
7492   NSTRACE_RECT   ("Final ns_userRect", ns_userRect);
7493   NSTRACE_MSG    ("Final maximized_width: %d", maximized_width);
7494   NSTRACE_MSG    ("Final maximized_height: %d", maximized_height);
7495   NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7497   [self windowWillResize: sender toSize: result.size];
7499   NSTRACE_RETURN_RECT (result);
7501   return result;
7505 - (void)windowDidDeminiaturize: sender
7507   NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7508   if (!emacsframe->output_data.ns)
7509     return;
7511   SET_FRAME_ICONIFIED (emacsframe, 0);
7512   SET_FRAME_VISIBLE (emacsframe, 1);
7513   windows_or_buffers_changed = 63;
7515   if (emacs_event)
7516     {
7517       emacs_event->kind = DEICONIFY_EVENT;
7518       EV_TRAILER ((id)nil);
7519     }
7523 - (void)windowDidExpose: sender
7525   NSTRACE ("[EmacsView windowDidExpose:]");
7526   if (!emacsframe->output_data.ns)
7527     return;
7529   SET_FRAME_VISIBLE (emacsframe, 1);
7530   SET_FRAME_GARBAGED (emacsframe);
7532   if (send_appdefined)
7533     ns_send_appdefined (-1);
7537 - (void)windowDidMiniaturize: sender
7539   NSTRACE ("[EmacsView windowDidMiniaturize:]");
7540   if (!emacsframe->output_data.ns)
7541     return;
7543   SET_FRAME_ICONIFIED (emacsframe, 1);
7544   SET_FRAME_VISIBLE (emacsframe, 0);
7546   if (emacs_event)
7547     {
7548       emacs_event->kind = ICONIFY_EVENT;
7549       EV_TRAILER ((id)nil);
7550     }
7553 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7554 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7555       willUseFullScreenPresentationOptions:
7556   (NSApplicationPresentationOptions)proposedOptions
7558   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7560 #endif
7562 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7564   NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7565   [self windowWillEnterFullScreen];
7567 - (void)windowWillEnterFullScreen /* provided for direct calls */
7569   NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7570   fs_before_fs = fs_state;
7573 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7575   NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7576   [self windowDidEnterFullScreen];
7579 - (void)windowDidEnterFullScreen /* provided for direct calls */
7581   NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7582   [self setFSValue: FULLSCREEN_BOTH];
7583   if (! [self fsIsNative])
7584     {
7585       [self windowDidBecomeKey];
7586       [nonfs_window orderOut:self];
7587     }
7588   else
7589     {
7590       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7591 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \
7592   && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
7593       unsigned val = (unsigned)[NSApp presentationOptions];
7595       // Mac OS X 10.7 bug fix, the menu won't appear without this.
7596       // val is non-zero on other macOS versions.
7597       if (val == 0)
7598         {
7599           NSApplicationPresentationOptions options
7600             = NSApplicationPresentationAutoHideDock
7601             | NSApplicationPresentationAutoHideMenuBar
7602             | NSApplicationPresentationFullScreen
7603             | NSApplicationPresentationAutoHideToolbar;
7605           [NSApp setPresentationOptions: options];
7606         }
7607 #endif
7608       [toolbar setVisible:tbar_visible];
7609     }
7612 - (void)windowWillExitFullScreen:(NSNotification *)notification
7614   NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7615   [self windowWillExitFullScreen];
7618 - (void)windowWillExitFullScreen /* provided for direct calls */
7620   NSTRACE ("[EmacsView windowWillExitFullScreen]");
7621   if (!FRAME_LIVE_P (emacsframe))
7622     {
7623       NSTRACE_MSG ("Ignored (frame dead)");
7624       return;
7625     }
7626   if (next_maximized != -1)
7627     fs_before_fs = next_maximized;
7630 - (void)windowDidExitFullScreen:(NSNotification *)notification
7632   NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7633   [self windowDidExitFullScreen];
7636 - (void)windowDidExitFullScreen /* provided for direct calls */
7638   NSTRACE ("[EmacsView windowDidExitFullScreen]");
7639   if (!FRAME_LIVE_P (emacsframe))
7640     {
7641       NSTRACE_MSG ("Ignored (frame dead)");
7642       return;
7643     }
7644   [self setFSValue: fs_before_fs];
7645   fs_before_fs = -1;
7646 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7647   [self updateCollectionBehavior];
7648 #endif
7649   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7650     {
7651       [toolbar setVisible:YES];
7652       update_frame_tool_bar (emacsframe);
7653       [self updateFrameSize:YES];
7654       [[self window] display];
7655     }
7656   else
7657     [toolbar setVisible:NO];
7659   if (next_maximized != -1)
7660     [[self window] performZoom:self];
7663 - (BOOL)fsIsNative
7665   return fs_is_native;
7668 - (BOOL)isFullscreen
7670   BOOL res;
7672   if (! fs_is_native)
7673     {
7674       res = (nonfs_window != nil);
7675     }
7676   else
7677     {
7678 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7679       res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7680 #else
7681       res = NO;
7682 #endif
7683     }
7685   NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7686            (int) res);
7688   return res;
7691 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7692 - (void)updateCollectionBehavior
7694   NSTRACE ("[EmacsView updateCollectionBehavior]");
7696   if (! [self isFullscreen])
7697     {
7698       NSWindow *win = [self window];
7699       NSWindowCollectionBehavior b = [win collectionBehavior];
7700       if (ns_use_native_fullscreen)
7701         b |= NSWindowCollectionBehaviorFullScreenPrimary;
7702       else
7703         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7705       [win setCollectionBehavior: b];
7706 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7707       if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7708 #endif
7709         fs_is_native = ns_use_native_fullscreen;
7710     }
7712 #endif
7714 - (void)toggleFullScreen: (id)sender
7716   NSWindow *w, *fw;
7717   BOOL onFirstScreen;
7718   struct frame *f;
7719   NSRect r, wr;
7720   NSColor *col;
7722   NSTRACE ("[EmacsView toggleFullScreen:]");
7724   if (fs_is_native)
7725     {
7726 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7727 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7728       if ([[self window] respondsToSelector: @selector(toggleFullScreen:)])
7729 #endif
7730         [[self window] toggleFullScreen:sender];
7731 #endif
7732       return;
7733     }
7735   w = [self window];
7736   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7737   f = emacsframe;
7738   wr = [w frame];
7739   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7740                                  (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7741                                  f);
7743   if (fs_state != FULLSCREEN_BOTH)
7744     {
7745       NSScreen *screen = [w screen];
7747 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
7748       /* Hide ghost menu bar on secondary monitor? */
7749       if (! onFirstScreen
7750 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
7751           && [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)]
7752 #endif
7753           )
7754         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7755 #endif
7756       /* Hide dock and menubar if we are on the primary screen.  */
7757       if (onFirstScreen)
7758         {
7759 #ifdef NS_IMPL_COCOA
7760           NSApplicationPresentationOptions options
7761             = NSApplicationPresentationAutoHideDock
7762             | NSApplicationPresentationAutoHideMenuBar;
7764           [NSApp setPresentationOptions: options];
7765 #else
7766           [NSMenu setMenuBarVisible:NO];
7767 #endif
7768         }
7770       fw = [[EmacsFSWindow alloc]
7771                        initWithContentRect:[w contentRectForFrameRect:wr]
7772                                  styleMask:NSWindowStyleMaskBorderless
7773                                    backing:NSBackingStoreBuffered
7774                                      defer:YES
7775                                     screen:screen];
7777       [fw setContentView:[w contentView]];
7778       [fw setTitle:[w title]];
7779       [fw setDelegate:self];
7780       [fw setAcceptsMouseMovedEvents: YES];
7781 #if !defined (NS_IMPL_COCOA) \
7782   || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7783 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7784       if ([fw respondsToSelector: @selector(useOptimizedDrawing:)])
7785 #endif
7786         [fw useOptimizedDrawing: YES];
7787 #endif
7788       [fw setBackgroundColor: col];
7789       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7790         [fw setOpaque: NO];
7792       f->border_width = 0;
7794       nonfs_window = w;
7796       [self windowWillEnterFullScreen];
7797       [fw makeKeyAndOrderFront:NSApp];
7798       [fw makeFirstResponder:self];
7799       [w orderOut:self];
7800       r = [fw frameRectForContentRect:[screen frame]];
7801       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7802       [self windowDidEnterFullScreen];
7803       [fw display];
7804     }
7805   else
7806     {
7807       fw = w;
7808       w = nonfs_window;
7809       nonfs_window = nil;
7811       if (onFirstScreen)
7812         {
7813 #ifdef NS_IMPL_COCOA
7814           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7815 #else
7816           [NSMenu setMenuBarVisible:YES];
7817 #endif
7818         }
7820       [w setContentView:[fw contentView]];
7821       [w setBackgroundColor: col];
7822       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7823         [w setOpaque: NO];
7825       f->border_width = bwidth;
7827       // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7829       [self windowWillExitFullScreen];
7830       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7831       [fw close];
7832       [w makeKeyAndOrderFront:NSApp];
7833       [self windowDidExitFullScreen];
7834       [self updateFrameSize:YES];
7835     }
7838 - (void)handleFS
7840   NSTRACE ("[EmacsView handleFS]");
7842   if (fs_state != emacsframe->want_fullscreen)
7843     {
7844       if (fs_state == FULLSCREEN_BOTH)
7845         {
7846           NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7847           [self toggleFullScreen:self];
7848         }
7850       switch (emacsframe->want_fullscreen)
7851         {
7852         case FULLSCREEN_BOTH:
7853           NSTRACE_MSG ("FULLSCREEN_BOTH");
7854           [self toggleFullScreen:self];
7855           break;
7856         case FULLSCREEN_WIDTH:
7857           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7858           next_maximized = FULLSCREEN_WIDTH;
7859           if (fs_state != FULLSCREEN_BOTH)
7860             [[self window] performZoom:self];
7861           break;
7862         case FULLSCREEN_HEIGHT:
7863           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7864           next_maximized = FULLSCREEN_HEIGHT;
7865           if (fs_state != FULLSCREEN_BOTH)
7866             [[self window] performZoom:self];
7867           break;
7868         case FULLSCREEN_MAXIMIZED:
7869           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7870           next_maximized = FULLSCREEN_MAXIMIZED;
7871           if (fs_state != FULLSCREEN_BOTH)
7872             [[self window] performZoom:self];
7873           break;
7874         case FULLSCREEN_NONE:
7875           NSTRACE_MSG ("FULLSCREEN_NONE");
7876           if (fs_state != FULLSCREEN_BOTH)
7877             {
7878               next_maximized = FULLSCREEN_NONE;
7879               [[self window] performZoom:self];
7880             }
7881           break;
7882         }
7884       emacsframe->want_fullscreen = FULLSCREEN_NONE;
7885     }
7889 - (void) setFSValue: (int)value
7891   NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7892            NSTRACE_ARG_FSTYPE(value));
7894   Lisp_Object lval = Qnil;
7895   switch (value)
7896     {
7897     case FULLSCREEN_BOTH:
7898       lval = Qfullboth;
7899       break;
7900     case FULLSCREEN_WIDTH:
7901       lval = Qfullwidth;
7902       break;
7903     case FULLSCREEN_HEIGHT:
7904       lval = Qfullheight;
7905       break;
7906     case FULLSCREEN_MAXIMIZED:
7907       lval = Qmaximized;
7908       break;
7909     }
7910   store_frame_param (emacsframe, Qfullscreen, lval);
7911   fs_state = value;
7914 - (void)mouseEntered: (NSEvent *)theEvent
7916   NSTRACE ("[EmacsView mouseEntered:]");
7917   if (emacsframe)
7918     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7919       = EV_TIMESTAMP (theEvent);
7923 - (void)mouseExited: (NSEvent *)theEvent
7925   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7927   NSTRACE ("[EmacsView mouseExited:]");
7929   if (!hlinfo)
7930     return;
7932   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7933     = EV_TIMESTAMP (theEvent);
7935   if (emacsframe == hlinfo->mouse_face_mouse_frame)
7936     {
7937       clear_mouse_face (hlinfo);
7938       hlinfo->mouse_face_mouse_frame = 0;
7939     }
7943 - (instancetype)menuDown: sender
7945   NSTRACE ("[EmacsView menuDown:]");
7946   if (context_menu_value == -1)
7947     context_menu_value = [sender tag];
7948   else
7949     {
7950       NSInteger tag = [sender tag];
7951       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7952                                     emacsframe->menu_bar_vector,
7953                                     (void *)tag);
7954     }
7956   ns_send_appdefined (-1);
7957   return self;
7961 - (EmacsToolbar *)toolbar
7963   return toolbar;
7967 /* this gets called on toolbar button click */
7968 - (instancetype)toolbarClicked: (id)item
7970   NSEvent *theEvent;
7971   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7973   NSTRACE ("[EmacsView toolbarClicked:]");
7975   if (!emacs_event)
7976     return self;
7978   /* send first event (for some reason two needed) */
7979   theEvent = [[self window] currentEvent];
7980   emacs_event->kind = TOOL_BAR_EVENT;
7981   XSETFRAME (emacs_event->arg, emacsframe);
7982   EV_TRAILER (theEvent);
7984   emacs_event->kind = TOOL_BAR_EVENT;
7985 /*   XSETINT (emacs_event->code, 0); */
7986   emacs_event->arg = AREF (emacsframe->tool_bar_items,
7987                            idx + TOOL_BAR_ITEM_KEY);
7988   emacs_event->modifiers = EV_MODIFIERS (theEvent);
7989   EV_TRAILER (theEvent);
7990   return self;
7994 - (instancetype)toggleToolbar: (id)sender
7996   NSTRACE ("[EmacsView toggleToolbar:]");
7998   if (!emacs_event)
7999     return self;
8001   emacs_event->kind = NS_NONKEY_EVENT;
8002   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
8003   EV_TRAILER ((id)nil);
8004   return self;
8008 - (void)drawRect: (NSRect)rect
8010   int x = NSMinX (rect), y = NSMinY (rect);
8011   int width = NSWidth (rect), height = NSHeight (rect);
8013   NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
8014            NSTRACE_ARG_RECT(rect));
8016   if (!emacsframe || !emacsframe->output_data.ns)
8017     return;
8019   ns_clear_frame_area (emacsframe, x, y, width, height);
8020   block_input ();
8021   expose_frame (emacsframe, x, y, width, height);
8022   unblock_input ();
8024   /*
8025     drawRect: may be called (at least in Mac OS X 10.5) for invisible
8026     views as well for some reason.  Thus, do not infer visibility
8027     here.
8029     emacsframe->async_visible = 1;
8030     emacsframe->async_iconified = 0;
8031   */
8035 /* NSDraggingDestination protocol methods.  Actually this is not really a
8036    protocol, but a category of Object.  O well...  */
8038 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
8040   NSTRACE ("[EmacsView draggingEntered:]");
8041   return NSDragOperationGeneric;
8045 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
8047   return YES;
8051 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
8053   id pb;
8054   int x, y;
8055   NSString *type;
8056   NSEvent *theEvent = [[self window] currentEvent];
8057   NSPoint position;
8058   NSDragOperation op = [sender draggingSourceOperationMask];
8059   int modifiers = 0;
8061   NSTRACE ("[EmacsView performDragOperation:]");
8063   if (!emacs_event)
8064     return NO;
8066   position = [self convertPoint: [sender draggingLocation] fromView: nil];
8067   x = lrint (position.x);  y = lrint (position.y);
8069   pb = [sender draggingPasteboard];
8070   type = [pb availableTypeFromArray: ns_drag_types];
8072   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
8073       // URL drags contain all operations (0xf), don't allow all to be set.
8074       (op & 0xf) != 0xf)
8075     {
8076       if (op & NSDragOperationLink)
8077         modifiers |= NSEventModifierFlagControl;
8078       if (op & NSDragOperationCopy)
8079         modifiers |= NSEventModifierFlagOption;
8080       if (op & NSDragOperationGeneric)
8081         modifiers |= NSEventModifierFlagCommand;
8082     }
8084   modifiers = EV_MODIFIERS2 (modifiers);
8085   if (type == 0)
8086     {
8087       return NO;
8088     }
8089   else if ([type isEqualToString: NSFilenamesPboardType])
8090     {
8091       NSArray *files;
8092       NSEnumerator *fenum;
8093       NSString *file;
8095       if (!(files = [pb propertyListForType: type]))
8096         return NO;
8098       fenum = [files objectEnumerator];
8099       while ( (file = [fenum nextObject]) )
8100         {
8101           emacs_event->kind = DRAG_N_DROP_EVENT;
8102           XSETINT (emacs_event->x, x);
8103           XSETINT (emacs_event->y, y);
8104           ns_input_file = append2 (ns_input_file,
8105                                    build_string ([file UTF8String]));
8106           emacs_event->modifiers = modifiers;
8107           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
8108           EV_TRAILER (theEvent);
8109         }
8110       return YES;
8111     }
8112   else if ([type isEqualToString: NSURLPboardType])
8113     {
8114       NSURL *url = [NSURL URLFromPasteboard: pb];
8115       if (url == nil) return NO;
8117       emacs_event->kind = DRAG_N_DROP_EVENT;
8118       XSETINT (emacs_event->x, x);
8119       XSETINT (emacs_event->y, y);
8120       emacs_event->modifiers = modifiers;
8121       emacs_event->arg =  list2 (Qurl,
8122                                  build_string ([[url absoluteString]
8123                                                  UTF8String]));
8124       EV_TRAILER (theEvent);
8126       if ([url isFileURL] != NO)
8127         {
8128           NSString *file = [url path];
8129           ns_input_file = append2 (ns_input_file,
8130                                    build_string ([file UTF8String]));
8131         }
8132       return YES;
8133     }
8134   else if ([type isEqualToString: NSStringPboardType]
8135            || [type isEqualToString: NSTabularTextPboardType])
8136     {
8137       NSString *data;
8139       if (! (data = [pb stringForType: type]))
8140         return NO;
8142       emacs_event->kind = DRAG_N_DROP_EVENT;
8143       XSETINT (emacs_event->x, x);
8144       XSETINT (emacs_event->y, y);
8145       emacs_event->modifiers = modifiers;
8146       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
8147       EV_TRAILER (theEvent);
8148       return YES;
8149     }
8150   else
8151     {
8152       fprintf (stderr, "Invalid data type in dragging pasteboard");
8153       return NO;
8154     }
8158 - (id) validRequestorForSendType: (NSString *)typeSent
8159                       returnType: (NSString *)typeReturned
8161   NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
8162   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
8163       && typeReturned == nil)
8164     {
8165       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
8166         return self;
8167     }
8169   return [super validRequestorForSendType: typeSent
8170                                returnType: typeReturned];
8174 /* The next two methods are part of NSServicesRequests informal protocol,
8175    supposedly called when a services menu item is chosen from this app.
8176    But this should not happen because we override the services menu with our
8177    own entries which call ns-perform-service.
8178    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
8179    So let's at least stub them out until further investigation can be done. */
8181 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
8183   /* we could call ns_string_from_pasteboard(pboard) here but then it should
8184      be written into the buffer in place of the existing selection..
8185      ordinary service calls go through functions defined in ns-win.el */
8186   return NO;
8189 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
8191   NSArray *typesDeclared;
8192   Lisp_Object val;
8194   NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
8196   /* We only support NSStringPboardType */
8197   if ([types containsObject:NSStringPboardType] == NO) {
8198     return NO;
8199   }
8201   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8202   if (CONSP (val) && SYMBOLP (XCAR (val)))
8203     {
8204       val = XCDR (val);
8205       if (CONSP (val) && NILP (XCDR (val)))
8206         val = XCAR (val);
8207     }
8208   if (! STRINGP (val))
8209     return NO;
8211   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
8212   [pb declareTypes:typesDeclared owner:nil];
8213   ns_string_to_pasteboard (pb, val);
8214   return YES;
8218 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
8219    (gives a miniaturized version of the window); currently we use the latter for
8220    frames whose active buffer doesn't correspond to any file
8221    (e.g., '*scratch*') */
8222 - (instancetype)setMiniwindowImage: (BOOL) setMini
8224   id image = [[self window] miniwindowImage];
8225   NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
8227   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
8228      about "AppleDockIconEnabled" notwithstanding, however the set message
8229      below has its effect nonetheless. */
8230   if (image != emacsframe->output_data.ns->miniimage)
8231     {
8232       if (image && [image isKindOfClass: [EmacsImage class]])
8233         [image release];
8234       [[self window] setMiniwindowImage:
8235                        setMini ? emacsframe->output_data.ns->miniimage : nil];
8236     }
8238   return self;
8242 - (void) setRows: (int) r andColumns: (int) c
8244   NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
8245   rows = r;
8246   cols = c;
8249 - (int) fullscreenState
8251   return fs_state;
8254 @end  /* EmacsView */
8258 /* ==========================================================================
8260     EmacsWindow implementation
8262    ========================================================================== */
8264 @implementation EmacsWindow
8266 #ifdef NS_IMPL_COCOA
8267 - (id)accessibilityAttributeValue:(NSString *)attribute
8269   Lisp_Object str = Qnil;
8270   struct frame *f = SELECTED_FRAME ();
8271   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
8273   NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
8275   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
8276     return NSAccessibilityTextFieldRole;
8278   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
8279       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
8280     {
8281       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8282     }
8283   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
8284     {
8285       if (! NILP (BVAR (curbuf, mark_active)))
8286           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8288       if (NILP (str))
8289         {
8290           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
8291           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
8292           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
8294           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
8295             str = make_uninit_multibyte_string (range, byte_range);
8296           else
8297             str = make_uninit_string (range);
8298           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
8299              Is this a problem?  */
8300           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
8301         }
8302     }
8305   if (! NILP (str))
8306     {
8307       if (CONSP (str) && SYMBOLP (XCAR (str)))
8308         {
8309           str = XCDR (str);
8310           if (CONSP (str) && NILP (XCDR (str)))
8311             str = XCAR (str);
8312         }
8313       if (STRINGP (str))
8314         {
8315           const char *utfStr = SSDATA (str);
8316           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8317           return nsStr;
8318         }
8319     }
8321   return [super accessibilityAttributeValue:attribute];
8323 #endif /* NS_IMPL_COCOA */
8325 /* Constrain size and placement of a frame.
8327    By returning the original "frameRect", the frame is not
8328    constrained. This can lead to unwanted situations where, for
8329    example, the menu bar covers the frame.
8331    The default implementation (accessed using "super") constrains the
8332    frame to the visible area of SCREEN, minus the menu bar (if
8333    present) and the Dock.  Note that default implementation also calls
8334    windowWillResize, with the frame it thinks should have.  (This can
8335    make the frame exit maximized mode.)
8337    Note that this should work in situations where multiple monitors
8338    are present.  Common configurations are side-by-side monitors and a
8339    monitor on top of another (e.g. when a laptop is placed under a
8340    large screen). */
8341 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8343   NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8344              NSTRACE_ARG_RECT (frameRect));
8346 #ifdef NS_IMPL_COCOA
8347 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
8348   // If separate spaces is on, it is like each screen is independent.  There is
8349   // no spanning of frames across screens.
8350   if (
8351 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
8352       [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)] &&
8353 #endif
8354       [NSScreen screensHaveSeparateSpaces])
8355     {
8356       NSTRACE_MSG ("Screens have separate spaces");
8357       frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8358       NSTRACE_RETURN_RECT (frameRect);
8359       return frameRect;
8360     }
8361   else
8362 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */
8364     // Check that the proposed frameRect is visible in at least one
8365     // screen.  If it is not, ask the system to reposition it (only
8366     // for non-child windows).
8368     if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe))
8369     {
8370       NSArray *screens = [NSScreen screens];
8371       NSUInteger nr_screens = [screens count];
8373       int i;
8374       BOOL frame_on_screen = NO;
8376       for (i = 0; i < nr_screens; ++i)
8377         {
8378           NSScreen *s = [screens objectAtIndex: i];
8379           NSRect scrRect = [s frame];
8381           if (NSIntersectsRect(frameRect, scrRect))
8382             {
8383               frame_on_screen = YES;
8384               break;
8385             }
8386         }
8388       if (!frame_on_screen)
8389         {
8390           NSTRACE_MSG ("Frame outside screens; constraining");
8391           frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8392           NSTRACE_RETURN_RECT (frameRect);
8393           return frameRect;
8394         }
8395     }
8396 #endif
8398   return constrain_frame_rect(frameRect,
8399                               [(EmacsView *)[self delegate] isFullscreen]);
8403 - (void)performZoom:(id)sender
8405   NSTRACE ("[EmacsWindow performZoom:]");
8407   return [super performZoom:sender];
8410 - (void)zoom:(id)sender
8412   NSTRACE ("[EmacsWindow zoom:]");
8414   ns_update_auto_hide_menu_bar();
8416   // Below are three zoom implementations.  In the final commit, the
8417   // idea is that the last should be included.
8419 #if 0
8420   // Native zoom done using the standard zoom animation.  Size of the
8421   // resulting frame reduced to accommodate the Dock and, if present,
8422   // the menu-bar.
8423   [super zoom:sender];
8425 #elif 0
8426   // Native zoom done using the standard zoom animation, plus an
8427   // explicit resize to cover the full screen, except the menu-bar and
8428   // dock, if present.
8429   [super zoom:sender];
8431   // After the native zoom, resize the resulting frame to fill the
8432   // entire screen, except the menu-bar.
8433   //
8434   // This works for all practical purposes.  (The only minor oddity is
8435   // when transiting from full-height frame to a maximized, the
8436   // animation reduces the height of the frame slightly (to the 4
8437   // pixels needed to accommodate the Doc) before it snaps back into
8438   // full height.  The user would need a very trained eye to spot
8439   // this.)
8440   NSScreen * screen = [self screen];
8441   if (screen != nil)
8442     {
8443       int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8445       NSTRACE_FSTYPE ("fullscreenState", fs_state);
8447       NSRect sr = [screen frame];
8448       struct EmacsMargins margins
8449         = ns_screen_margins_ignoring_hidden_dock(screen);
8451       NSRect wr = [self frame];
8452       NSTRACE_RECT ("Rect after zoom", wr);
8454       NSRect newWr = wr;
8456       if (fs_state == FULLSCREEN_MAXIMIZED
8457           || fs_state == FULLSCREEN_HEIGHT)
8458         {
8459           newWr.origin.y = sr.origin.y + margins.bottom;
8460           newWr.size.height = sr.size.height - margins.top - margins.bottom;
8461         }
8463       if (fs_state == FULLSCREEN_MAXIMIZED
8464           || fs_state == FULLSCREEN_WIDTH)
8465         {
8466           newWr.origin.x = sr.origin.x + margins.left;
8467           newWr.size.width = sr.size.width - margins.right - margins.left;
8468         }
8470       if (newWr.size.width     != wr.size.width
8471           || newWr.size.height != wr.size.height
8472           || newWr.origin.x    != wr.origin.x
8473           || newWr.origin.y    != wr.origin.y)
8474         {
8475           NSTRACE_MSG ("New frame different");
8476           [self setFrame: newWr display: NO];
8477         }
8478     }
8479 #else
8480   // Non-native zoom which is done instantaneously.  The resulting
8481   // frame covers the entire screen, except the menu-bar and dock, if
8482   // present.
8483   NSScreen * screen = [self screen];
8484   if (screen != nil)
8485     {
8486       NSRect sr = [screen frame];
8487       struct EmacsMargins margins
8488         = ns_screen_margins_ignoring_hidden_dock(screen);
8490       sr.size.height -= (margins.top + margins.bottom);
8491       sr.size.width  -= (margins.left + margins.right);
8492       sr.origin.x += margins.left;
8493       sr.origin.y += margins.bottom;
8495       sr = [[self delegate] windowWillUseStandardFrame:self
8496                                           defaultFrame:sr];
8497       [self setFrame: sr display: NO];
8498     }
8499 #endif
8502 - (void)setFrame:(NSRect)windowFrame
8503          display:(BOOL)displayViews
8505   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8506            NSTRACE_ARG_RECT (windowFrame), displayViews);
8508   [super setFrame:windowFrame display:displayViews];
8511 - (void)setFrame:(NSRect)windowFrame
8512          display:(BOOL)displayViews
8513          animate:(BOOL)performAnimation
8515   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8516            " display:%d performAnimation:%d]",
8517            NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8519   [super setFrame:windowFrame display:displayViews animate:performAnimation];
8522 - (void)setFrameTopLeftPoint:(NSPoint)point
8524   NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8525            NSTRACE_ARG_POINT (point));
8527   [super setFrameTopLeftPoint:point];
8530 - (BOOL)canBecomeKeyWindow
8532   return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8534 @end /* EmacsWindow */
8537 @implementation EmacsFSWindow
8539 - (BOOL)canBecomeKeyWindow
8541   return YES;
8544 - (BOOL)canBecomeMainWindow
8546   return YES;
8549 @end
8551 /* ==========================================================================
8553     EmacsScroller implementation
8555    ========================================================================== */
8558 @implementation EmacsScroller
8560 /* for repeat button push */
8561 #define SCROLL_BAR_FIRST_DELAY 0.5
8562 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8564 + (CGFloat) scrollerWidth
8566   /* TODO: if we want to allow variable widths, this is the place to do it,
8567            however neither GNUstep nor Cocoa support it very well */
8568   CGFloat r;
8569 #if defined (NS_IMPL_COCOA) \
8570   && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
8571 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8572   if ([NSScroller respondsToSelector:
8573                     @selector(scrollerWidthForControlSize:scrollerStyle:)])
8574 #endif
8575     r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8576                                   scrollerStyle: NSScrollerStyleLegacy];
8577 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8578   else
8579 #endif
8580 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
8581 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
8582   || defined (NS_IMPL_GNUSTEP)
8583     r = [NSScroller scrollerWidth];
8584 #endif
8585   return r;
8588 - (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin
8590   NSTRACE ("[EmacsScroller initFrame: window:]");
8592   if (r.size.width > r.size.height)
8593       horizontal = YES;
8594   else
8595       horizontal = NO;
8597   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8598   [self setContinuous: YES];
8599   [self setEnabled: YES];
8601   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8602      locked against the top and bottom edges, and right edge on macOS, where
8603      scrollers are on right. */
8604 #ifdef NS_IMPL_GNUSTEP
8605   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8606 #else
8607   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8608 #endif
8610   window = XWINDOW (nwin);
8611   condemned = NO;
8612   if (horizontal)
8613     pixel_length = NSWidth (r);
8614   else
8615     pixel_length = NSHeight (r);
8616   if (pixel_length == 0) pixel_length = 1;
8617   min_portion = 20 / pixel_length;
8619   frame = XFRAME (window->frame);
8620   if (FRAME_LIVE_P (frame))
8621     {
8622       int i;
8623       EmacsView *view = FRAME_NS_VIEW (frame);
8624       NSView *sview = [[view window] contentView];
8625       NSArray *subs = [sview subviews];
8627       /* disable optimization stopping redraw of other scrollbars */
8628       view->scrollbarsNeedingUpdate = 0;
8629       for (i =[subs count]-1; i >= 0; i--)
8630         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8631           view->scrollbarsNeedingUpdate++;
8632       [sview addSubview: self];
8633     }
8635 /*  [self setFrame: r]; */
8637   return self;
8641 - (void)setFrame: (NSRect)newRect
8643   NSTRACE ("[EmacsScroller setFrame:]");
8645 /*  block_input (); */
8646   if (horizontal)
8647     pixel_length = NSWidth (newRect);
8648   else
8649     pixel_length = NSHeight (newRect);
8650   if (pixel_length == 0) pixel_length = 1;
8651   min_portion = 20 / pixel_length;
8652   [super setFrame: newRect];
8653 /*  unblock_input (); */
8657 - (void)dealloc
8659   NSTRACE ("[EmacsScroller dealloc]");
8660   if (window)
8661     {
8662       if (horizontal)
8663         wset_horizontal_scroll_bar (window, Qnil);
8664       else
8665         wset_vertical_scroll_bar (window, Qnil);
8666     }
8667   window = 0;
8668   [super dealloc];
8672 - (instancetype)condemn
8674   NSTRACE ("[EmacsScroller condemn]");
8675   condemned =YES;
8676   return self;
8680 - (instancetype)reprieve
8682   NSTRACE ("[EmacsScroller reprieve]");
8683   condemned =NO;
8684   return self;
8688 -(bool)judge
8690   NSTRACE ("[EmacsScroller judge]");
8691   bool ret = condemned;
8692   if (condemned)
8693     {
8694       EmacsView *view;
8695       block_input ();
8696       /* ensure other scrollbar updates after deletion */
8697       view = (EmacsView *)FRAME_NS_VIEW (frame);
8698       if (view != nil)
8699         view->scrollbarsNeedingUpdate++;
8700       if (window)
8701         {
8702           if (horizontal)
8703             wset_horizontal_scroll_bar (window, Qnil);
8704           else
8705             wset_vertical_scroll_bar (window, Qnil);
8706         }
8707       window = 0;
8708       [self removeFromSuperview];
8709       [self release];
8710       unblock_input ();
8711     }
8712   return ret;
8716 - (void)resetCursorRects
8718   NSRect visible = [self visibleRect];
8719   NSTRACE ("[EmacsScroller resetCursorRects]");
8721   if (!NSIsEmptyRect (visible))
8722     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8723   [[NSCursor arrowCursor] setOnMouseEntered: YES];
8727 - (int) checkSamePosition: (int) position portion: (int) portion
8728                     whole: (int) whole
8730   return em_position ==position && em_portion ==portion && em_whole ==whole
8731     && portion != whole; /* needed for resize empty buf */
8735 - (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole
8737   NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8739   em_position = position;
8740   em_portion = portion;
8741   em_whole = whole;
8743   if (portion >= whole)
8744     {
8745 #ifdef NS_IMPL_COCOA
8746       [self setKnobProportion: 1.0];
8747       [self setDoubleValue: 1.0];
8748 #else
8749       [self setFloatValue: 0.0 knobProportion: 1.0];
8750 #endif
8751     }
8752   else
8753     {
8754       float pos;
8755       CGFloat por;
8756       portion = max ((float)whole*min_portion/pixel_length, portion);
8757       pos = (float)position / (whole - portion);
8758       por = (CGFloat)portion/whole;
8759 #ifdef NS_IMPL_COCOA
8760       [self setKnobProportion: por];
8761       [self setDoubleValue: pos];
8762 #else
8763       [self setFloatValue: pos knobProportion: por];
8764 #endif
8765     }
8767   return self;
8770 /* set up emacs_event */
8771 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8773   Lisp_Object win;
8775   NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8777   if (!emacs_event)
8778     return;
8780   emacs_event->part = last_hit_part;
8781   emacs_event->code = 0;
8782   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8783   XSETWINDOW (win, window);
8784   emacs_event->frame_or_window = win;
8785   emacs_event->timestamp = EV_TIMESTAMP (e);
8786   emacs_event->arg = Qnil;
8788   if (horizontal)
8789     {
8790       emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8791       XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8792       XSETINT (emacs_event->y, em_whole);
8793     }
8794   else
8795     {
8796       emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8797       XSETINT (emacs_event->x, loc);
8798       XSETINT (emacs_event->y, pixel_length-20);
8799     }
8801   if (q_event_ptr)
8802     {
8803       n_emacs_events_pending++;
8804       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8805     }
8806   else
8807     hold_event (emacs_event);
8808   EVENT_INIT (*emacs_event);
8809   ns_send_appdefined (-1);
8813 /* called manually thru timer to implement repeated button action w/hold-down */
8814 - (instancetype)repeatScroll: (NSTimer *)scrollEntry
8816   NSEvent *e = [[self window] currentEvent];
8817   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
8818   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8820   NSTRACE ("[EmacsScroller repeatScroll:]");
8822   /* clear timer if need be */
8823   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8824     {
8825         [scroll_repeat_entry invalidate];
8826         [scroll_repeat_entry release];
8827         scroll_repeat_entry = nil;
8829         if (inKnob)
8830           return self;
8832         scroll_repeat_entry
8833           = [[NSTimer scheduledTimerWithTimeInterval:
8834                         SCROLL_BAR_CONTINUOUS_DELAY
8835                                             target: self
8836                                           selector: @selector (repeatScroll:)
8837                                           userInfo: 0
8838                                            repeats: YES]
8839               retain];
8840     }
8842   [self sendScrollEventAtLoc: 0 fromEvent: e];
8843   return self;
8847 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
8848    mouseDragged events without going into a modal loop. */
8849 - (void)mouseDown: (NSEvent *)e
8851   NSRect sr, kr;
8852   /* hitPart is only updated AFTER event is passed on */
8853   NSScrollerPart part = [self testPart: [e locationInWindow]];
8854   CGFloat loc, kloc, pos UNINIT;
8855   int edge = 0;
8857   NSTRACE ("[EmacsScroller mouseDown:]");
8859   switch (part)
8860     {
8861     case NSScrollerDecrementPage:
8862       last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
8863     case NSScrollerIncrementPage:
8864       last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
8865     case NSScrollerDecrementLine:
8866       last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
8867     case NSScrollerIncrementLine:
8868       last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
8869     case NSScrollerKnob:
8870       last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
8871     case NSScrollerKnobSlot:  /* GNUstep-only */
8872       last_hit_part = scroll_bar_move_ratio; break;
8873     default:  /* NSScrollerNoPart? */
8874       fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
8875                (long) part);
8876       return;
8877     }
8879   if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
8880     {
8881       /* handle, or on GNUstep possibly slot */
8882       NSEvent *fake_event;
8883       int length;
8885       /* compute float loc in slot and mouse offset on knob */
8886       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8887                       toView: nil];
8888       if (horizontal)
8889         {
8890           length = NSWidth (sr);
8891           loc = ([e locationInWindow].x - NSMinX (sr));
8892         }
8893       else
8894         {
8895           length = NSHeight (sr);
8896           loc = length - ([e locationInWindow].y - NSMinY (sr));
8897         }
8899       if (loc <= 0.0)
8900         {
8901           loc = 0.0;
8902           edge = -1;
8903         }
8904       else if (loc >= length)
8905         {
8906           loc = length;
8907           edge = 1;
8908         }
8910       if (edge)
8911         kloc = 0.5 * edge;
8912       else
8913         {
8914           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8915                           toView: nil];
8916           if (horizontal)
8917             kloc = ([e locationInWindow].x - NSMinX (kr));
8918           else
8919             kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8920         }
8921       last_mouse_offset = kloc;
8923       if (part != NSScrollerKnob)
8924         /* this is a slot click on GNUstep: go straight there */
8925         pos = loc;
8927       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8928       fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
8929                                       location: [e locationInWindow]
8930                                  modifierFlags: [e modifierFlags]
8931                                      timestamp: [e timestamp]
8932                                   windowNumber: [e windowNumber]
8933                                        context: nil
8934                                    eventNumber: [e eventNumber]
8935                                     clickCount: [e clickCount]
8936                                       pressure: [e pressure]];
8937       [super mouseUp: fake_event];
8938     }
8939   else
8940     {
8941       pos = 0;      /* ignored */
8943       /* set a timer to repeat, as we can't let superclass do this modally */
8944       scroll_repeat_entry
8945         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8946                                             target: self
8947                                           selector: @selector (repeatScroll:)
8948                                           userInfo: 0
8949                                            repeats: YES]
8950             retain];
8951     }
8953   if (part != NSScrollerKnob)
8954     [self sendScrollEventAtLoc: pos fromEvent: e];
8958 /* Called as we manually track scroller drags, rather than superclass. */
8959 - (void)mouseDragged: (NSEvent *)e
8961     NSRect sr;
8962     double loc, pos;
8963     int length;
8965     NSTRACE ("[EmacsScroller mouseDragged:]");
8967       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8968                       toView: nil];
8970       if (horizontal)
8971         {
8972           length = NSWidth (sr);
8973           loc = ([e locationInWindow].x - NSMinX (sr));
8974         }
8975       else
8976         {
8977           length = NSHeight (sr);
8978           loc = length - ([e locationInWindow].y - NSMinY (sr));
8979         }
8981       if (loc <= 0.0)
8982         {
8983           loc = 0.0;
8984         }
8985       else if (loc >= length + last_mouse_offset)
8986         {
8987           loc = length + last_mouse_offset;
8988         }
8990       pos = (loc - last_mouse_offset);
8991       [self sendScrollEventAtLoc: pos fromEvent: e];
8995 - (void)mouseUp: (NSEvent *)e
8997   NSTRACE ("[EmacsScroller mouseUp:]");
8999   if (scroll_repeat_entry)
9000     {
9001       [scroll_repeat_entry invalidate];
9002       [scroll_repeat_entry release];
9003       scroll_repeat_entry = nil;
9004     }
9005   last_hit_part = scroll_bar_above_handle;
9009 /* treat scrollwheel events in the bar as though they were in the main window */
9010 - (void) scrollWheel: (NSEvent *)theEvent
9012   NSTRACE ("[EmacsScroller scrollWheel:]");
9014   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
9015   [view mouseDown: theEvent];
9018 @end  /* EmacsScroller */
9021 #ifdef NS_IMPL_GNUSTEP
9022 /* Dummy class to get rid of startup warnings.  */
9023 @implementation EmacsDocument
9025 @end
9026 #endif
9029 /* ==========================================================================
9031    Font-related functions; these used to be in nsfaces.m
9033    ========================================================================== */
9036 Lisp_Object
9037 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
9039   struct font *font = XFONT_OBJECT (font_object);
9040   EmacsView *view = FRAME_NS_VIEW (f);
9041   int font_ascent, font_descent;
9043   if (fontset < 0)
9044     fontset = fontset_from_font (font_object);
9045   FRAME_FONTSET (f) = fontset;
9047   if (FRAME_FONT (f) == font)
9048     /* This font is already set in frame F.  There's nothing more to
9049        do.  */
9050     return font_object;
9052   FRAME_FONT (f) = font;
9054   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
9055   FRAME_COLUMN_WIDTH (f) = font->average_width;
9056   get_font_ascent_descent (font, &font_ascent, &font_descent);
9057   FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
9059   /* Compute the scroll bar width in character columns.  */
9060   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
9061     {
9062       int wid = FRAME_COLUMN_WIDTH (f);
9063       FRAME_CONFIG_SCROLL_BAR_COLS (f)
9064         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
9065     }
9066   else
9067     {
9068       int wid = FRAME_COLUMN_WIDTH (f);
9069       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
9070     }
9072   /* Compute the scroll bar height in character lines.  */
9073   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
9074     {
9075       int height = FRAME_LINE_HEIGHT (f);
9076       FRAME_CONFIG_SCROLL_BAR_LINES (f)
9077         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
9078     }
9079   else
9080     {
9081       int height = FRAME_LINE_HEIGHT (f);
9082       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
9083     }
9085   /* Now make the frame display the given font.  */
9086   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
9087     adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
9088                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
9089                        false, Qfont);
9091   return font_object;
9095 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
9096 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
9097          in 1.43. */
9099 const char *
9100 ns_xlfd_to_fontname (const char *xlfd)
9101 /* --------------------------------------------------------------------------
9102     Convert an X font name (XLFD) to an NS font name.
9103     Only family is used.
9104     The string returned is temporarily allocated.
9105    -------------------------------------------------------------------------- */
9107   char *name = xmalloc (180);
9108   int i, len;
9109   const char *ret;
9111   if (!strncmp (xlfd, "--", 2))
9112     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
9113   else
9114     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
9116   /* stopgap for malformed XLFD input */
9117   if (strlen (name) == 0)
9118     strcpy (name, "Monaco");
9120   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
9121      also uppercase after '-' or ' ' */
9122   name[0] = c_toupper (name[0]);
9123   for (len =strlen (name), i =0; i<len; i++)
9124     {
9125       if (name[i] == '$')
9126         {
9127           name[i] = '-';
9128           if (i+1<len)
9129             name[i+1] = c_toupper (name[i+1]);
9130         }
9131       else if (name[i] == '_')
9132         {
9133           name[i] = ' ';
9134           if (i+1<len)
9135             name[i+1] = c_toupper (name[i+1]);
9136         }
9137     }
9138 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
9139   ret = [[NSString stringWithUTF8String: name] UTF8String];
9140   xfree (name);
9141   return ret;
9145 void
9146 syms_of_nsterm (void)
9148   NSTRACE ("syms_of_nsterm");
9150   ns_antialias_threshold = 10.0;
9152   /* from 23+ we need to tell emacs what modifiers there are.. */
9153   DEFSYM (Qmodifier_value, "modifier-value");
9154   DEFSYM (Qalt, "alt");
9155   DEFSYM (Qhyper, "hyper");
9156   DEFSYM (Qmeta, "meta");
9157   DEFSYM (Qsuper, "super");
9158   DEFSYM (Qcontrol, "control");
9159   DEFSYM (QUTF8_STRING, "UTF8_STRING");
9161   DEFSYM (Qfile, "file");
9162   DEFSYM (Qurl, "url");
9164   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
9165   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
9166   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
9167   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
9168   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
9170   DEFVAR_LISP ("ns-input-file", ns_input_file,
9171               "The file specified in the last NS event.");
9172   ns_input_file =Qnil;
9174   DEFVAR_LISP ("ns-working-text", ns_working_text,
9175               "String for visualizing working composition sequence.");
9176   ns_working_text =Qnil;
9178   DEFVAR_LISP ("ns-input-font", ns_input_font,
9179               "The font specified in the last NS event.");
9180   ns_input_font =Qnil;
9182   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
9183               "The fontsize specified in the last NS event.");
9184   ns_input_fontsize =Qnil;
9186   DEFVAR_LISP ("ns-input-line", ns_input_line,
9187                "The line specified in the last NS event.");
9188   ns_input_line =Qnil;
9190   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
9191                "The service name specified in the last NS event.");
9192   ns_input_spi_name =Qnil;
9194   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
9195                "The service argument specified in the last NS event.");
9196   ns_input_spi_arg =Qnil;
9198   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
9199                "This variable describes the behavior of the alternate or option key.\n\
9200 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9201 that key.\n\
9202 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9203 at all, allowing it to be used at a lower level for accented character entry.");
9204   ns_alternate_modifier = Qmeta;
9206   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
9207                "This variable describes the behavior of the right alternate or option key.\n\
9208 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9209 that key.\n\
9210 Set to left means be the same key as `ns-alternate-modifier'.\n\
9211 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9212 at all, allowing it to be used at a lower level for accented character entry.");
9213   ns_right_alternate_modifier = Qleft;
9215   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
9216                "This variable describes the behavior of the command key.\n\
9217 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9218 that key.");
9219   ns_command_modifier = Qsuper;
9221   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
9222                "This variable describes the behavior of the right command key.\n\
9223 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9224 that key.\n\
9225 Set to left means be the same key as `ns-command-modifier'.\n\
9226 Set to none means that the command / option key is not interpreted by Emacs\n\
9227 at all, allowing it to be used at a lower level for accented character entry.");
9228   ns_right_command_modifier = Qleft;
9230   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
9231                "This variable describes the behavior of the control key.\n\
9232 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9233 that key.");
9234   ns_control_modifier = Qcontrol;
9236   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
9237                "This variable describes the behavior of the right control key.\n\
9238 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9239 that key.\n\
9240 Set to left means be the same key as `ns-control-modifier'.\n\
9241 Set to none means that the control / option key is not interpreted by Emacs\n\
9242 at all, allowing it to be used at a lower level for accented character entry.");
9243   ns_right_control_modifier = Qleft;
9245   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
9246                "This variable describes the behavior of the function key (on laptops).\n\
9247 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9248 that key.\n\
9249 Set to none means that the function key is not interpreted by Emacs at all,\n\
9250 allowing it to be used at a lower level for accented character entry.");
9251   ns_function_modifier = Qnone;
9253   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
9254                "Non-nil (the default) means to render text antialiased.");
9255   ns_antialias_text = Qt;
9257   DEFVAR_LISP ("ns-use-thin-smoothing", ns_use_thin_smoothing,
9258                "Non-nil turns on a font smoothing method that produces thinner strokes.");
9259   ns_use_thin_smoothing = Qnil;
9261   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
9262                "Whether to confirm application quit using dialog.");
9263   ns_confirm_quit = Qnil;
9265   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
9266                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
9267 Only works on Mac OS X 10.6 or later.  */);
9268   ns_auto_hide_menu_bar = Qnil;
9270   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
9271      doc: /*Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
9272 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
9273 multiple monitors, but lacks tool bar.  This variable is ignored on
9274 Mac OS X < 10.7.  Default is t.  */);
9275   ns_use_native_fullscreen = YES;
9276   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
9278   DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
9279      doc: /*Non-nil means use animation on non-native fullscreen.
9280 For native fullscreen, this does nothing.
9281 Default is nil.  */);
9282   ns_use_fullscreen_animation = NO;
9284   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
9285      doc: /*Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
9286 Note that this does not apply to images.
9287 This variable is ignored on Mac OS X < 10.7 and GNUstep.  */);
9288   ns_use_srgb_colorspace = YES;
9290   DEFVAR_BOOL ("ns-use-mwheel-acceleration",
9291                ns_use_mwheel_acceleration,
9292      doc: /*Non-nil means use macOS's standard mouse wheel acceleration.
9293 This variable is ignored on macOS < 10.7 and GNUstep.  Default is t.  */);
9294   ns_use_mwheel_acceleration = YES;
9296   DEFVAR_LISP ("ns-mwheel-line-height", ns_mwheel_line_height,
9297                doc: /*The number of pixels touchpad scrolling considers one line.
9298 Nil or a non-number means use the default frame line height.
9299 This variable is ignored on macOS < 10.7 and GNUstep.  Default is nil.  */);
9300   ns_mwheel_line_height = Qnil;
9302   DEFVAR_BOOL ("ns-use-mwheel-momentum", ns_use_mwheel_momentum,
9303                doc: /*Non-nil means mouse wheel scrolling uses momentum.
9304 This variable is ignored on macOS < 10.7 and GNUstep.  Default is t.  */);
9305   ns_use_mwheel_momentum = YES;
9307   /* TODO: move to common code */
9308   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
9309                doc: /* Which toolkit scroll bars Emacs uses, if any.
9310 A value of nil means Emacs doesn't use toolkit scroll bars.
9311 With the X Window system, the value is a symbol describing the
9312 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
9313 With MS Windows or Nextstep, the value is t.  */);
9314   Vx_toolkit_scroll_bars = Qt;
9316   DEFVAR_BOOL ("x-use-underline-position-properties",
9317                x_use_underline_position_properties,
9318      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
9319 A value of nil means ignore them.  If you encounter fonts with bogus
9320 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
9321 to 4.1, set this to nil. */);
9322   x_use_underline_position_properties = 0;
9324   DEFVAR_BOOL ("x-underline-at-descent-line",
9325                x_underline_at_descent_line,
9326      doc: /* Non-nil means to draw the underline at the same place as the descent line.
9327 A value of nil means to draw the underline according to the value of the
9328 variable `x-use-underline-position-properties', which is usually at the
9329 baseline level.  The default value is nil.  */);
9330   x_underline_at_descent_line = 0;
9332   /* Tell Emacs about this window system.  */
9333   Fprovide (Qns, Qnil);
9335   DEFSYM (Qcocoa, "cocoa");
9336   DEFSYM (Qgnustep, "gnustep");
9338 #ifdef NS_IMPL_COCOA
9339   Fprovide (Qcocoa, Qnil);
9340   syms_of_macfont ();
9341 #else
9342   Fprovide (Qgnustep, Qnil);
9343   syms_of_nsfont ();
9344 #endif