Update authors.el
[emacs.git] / src / nsterm.m
blobf0b6a70dae3b37278273c4a1420a17d6f7b26084
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 (fs_state == FULLSCREEN_MAXIMIZED
6897       && (maximized_width != (int)frameSize.width
6898           || maximized_height != (int)frameSize.height))
6899     [self setFSValue: FULLSCREEN_NONE];
6900   else if (fs_state == FULLSCREEN_WIDTH
6901            && maximized_width != (int)frameSize.width)
6902     [self setFSValue: FULLSCREEN_NONE];
6903   else if (fs_state == FULLSCREEN_HEIGHT
6904            && maximized_height != (int)frameSize.height)
6905     [self setFSValue: FULLSCREEN_NONE];
6907   if (fs_state == FULLSCREEN_NONE)
6908     maximized_width = maximized_height = -1;
6910   if (! [self isFullscreen])
6911     {
6912       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6913         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6914     }
6916   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6917   if (cols < MINWIDTH)
6918     cols = MINWIDTH;
6920   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6921                                            frameSize.height - extra);
6922   if (rows < MINHEIGHT)
6923     rows = MINHEIGHT;
6924 #ifdef NS_IMPL_COCOA
6925   {
6926     /* this sets window title to have size in it; the wm does this under GS */
6927     NSRect r = [[self window] frame];
6928     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6929       {
6930         if (old_title != 0)
6931           {
6932             xfree (old_title);
6933             old_title = 0;
6934           }
6935       }
6936     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
6937              && [[self window] title] != NULL)
6938       {
6939         char *size_title;
6940         NSWindow *window = [self window];
6941         if (old_title == 0)
6942           {
6943             char *t = strdup ([[[self window] title] UTF8String]);
6944             char *pos = strstr (t, "  â€”  ");
6945             if (pos)
6946               *pos = '\0';
6947             old_title = t;
6948           }
6949         size_title = xmalloc (strlen (old_title) + 40);
6950         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
6951         [window setTitle: [NSString stringWithUTF8String: size_title]];
6952         [window display];
6953         xfree (size_title);
6954       }
6955   }
6956 #endif /* NS_IMPL_COCOA */
6958   NSTRACE_MSG ("cols: %d  rows: %d", cols, rows);
6960   /* Restrict the new size to the text gird.
6962      Don't restrict the width if the user only adjusted the height, and
6963      vice versa.  (Without this, the frame would shrink, and move
6964      slightly, if the window was resized by dragging one of its
6965      borders.) */
6966   if (!frame_resize_pixelwise)
6967     {
6968       NSRect r = [[self window] frame];
6970       if (r.size.width != frameSize.width)
6971         {
6972           frameSize.width =
6973             FRAME_TEXT_COLS_TO_PIXEL_WIDTH  (emacsframe, cols);
6974         }
6976       if (r.size.height != frameSize.height)
6977         {
6978           frameSize.height =
6979             FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6980         }
6981     }
6983   NSTRACE_RETURN_SIZE (frameSize);
6985   return frameSize;
6989 - (void)windowDidResize: (NSNotification *)notification
6991   NSTRACE ("[EmacsView windowDidResize:]");
6992   if (!FRAME_LIVE_P (emacsframe))
6993     {
6994       NSTRACE_MSG ("Ignored (frame dead)");
6995       return;
6996     }
6997   if (emacsframe->output_data.ns->in_animation)
6998     {
6999       NSTRACE_MSG ("Ignored (in animation)");
7000       return;
7001     }
7003   if (! [self fsIsNative])
7004     {
7005       NSWindow *theWindow = [notification object];
7006       /* We can get notification on the non-FS window when in
7007          fullscreen mode.  */
7008       if ([self window] != theWindow) return;
7009     }
7011   NSTRACE_RECT ("frame", [[notification object] frame]);
7013 #ifdef NS_IMPL_GNUSTEP
7014   NSWindow *theWindow = [notification object];
7016    /* In GNUstep, at least currently, it's possible to get a didResize
7017       without getting a willResize.. therefore we need to act as if we got
7018       the willResize now */
7019   NSSize sz = [theWindow frame].size;
7020   sz = [self windowWillResize: theWindow toSize: sz];
7021 #endif /* NS_IMPL_GNUSTEP */
7023   if (cols > 0 && rows > 0)
7024     {
7025       [self updateFrameSize: YES];
7026     }
7028   ns_send_appdefined (-1);
7031 #ifdef NS_IMPL_COCOA
7032 - (void)viewDidEndLiveResize
7034   NSTRACE ("[EmacsView viewDidEndLiveResize]");
7036   [super viewDidEndLiveResize];
7037   if (old_title != 0)
7038     {
7039       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
7040       xfree (old_title);
7041       old_title = 0;
7042     }
7043   maximizing_resize = NO;
7045 #endif /* NS_IMPL_COCOA */
7048 - (void)windowDidBecomeKey: (NSNotification *)notification
7049 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
7051   [self windowDidBecomeKey];
7055 - (void)windowDidBecomeKey      /* for direct calls */
7057   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7058   struct frame *old_focus = dpyinfo->x_focus_frame;
7060   NSTRACE ("[EmacsView windowDidBecomeKey]");
7062   if (emacsframe != old_focus)
7063     dpyinfo->x_focus_frame = emacsframe;
7065   ns_frame_rehighlight (emacsframe);
7067   if (emacs_event)
7068     {
7069       emacs_event->kind = FOCUS_IN_EVENT;
7070       EV_TRAILER ((id)nil);
7071     }
7075 - (void)windowDidResignKey: (NSNotification *)notification
7076 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
7078   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7079   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
7080   NSTRACE ("[EmacsView windowDidResignKey:]");
7082   if (is_focus_frame)
7083     dpyinfo->x_focus_frame = 0;
7085   emacsframe->mouse_moved = 0;
7086   ns_frame_rehighlight (emacsframe);
7088   /* FIXME: for some reason needed on second and subsequent clicks away
7089             from sole-frame Emacs to get hollow box to show */
7090   if (!windowClosing && [[self window] isVisible] == YES)
7091     {
7092       x_update_cursor (emacsframe, 1);
7093       x_set_frame_alpha (emacsframe);
7094     }
7096   if (any_help_event_p)
7097     {
7098       Lisp_Object frame;
7099       XSETFRAME (frame, emacsframe);
7100       help_echo_string = Qnil;
7101       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
7102     }
7104   if (emacs_event && is_focus_frame)
7105     {
7106       [self deleteWorkingText];
7107       emacs_event->kind = FOCUS_OUT_EVENT;
7108       EV_TRAILER ((id)nil);
7109     }
7113 - (void)windowWillMiniaturize: sender
7115   NSTRACE ("[EmacsView windowWillMiniaturize:]");
7119 - (void)setFrame:(NSRect)frameRect
7121   NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
7122            NSTRACE_ARG_RECT (frameRect));
7124   [super setFrame:(NSRect)frameRect];
7128 - (BOOL)isFlipped
7130   return YES;
7134 - (BOOL)isOpaque
7136   return NO;
7140 - (void)createToolbar: (struct frame *)f
7142   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
7143   NSWindow *window = [view window];
7145   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
7146                    [NSString stringWithFormat: @"Emacs Frame %d",
7147                              ns_window_num]];
7148   [toolbar setVisible: NO];
7149   [window setToolbar: toolbar];
7151   /* Don't set frame garbaged until tool bar is up to date?
7152      This avoids an extra clear and redraw (flicker) at frame creation.  */
7153   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
7154   else wait_for_tool_bar = NO;
7157 #ifdef NS_IMPL_COCOA
7158   {
7159     NSButton *toggleButton;
7160     toggleButton = [window standardWindowButton: NSWindowToolbarButton];
7161     [toggleButton setTarget: self];
7162     [toggleButton setAction: @selector (toggleToolbar: )];
7163   }
7164 #endif
7168 - (instancetype) initFrameFromEmacs: (struct frame *)f
7170   NSRect r, wr;
7171   Lisp_Object tem;
7172   NSWindow *win;
7173   NSColor *col;
7174   NSString *name;
7176   NSTRACE ("[EmacsView initFrameFromEmacs:]");
7177   NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
7179   windowClosing = NO;
7180   processingCompose = NO;
7181   scrollbarsNeedingUpdate = 0;
7182   fs_state = FULLSCREEN_NONE;
7183   fs_before_fs = next_maximized = -1;
7185   fs_is_native = NO;
7186 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7187 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7188   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7189 #endif
7190     fs_is_native = ns_use_native_fullscreen;
7191 #endif
7193   maximized_width = maximized_height = -1;
7194   nonfs_window = nil;
7196   ns_userRect = NSMakeRect (0, 0, 0, 0);
7197   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
7198                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
7199   [self initWithFrame: r];
7200   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
7202   FRAME_NS_VIEW (f) = self;
7203   emacsframe = f;
7204 #ifdef NS_IMPL_COCOA
7205   old_title = 0;
7206   maximizing_resize = NO;
7207 #endif
7209   win = [[EmacsWindow alloc]
7210             initWithContentRect: r
7211                       styleMask: ((FRAME_UNDECORATED (f)
7212                                    ? FRAME_UNDECORATED_FLAGS
7213                                    : FRAME_DECORATED_FLAGS)
7214 #ifdef NS_IMPL_COCOA
7215                                   | NSWindowStyleMaskResizable
7216                                   | NSWindowStyleMaskMiniaturizable
7217                                   | NSWindowStyleMaskClosable
7218 #endif
7219                                   )
7220                         backing: NSBackingStoreBuffered
7221                           defer: YES];
7223 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7224 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7225   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7226 #endif
7227     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
7228 #endif
7230   wr = [win frame];
7231   bwidth = f->border_width = wr.size.width - r.size.width;
7233   [win setAcceptsMouseMovedEvents: YES];
7234   [win setDelegate: self];
7235 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7236 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7237   if ([win respondsToSelector: @selector(useOptimizedDrawing:)])
7238 #endif
7239     [win useOptimizedDrawing: YES];
7240 #endif
7242   [[win contentView] addSubview: self];
7244   if (ns_drag_types)
7245     [self registerForDraggedTypes: ns_drag_types];
7247   tem = f->name;
7248   name = [NSString stringWithUTF8String:
7249                    NILP (tem) ? "Emacs" : SSDATA (tem)];
7250   [win setTitle: name];
7252   /* toolbar support */
7253   if (! FRAME_UNDECORATED (f))
7254     [self createToolbar: f];
7256 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7257 #ifndef NSAppKitVersionNumber10_10
7258 #define NSAppKitVersionNumber10_10 1343
7259 #endif
7261   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_10
7262       && FRAME_NS_APPEARANCE (f) != ns_appearance_aqua)
7263     win.appearance = [NSAppearance
7264                           appearanceNamed: NSAppearanceNameVibrantDark];
7265 #endif
7267 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7268   if ([win respondsToSelector: @selector(titlebarAppearsTransparent)])
7269     win.titlebarAppearsTransparent = FRAME_NS_TRANSPARENT_TITLEBAR (f);
7270 #endif
7272   tem = f->icon_name;
7273   if (!NILP (tem))
7274     [win setMiniwindowTitle:
7275            [NSString stringWithUTF8String: SSDATA (tem)]];
7277   if (FRAME_PARENT_FRAME (f) != NULL)
7278     {
7279       NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
7280       [parent addChildWindow: win
7281                      ordered: NSWindowAbove];
7282     }
7284   if (FRAME_Z_GROUP (f) != z_group_none)
7285       win.level = NSNormalWindowLevel
7286         + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
7288   {
7289     NSScreen *screen = [win screen];
7291     if (screen != 0)
7292       {
7293         NSPoint pt = NSMakePoint
7294           (IN_BOUND (-SCREENMAX, f->left_pos
7295                      + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7296            IN_BOUND (-SCREENMAX,
7297                      NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7298                      SCREENMAX));
7300         [win setFrameTopLeftPoint: pt];
7302         NSTRACE_RECT ("new frame", [win frame]);
7303       }
7304   }
7306   [win makeFirstResponder: self];
7308   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7309                                  (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7310                                  emacsframe);
7311   [win setBackgroundColor: col];
7312   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7313     [win setOpaque: NO];
7315 #if !defined (NS_IMPL_COCOA) \
7316   || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7317 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7318   if ([self respondsToSelector: @selector(allocateGState)])
7319 #endif
7320     [self allocateGState];
7321 #endif
7322   [NSApp registerServicesMenuSendTypes: ns_send_types
7323                            returnTypes: [NSArray array]];
7325   /* macOS Sierra automatically enables tabbed windows.  We can't
7326      allow this to be enabled until it's available on a Free system.
7327      Currently it only happens by accident and is buggy anyway. */
7328 #if defined (NS_IMPL_COCOA) \
7329   && MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
7330 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
7331   if ([win respondsToSelector: @selector(setTabbingMode:)])
7332 #endif
7333     [win setTabbingMode: NSWindowTabbingModeDisallowed];
7334 #endif
7336   ns_window_num++;
7337   return self;
7341 - (void)windowDidMove: sender
7343   NSWindow *win = [self window];
7344   NSRect r = [win frame];
7345   NSArray *screens = [NSScreen screens];
7346   NSScreen *screen = [screens objectAtIndex: 0];
7348   NSTRACE ("[EmacsView windowDidMove:]");
7350   if (!emacsframe->output_data.ns)
7351     return;
7352   if (screen != nil)
7353     {
7354       emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7355       emacsframe->top_pos =
7356         NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7358       if (emacs_event)
7359         {
7360           emacs_event->kind = MOVE_FRAME_EVENT;
7361           EV_TRAILER ((id)nil);
7362         }
7363     }
7367 /* Called AFTER method below, but before our windowWillResize call there leads
7368    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
7369    location so set_window_size moves the frame. */
7370 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7372   NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7373             NSTRACE_FMT_RETURN "YES"),
7374            NSTRACE_ARG_RECT (newFrame));
7376   emacsframe->output_data.ns->zooming = 1;
7377   return YES;
7381 /* Override to do something slightly nonstandard, but nice.  First click on
7382    zoom button will zoom vertically.  Second will zoom completely.  Third
7383    returns to original. */
7384 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7385                         defaultFrame:(NSRect)defaultFrame
7387   // TODO: Rename to "currentFrame" and assign "result" properly in
7388   // all paths.
7389   NSRect result = [sender frame];
7391   NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7392             NSTRACE_FMT_RECT "]"),
7393            NSTRACE_ARG_RECT (defaultFrame));
7394   NSTRACE_FSTYPE ("fs_state", fs_state);
7395   NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7396   NSTRACE_FSTYPE ("next_maximized", next_maximized);
7397   NSTRACE_RECT   ("ns_userRect", ns_userRect);
7398   NSTRACE_RECT   ("[sender frame]", [sender frame]);
7400   if (fs_before_fs != -1) /* Entering fullscreen */
7401     {
7402       NSTRACE_MSG ("Entering fullscreen");
7403       result = defaultFrame;
7404     }
7405   else
7406     {
7407       // Save the window size and position (frame) before the resize.
7408       if (fs_state != FULLSCREEN_MAXIMIZED
7409           && fs_state != FULLSCREEN_WIDTH)
7410         {
7411           ns_userRect.size.width = result.size.width;
7412           ns_userRect.origin.x   = result.origin.x;
7413         }
7415       if (fs_state != FULLSCREEN_MAXIMIZED
7416           && fs_state != FULLSCREEN_HEIGHT)
7417         {
7418           ns_userRect.size.height = result.size.height;
7419           ns_userRect.origin.y    = result.origin.y;
7420         }
7422       NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7424       if (next_maximized == FULLSCREEN_HEIGHT
7425           || (next_maximized == -1
7426               && abs ((int)(defaultFrame.size.height - result.size.height))
7427               > FRAME_LINE_HEIGHT (emacsframe)))
7428         {
7429           /* first click */
7430           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7431           maximized_height = result.size.height = defaultFrame.size.height;
7432           maximized_width = -1;
7433           result.origin.y = defaultFrame.origin.y;
7434           if (ns_userRect.size.height != 0)
7435             {
7436               result.origin.x = ns_userRect.origin.x;
7437               result.size.width = ns_userRect.size.width;
7438             }
7439           [self setFSValue: FULLSCREEN_HEIGHT];
7440 #ifdef NS_IMPL_COCOA
7441           maximizing_resize = YES;
7442 #endif
7443         }
7444       else if (next_maximized == FULLSCREEN_WIDTH)
7445         {
7446           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7447           maximized_width = result.size.width = defaultFrame.size.width;
7448           maximized_height = -1;
7449           result.origin.x = defaultFrame.origin.x;
7450           if (ns_userRect.size.width != 0)
7451             {
7452               result.origin.y = ns_userRect.origin.y;
7453               result.size.height = ns_userRect.size.height;
7454             }
7455           [self setFSValue: FULLSCREEN_WIDTH];
7456         }
7457       else if (next_maximized == FULLSCREEN_MAXIMIZED
7458                || (next_maximized == -1
7459                    && abs ((int)(defaultFrame.size.width - result.size.width))
7460                    > FRAME_COLUMN_WIDTH (emacsframe)))
7461         {
7462           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7464           result = defaultFrame;  /* second click */
7465           maximized_width = result.size.width;
7466           maximized_height = result.size.height;
7467           [self setFSValue: FULLSCREEN_MAXIMIZED];
7468 #ifdef NS_IMPL_COCOA
7469           maximizing_resize = YES;
7470 #endif
7471         }
7472       else
7473         {
7474           /* restore */
7475           NSTRACE_MSG ("Restore");
7476           result = ns_userRect.size.height ? ns_userRect : result;
7477           NSTRACE_RECT ("restore (2)", result);
7478           ns_userRect = NSMakeRect (0, 0, 0, 0);
7479 #ifdef NS_IMPL_COCOA
7480           maximizing_resize = fs_state != FULLSCREEN_NONE;
7481 #endif
7482           [self setFSValue: FULLSCREEN_NONE];
7483           maximized_width = maximized_height = -1;
7484         }
7485     }
7487   if (fs_before_fs == -1) next_maximized = -1;
7489   NSTRACE_RECT   ("Final ns_userRect", ns_userRect);
7490   NSTRACE_MSG    ("Final maximized_width: %d", maximized_width);
7491   NSTRACE_MSG    ("Final maximized_height: %d", maximized_height);
7492   NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7494   [self windowWillResize: sender toSize: result.size];
7496   NSTRACE_RETURN_RECT (result);
7498   return result;
7502 - (void)windowDidDeminiaturize: sender
7504   NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7505   if (!emacsframe->output_data.ns)
7506     return;
7508   SET_FRAME_ICONIFIED (emacsframe, 0);
7509   SET_FRAME_VISIBLE (emacsframe, 1);
7510   windows_or_buffers_changed = 63;
7512   if (emacs_event)
7513     {
7514       emacs_event->kind = DEICONIFY_EVENT;
7515       EV_TRAILER ((id)nil);
7516     }
7520 - (void)windowDidExpose: sender
7522   NSTRACE ("[EmacsView windowDidExpose:]");
7523   if (!emacsframe->output_data.ns)
7524     return;
7526   SET_FRAME_VISIBLE (emacsframe, 1);
7527   SET_FRAME_GARBAGED (emacsframe);
7529   if (send_appdefined)
7530     ns_send_appdefined (-1);
7534 - (void)windowDidMiniaturize: sender
7536   NSTRACE ("[EmacsView windowDidMiniaturize:]");
7537   if (!emacsframe->output_data.ns)
7538     return;
7540   SET_FRAME_ICONIFIED (emacsframe, 1);
7541   SET_FRAME_VISIBLE (emacsframe, 0);
7543   if (emacs_event)
7544     {
7545       emacs_event->kind = ICONIFY_EVENT;
7546       EV_TRAILER ((id)nil);
7547     }
7550 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7551 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7552       willUseFullScreenPresentationOptions:
7553   (NSApplicationPresentationOptions)proposedOptions
7555   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7557 #endif
7559 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7561   NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7562   [self windowWillEnterFullScreen];
7564 - (void)windowWillEnterFullScreen /* provided for direct calls */
7566   NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7567   fs_before_fs = fs_state;
7570 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7572   NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7573   [self windowDidEnterFullScreen];
7576 - (void)windowDidEnterFullScreen /* provided for direct calls */
7578   NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7579   [self setFSValue: FULLSCREEN_BOTH];
7580   if (! [self fsIsNative])
7581     {
7582       [self windowDidBecomeKey];
7583       [nonfs_window orderOut:self];
7584     }
7585   else
7586     {
7587       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7588 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \
7589   && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
7590       unsigned val = (unsigned)[NSApp presentationOptions];
7592       // Mac OS X 10.7 bug fix, the menu won't appear without this.
7593       // val is non-zero on other macOS versions.
7594       if (val == 0)
7595         {
7596           NSApplicationPresentationOptions options
7597             = NSApplicationPresentationAutoHideDock
7598             | NSApplicationPresentationAutoHideMenuBar
7599             | NSApplicationPresentationFullScreen
7600             | NSApplicationPresentationAutoHideToolbar;
7602           [NSApp setPresentationOptions: options];
7603         }
7604 #endif
7605       [toolbar setVisible:tbar_visible];
7606     }
7609 - (void)windowWillExitFullScreen:(NSNotification *)notification
7611   NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7612   [self windowWillExitFullScreen];
7615 - (void)windowWillExitFullScreen /* provided for direct calls */
7617   NSTRACE ("[EmacsView windowWillExitFullScreen]");
7618   if (!FRAME_LIVE_P (emacsframe))
7619     {
7620       NSTRACE_MSG ("Ignored (frame dead)");
7621       return;
7622     }
7623   if (next_maximized != -1)
7624     fs_before_fs = next_maximized;
7627 - (void)windowDidExitFullScreen:(NSNotification *)notification
7629   NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7630   [self windowDidExitFullScreen];
7633 - (void)windowDidExitFullScreen /* provided for direct calls */
7635   NSTRACE ("[EmacsView windowDidExitFullScreen]");
7636   if (!FRAME_LIVE_P (emacsframe))
7637     {
7638       NSTRACE_MSG ("Ignored (frame dead)");
7639       return;
7640     }
7641   [self setFSValue: fs_before_fs];
7642   fs_before_fs = -1;
7643 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7644   [self updateCollectionBehavior];
7645 #endif
7646   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7647     {
7648       [toolbar setVisible:YES];
7649       update_frame_tool_bar (emacsframe);
7650       [self updateFrameSize:YES];
7651       [[self window] display];
7652     }
7653   else
7654     [toolbar setVisible:NO];
7656   if (next_maximized != -1)
7657     [[self window] performZoom:self];
7660 - (BOOL)fsIsNative
7662   return fs_is_native;
7665 - (BOOL)isFullscreen
7667   BOOL res;
7669   if (! fs_is_native)
7670     {
7671       res = (nonfs_window != nil);
7672     }
7673   else
7674     {
7675 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7676       res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7677 #else
7678       res = NO;
7679 #endif
7680     }
7682   NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7683            (int) res);
7685   return res;
7688 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7689 - (void)updateCollectionBehavior
7691   NSTRACE ("[EmacsView updateCollectionBehavior]");
7693   if (! [self isFullscreen])
7694     {
7695       NSWindow *win = [self window];
7696       NSWindowCollectionBehavior b = [win collectionBehavior];
7697       if (ns_use_native_fullscreen)
7698         b |= NSWindowCollectionBehaviorFullScreenPrimary;
7699       else
7700         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7702       [win setCollectionBehavior: b];
7703 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7704       if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7705 #endif
7706         fs_is_native = ns_use_native_fullscreen;
7707     }
7709 #endif
7711 - (void)toggleFullScreen: (id)sender
7713   NSWindow *w, *fw;
7714   BOOL onFirstScreen;
7715   struct frame *f;
7716   NSRect r, wr;
7717   NSColor *col;
7719   NSTRACE ("[EmacsView toggleFullScreen:]");
7721   if (fs_is_native)
7722     {
7723 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7724 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7725       if ([[self window] respondsToSelector: @selector(toggleFullScreen:)])
7726 #endif
7727         [[self window] toggleFullScreen:sender];
7728 #endif
7729       return;
7730     }
7732   w = [self window];
7733   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7734   f = emacsframe;
7735   wr = [w frame];
7736   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7737                                  (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7738                                  f);
7740   if (fs_state != FULLSCREEN_BOTH)
7741     {
7742       NSScreen *screen = [w screen];
7744 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
7745       /* Hide ghost menu bar on secondary monitor? */
7746       if (! onFirstScreen
7747 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
7748           && [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)]
7749 #endif
7750           )
7751         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7752 #endif
7753       /* Hide dock and menubar if we are on the primary screen.  */
7754       if (onFirstScreen)
7755         {
7756 #ifdef NS_IMPL_COCOA
7757           NSApplicationPresentationOptions options
7758             = NSApplicationPresentationAutoHideDock
7759             | NSApplicationPresentationAutoHideMenuBar;
7761           [NSApp setPresentationOptions: options];
7762 #else
7763           [NSMenu setMenuBarVisible:NO];
7764 #endif
7765         }
7767       fw = [[EmacsFSWindow alloc]
7768                        initWithContentRect:[w contentRectForFrameRect:wr]
7769                                  styleMask:NSWindowStyleMaskBorderless
7770                                    backing:NSBackingStoreBuffered
7771                                      defer:YES
7772                                     screen:screen];
7774       [fw setContentView:[w contentView]];
7775       [fw setTitle:[w title]];
7776       [fw setDelegate:self];
7777       [fw setAcceptsMouseMovedEvents: YES];
7778 #if !defined (NS_IMPL_COCOA) \
7779   || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7780 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7781       if ([fw respondsToSelector: @selector(useOptimizedDrawing:)])
7782 #endif
7783         [fw useOptimizedDrawing: YES];
7784 #endif
7785       [fw setBackgroundColor: col];
7786       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7787         [fw setOpaque: NO];
7789       f->border_width = 0;
7791       nonfs_window = w;
7793       [self windowWillEnterFullScreen];
7794       [fw makeKeyAndOrderFront:NSApp];
7795       [fw makeFirstResponder:self];
7796       [w orderOut:self];
7797       r = [fw frameRectForContentRect:[screen frame]];
7798       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7799       [self windowDidEnterFullScreen];
7800       [fw display];
7801     }
7802   else
7803     {
7804       fw = w;
7805       w = nonfs_window;
7806       nonfs_window = nil;
7808       if (onFirstScreen)
7809         {
7810 #ifdef NS_IMPL_COCOA
7811           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7812 #else
7813           [NSMenu setMenuBarVisible:YES];
7814 #endif
7815         }
7817       [w setContentView:[fw contentView]];
7818       [w setBackgroundColor: col];
7819       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7820         [w setOpaque: NO];
7822       f->border_width = bwidth;
7824       // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7826       [self windowWillExitFullScreen];
7827       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7828       [fw close];
7829       [w makeKeyAndOrderFront:NSApp];
7830       [self windowDidExitFullScreen];
7831       [self updateFrameSize:YES];
7832     }
7835 - (void)handleFS
7837   NSTRACE ("[EmacsView handleFS]");
7839   if (fs_state != emacsframe->want_fullscreen)
7840     {
7841       if (fs_state == FULLSCREEN_BOTH)
7842         {
7843           NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7844           [self toggleFullScreen:self];
7845         }
7847       switch (emacsframe->want_fullscreen)
7848         {
7849         case FULLSCREEN_BOTH:
7850           NSTRACE_MSG ("FULLSCREEN_BOTH");
7851           [self toggleFullScreen:self];
7852           break;
7853         case FULLSCREEN_WIDTH:
7854           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7855           next_maximized = FULLSCREEN_WIDTH;
7856           if (fs_state != FULLSCREEN_BOTH)
7857             [[self window] performZoom:self];
7858           break;
7859         case FULLSCREEN_HEIGHT:
7860           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7861           next_maximized = FULLSCREEN_HEIGHT;
7862           if (fs_state != FULLSCREEN_BOTH)
7863             [[self window] performZoom:self];
7864           break;
7865         case FULLSCREEN_MAXIMIZED:
7866           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7867           next_maximized = FULLSCREEN_MAXIMIZED;
7868           if (fs_state != FULLSCREEN_BOTH)
7869             [[self window] performZoom:self];
7870           break;
7871         case FULLSCREEN_NONE:
7872           NSTRACE_MSG ("FULLSCREEN_NONE");
7873           if (fs_state != FULLSCREEN_BOTH)
7874             {
7875               next_maximized = FULLSCREEN_NONE;
7876               [[self window] performZoom:self];
7877             }
7878           break;
7879         }
7881       emacsframe->want_fullscreen = FULLSCREEN_NONE;
7882     }
7886 - (void) setFSValue: (int)value
7888   NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7889            NSTRACE_ARG_FSTYPE(value));
7891   Lisp_Object lval = Qnil;
7892   switch (value)
7893     {
7894     case FULLSCREEN_BOTH:
7895       lval = Qfullboth;
7896       break;
7897     case FULLSCREEN_WIDTH:
7898       lval = Qfullwidth;
7899       break;
7900     case FULLSCREEN_HEIGHT:
7901       lval = Qfullheight;
7902       break;
7903     case FULLSCREEN_MAXIMIZED:
7904       lval = Qmaximized;
7905       break;
7906     }
7907   store_frame_param (emacsframe, Qfullscreen, lval);
7908   fs_state = value;
7911 - (void)mouseEntered: (NSEvent *)theEvent
7913   NSTRACE ("[EmacsView mouseEntered:]");
7914   if (emacsframe)
7915     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7916       = EV_TIMESTAMP (theEvent);
7920 - (void)mouseExited: (NSEvent *)theEvent
7922   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7924   NSTRACE ("[EmacsView mouseExited:]");
7926   if (!hlinfo)
7927     return;
7929   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7930     = EV_TIMESTAMP (theEvent);
7932   if (emacsframe == hlinfo->mouse_face_mouse_frame)
7933     {
7934       clear_mouse_face (hlinfo);
7935       hlinfo->mouse_face_mouse_frame = 0;
7936     }
7940 - (instancetype)menuDown: sender
7942   NSTRACE ("[EmacsView menuDown:]");
7943   if (context_menu_value == -1)
7944     context_menu_value = [sender tag];
7945   else
7946     {
7947       NSInteger tag = [sender tag];
7948       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7949                                     emacsframe->menu_bar_vector,
7950                                     (void *)tag);
7951     }
7953   ns_send_appdefined (-1);
7954   return self;
7958 - (EmacsToolbar *)toolbar
7960   return toolbar;
7964 /* this gets called on toolbar button click */
7965 - (instancetype)toolbarClicked: (id)item
7967   NSEvent *theEvent;
7968   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7970   NSTRACE ("[EmacsView toolbarClicked:]");
7972   if (!emacs_event)
7973     return self;
7975   /* send first event (for some reason two needed) */
7976   theEvent = [[self window] currentEvent];
7977   emacs_event->kind = TOOL_BAR_EVENT;
7978   XSETFRAME (emacs_event->arg, emacsframe);
7979   EV_TRAILER (theEvent);
7981   emacs_event->kind = TOOL_BAR_EVENT;
7982 /*   XSETINT (emacs_event->code, 0); */
7983   emacs_event->arg = AREF (emacsframe->tool_bar_items,
7984                            idx + TOOL_BAR_ITEM_KEY);
7985   emacs_event->modifiers = EV_MODIFIERS (theEvent);
7986   EV_TRAILER (theEvent);
7987   return self;
7991 - (instancetype)toggleToolbar: (id)sender
7993   NSTRACE ("[EmacsView toggleToolbar:]");
7995   if (!emacs_event)
7996     return self;
7998   emacs_event->kind = NS_NONKEY_EVENT;
7999   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
8000   EV_TRAILER ((id)nil);
8001   return self;
8005 - (void)drawRect: (NSRect)rect
8007   int x = NSMinX (rect), y = NSMinY (rect);
8008   int width = NSWidth (rect), height = NSHeight (rect);
8010   NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
8011            NSTRACE_ARG_RECT(rect));
8013   if (!emacsframe || !emacsframe->output_data.ns)
8014     return;
8016   ns_clear_frame_area (emacsframe, x, y, width, height);
8017   block_input ();
8018   expose_frame (emacsframe, x, y, width, height);
8019   unblock_input ();
8021   /*
8022     drawRect: may be called (at least in Mac OS X 10.5) for invisible
8023     views as well for some reason.  Thus, do not infer visibility
8024     here.
8026     emacsframe->async_visible = 1;
8027     emacsframe->async_iconified = 0;
8028   */
8032 /* NSDraggingDestination protocol methods.  Actually this is not really a
8033    protocol, but a category of Object.  O well...  */
8035 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
8037   NSTRACE ("[EmacsView draggingEntered:]");
8038   return NSDragOperationGeneric;
8042 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
8044   return YES;
8048 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
8050   id pb;
8051   int x, y;
8052   NSString *type;
8053   NSEvent *theEvent = [[self window] currentEvent];
8054   NSPoint position;
8055   NSDragOperation op = [sender draggingSourceOperationMask];
8056   int modifiers = 0;
8058   NSTRACE ("[EmacsView performDragOperation:]");
8060   if (!emacs_event)
8061     return NO;
8063   position = [self convertPoint: [sender draggingLocation] fromView: nil];
8064   x = lrint (position.x);  y = lrint (position.y);
8066   pb = [sender draggingPasteboard];
8067   type = [pb availableTypeFromArray: ns_drag_types];
8069   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
8070       // URL drags contain all operations (0xf), don't allow all to be set.
8071       (op & 0xf) != 0xf)
8072     {
8073       if (op & NSDragOperationLink)
8074         modifiers |= NSEventModifierFlagControl;
8075       if (op & NSDragOperationCopy)
8076         modifiers |= NSEventModifierFlagOption;
8077       if (op & NSDragOperationGeneric)
8078         modifiers |= NSEventModifierFlagCommand;
8079     }
8081   modifiers = EV_MODIFIERS2 (modifiers);
8082   if (type == 0)
8083     {
8084       return NO;
8085     }
8086   else if ([type isEqualToString: NSFilenamesPboardType])
8087     {
8088       NSArray *files;
8089       NSEnumerator *fenum;
8090       NSString *file;
8092       if (!(files = [pb propertyListForType: type]))
8093         return NO;
8095       fenum = [files objectEnumerator];
8096       while ( (file = [fenum nextObject]) )
8097         {
8098           emacs_event->kind = DRAG_N_DROP_EVENT;
8099           XSETINT (emacs_event->x, x);
8100           XSETINT (emacs_event->y, y);
8101           ns_input_file = append2 (ns_input_file,
8102                                    build_string ([file UTF8String]));
8103           emacs_event->modifiers = modifiers;
8104           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
8105           EV_TRAILER (theEvent);
8106         }
8107       return YES;
8108     }
8109   else if ([type isEqualToString: NSURLPboardType])
8110     {
8111       NSURL *url = [NSURL URLFromPasteboard: pb];
8112       if (url == nil) return NO;
8114       emacs_event->kind = DRAG_N_DROP_EVENT;
8115       XSETINT (emacs_event->x, x);
8116       XSETINT (emacs_event->y, y);
8117       emacs_event->modifiers = modifiers;
8118       emacs_event->arg =  list2 (Qurl,
8119                                  build_string ([[url absoluteString]
8120                                                  UTF8String]));
8121       EV_TRAILER (theEvent);
8123       if ([url isFileURL] != NO)
8124         {
8125           NSString *file = [url path];
8126           ns_input_file = append2 (ns_input_file,
8127                                    build_string ([file UTF8String]));
8128         }
8129       return YES;
8130     }
8131   else if ([type isEqualToString: NSStringPboardType]
8132            || [type isEqualToString: NSTabularTextPboardType])
8133     {
8134       NSString *data;
8136       if (! (data = [pb stringForType: type]))
8137         return NO;
8139       emacs_event->kind = DRAG_N_DROP_EVENT;
8140       XSETINT (emacs_event->x, x);
8141       XSETINT (emacs_event->y, y);
8142       emacs_event->modifiers = modifiers;
8143       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
8144       EV_TRAILER (theEvent);
8145       return YES;
8146     }
8147   else
8148     {
8149       fprintf (stderr, "Invalid data type in dragging pasteboard");
8150       return NO;
8151     }
8155 - (id) validRequestorForSendType: (NSString *)typeSent
8156                       returnType: (NSString *)typeReturned
8158   NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
8159   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
8160       && typeReturned == nil)
8161     {
8162       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
8163         return self;
8164     }
8166   return [super validRequestorForSendType: typeSent
8167                                returnType: typeReturned];
8171 /* The next two methods are part of NSServicesRequests informal protocol,
8172    supposedly called when a services menu item is chosen from this app.
8173    But this should not happen because we override the services menu with our
8174    own entries which call ns-perform-service.
8175    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
8176    So let's at least stub them out until further investigation can be done. */
8178 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
8180   /* we could call ns_string_from_pasteboard(pboard) here but then it should
8181      be written into the buffer in place of the existing selection..
8182      ordinary service calls go through functions defined in ns-win.el */
8183   return NO;
8186 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
8188   NSArray *typesDeclared;
8189   Lisp_Object val;
8191   NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
8193   /* We only support NSStringPboardType */
8194   if ([types containsObject:NSStringPboardType] == NO) {
8195     return NO;
8196   }
8198   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8199   if (CONSP (val) && SYMBOLP (XCAR (val)))
8200     {
8201       val = XCDR (val);
8202       if (CONSP (val) && NILP (XCDR (val)))
8203         val = XCAR (val);
8204     }
8205   if (! STRINGP (val))
8206     return NO;
8208   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
8209   [pb declareTypes:typesDeclared owner:nil];
8210   ns_string_to_pasteboard (pb, val);
8211   return YES;
8215 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
8216    (gives a miniaturized version of the window); currently we use the latter for
8217    frames whose active buffer doesn't correspond to any file
8218    (e.g., '*scratch*') */
8219 - (instancetype)setMiniwindowImage: (BOOL) setMini
8221   id image = [[self window] miniwindowImage];
8222   NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
8224   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
8225      about "AppleDockIconEnabled" notwithstanding, however the set message
8226      below has its effect nonetheless. */
8227   if (image != emacsframe->output_data.ns->miniimage)
8228     {
8229       if (image && [image isKindOfClass: [EmacsImage class]])
8230         [image release];
8231       [[self window] setMiniwindowImage:
8232                        setMini ? emacsframe->output_data.ns->miniimage : nil];
8233     }
8235   return self;
8239 - (void) setRows: (int) r andColumns: (int) c
8241   NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
8242   rows = r;
8243   cols = c;
8246 - (int) fullscreenState
8248   return fs_state;
8251 @end  /* EmacsView */
8255 /* ==========================================================================
8257     EmacsWindow implementation
8259    ========================================================================== */
8261 @implementation EmacsWindow
8263 #ifdef NS_IMPL_COCOA
8264 - (id)accessibilityAttributeValue:(NSString *)attribute
8266   Lisp_Object str = Qnil;
8267   struct frame *f = SELECTED_FRAME ();
8268   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
8270   NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
8272   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
8273     return NSAccessibilityTextFieldRole;
8275   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
8276       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
8277     {
8278       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8279     }
8280   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
8281     {
8282       if (! NILP (BVAR (curbuf, mark_active)))
8283           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8285       if (NILP (str))
8286         {
8287           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
8288           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
8289           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
8291           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
8292             str = make_uninit_multibyte_string (range, byte_range);
8293           else
8294             str = make_uninit_string (range);
8295           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
8296              Is this a problem?  */
8297           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
8298         }
8299     }
8302   if (! NILP (str))
8303     {
8304       if (CONSP (str) && SYMBOLP (XCAR (str)))
8305         {
8306           str = XCDR (str);
8307           if (CONSP (str) && NILP (XCDR (str)))
8308             str = XCAR (str);
8309         }
8310       if (STRINGP (str))
8311         {
8312           const char *utfStr = SSDATA (str);
8313           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8314           return nsStr;
8315         }
8316     }
8318   return [super accessibilityAttributeValue:attribute];
8320 #endif /* NS_IMPL_COCOA */
8322 /* Constrain size and placement of a frame.
8324    By returning the original "frameRect", the frame is not
8325    constrained. This can lead to unwanted situations where, for
8326    example, the menu bar covers the frame.
8328    The default implementation (accessed using "super") constrains the
8329    frame to the visible area of SCREEN, minus the menu bar (if
8330    present) and the Dock.  Note that default implementation also calls
8331    windowWillResize, with the frame it thinks should have.  (This can
8332    make the frame exit maximized mode.)
8334    Note that this should work in situations where multiple monitors
8335    are present.  Common configurations are side-by-side monitors and a
8336    monitor on top of another (e.g. when a laptop is placed under a
8337    large screen). */
8338 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8340   NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8341              NSTRACE_ARG_RECT (frameRect));
8343 #ifdef NS_IMPL_COCOA
8344 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
8345   // If separate spaces is on, it is like each screen is independent.  There is
8346   // no spanning of frames across screens.
8347   if (
8348 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
8349       [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)] &&
8350 #endif
8351       [NSScreen screensHaveSeparateSpaces])
8352     {
8353       NSTRACE_MSG ("Screens have separate spaces");
8354       frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8355       NSTRACE_RETURN_RECT (frameRect);
8356       return frameRect;
8357     }
8358   else
8359 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */
8361     // Check that the proposed frameRect is visible in at least one
8362     // screen.  If it is not, ask the system to reposition it (only
8363     // for non-child windows).
8365     if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe))
8366     {
8367       NSArray *screens = [NSScreen screens];
8368       NSUInteger nr_screens = [screens count];
8370       int i;
8371       BOOL frame_on_screen = NO;
8373       for (i = 0; i < nr_screens; ++i)
8374         {
8375           NSScreen *s = [screens objectAtIndex: i];
8376           NSRect scrRect = [s frame];
8378           if (NSIntersectsRect(frameRect, scrRect))
8379             {
8380               frame_on_screen = YES;
8381               break;
8382             }
8383         }
8385       if (!frame_on_screen)
8386         {
8387           NSTRACE_MSG ("Frame outside screens; constraining");
8388           frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8389           NSTRACE_RETURN_RECT (frameRect);
8390           return frameRect;
8391         }
8392     }
8393 #endif
8395   return constrain_frame_rect(frameRect,
8396                               [(EmacsView *)[self delegate] isFullscreen]);
8400 - (void)performZoom:(id)sender
8402   NSTRACE ("[EmacsWindow performZoom:]");
8404   return [super performZoom:sender];
8407 - (void)zoom:(id)sender
8409   NSTRACE ("[EmacsWindow zoom:]");
8411   ns_update_auto_hide_menu_bar();
8413   // Below are three zoom implementations.  In the final commit, the
8414   // idea is that the last should be included.
8416 #if 0
8417   // Native zoom done using the standard zoom animation.  Size of the
8418   // resulting frame reduced to accommodate the Dock and, if present,
8419   // the menu-bar.
8420   [super zoom:sender];
8422 #elif 0
8423   // Native zoom done using the standard zoom animation, plus an
8424   // explicit resize to cover the full screen, except the menu-bar and
8425   // dock, if present.
8426   [super zoom:sender];
8428   // After the native zoom, resize the resulting frame to fill the
8429   // entire screen, except the menu-bar.
8430   //
8431   // This works for all practical purposes.  (The only minor oddity is
8432   // when transiting from full-height frame to a maximized, the
8433   // animation reduces the height of the frame slightly (to the 4
8434   // pixels needed to accommodate the Doc) before it snaps back into
8435   // full height.  The user would need a very trained eye to spot
8436   // this.)
8437   NSScreen * screen = [self screen];
8438   if (screen != nil)
8439     {
8440       int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8442       NSTRACE_FSTYPE ("fullscreenState", fs_state);
8444       NSRect sr = [screen frame];
8445       struct EmacsMargins margins
8446         = ns_screen_margins_ignoring_hidden_dock(screen);
8448       NSRect wr = [self frame];
8449       NSTRACE_RECT ("Rect after zoom", wr);
8451       NSRect newWr = wr;
8453       if (fs_state == FULLSCREEN_MAXIMIZED
8454           || fs_state == FULLSCREEN_HEIGHT)
8455         {
8456           newWr.origin.y = sr.origin.y + margins.bottom;
8457           newWr.size.height = sr.size.height - margins.top - margins.bottom;
8458         }
8460       if (fs_state == FULLSCREEN_MAXIMIZED
8461           || fs_state == FULLSCREEN_WIDTH)
8462         {
8463           newWr.origin.x = sr.origin.x + margins.left;
8464           newWr.size.width = sr.size.width - margins.right - margins.left;
8465         }
8467       if (newWr.size.width     != wr.size.width
8468           || newWr.size.height != wr.size.height
8469           || newWr.origin.x    != wr.origin.x
8470           || newWr.origin.y    != wr.origin.y)
8471         {
8472           NSTRACE_MSG ("New frame different");
8473           [self setFrame: newWr display: NO];
8474         }
8475     }
8476 #else
8477   // Non-native zoom which is done instantaneously.  The resulting
8478   // frame covers the entire screen, except the menu-bar and dock, if
8479   // present.
8480   NSScreen * screen = [self screen];
8481   if (screen != nil)
8482     {
8483       NSRect sr = [screen frame];
8484       struct EmacsMargins margins
8485         = ns_screen_margins_ignoring_hidden_dock(screen);
8487       sr.size.height -= (margins.top + margins.bottom);
8488       sr.size.width  -= (margins.left + margins.right);
8489       sr.origin.x += margins.left;
8490       sr.origin.y += margins.bottom;
8492       sr = [[self delegate] windowWillUseStandardFrame:self
8493                                           defaultFrame:sr];
8494       [self setFrame: sr display: NO];
8495     }
8496 #endif
8499 - (void)setFrame:(NSRect)windowFrame
8500          display:(BOOL)displayViews
8502   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8503            NSTRACE_ARG_RECT (windowFrame), displayViews);
8505   [super setFrame:windowFrame display:displayViews];
8508 - (void)setFrame:(NSRect)windowFrame
8509          display:(BOOL)displayViews
8510          animate:(BOOL)performAnimation
8512   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8513            " display:%d performAnimation:%d]",
8514            NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8516   [super setFrame:windowFrame display:displayViews animate:performAnimation];
8519 - (void)setFrameTopLeftPoint:(NSPoint)point
8521   NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8522            NSTRACE_ARG_POINT (point));
8524   [super setFrameTopLeftPoint:point];
8527 - (BOOL)canBecomeKeyWindow
8529   return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8531 @end /* EmacsWindow */
8534 @implementation EmacsFSWindow
8536 - (BOOL)canBecomeKeyWindow
8538   return YES;
8541 - (BOOL)canBecomeMainWindow
8543   return YES;
8546 @end
8548 /* ==========================================================================
8550     EmacsScroller implementation
8552    ========================================================================== */
8555 @implementation EmacsScroller
8557 /* for repeat button push */
8558 #define SCROLL_BAR_FIRST_DELAY 0.5
8559 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8561 + (CGFloat) scrollerWidth
8563   /* TODO: if we want to allow variable widths, this is the place to do it,
8564            however neither GNUstep nor Cocoa support it very well */
8565   CGFloat r;
8566 #if defined (NS_IMPL_COCOA) \
8567   && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
8568 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8569   if ([NSScroller respondsToSelector:
8570                     @selector(scrollerWidthForControlSize:scrollerStyle:)])
8571 #endif
8572     r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8573                                   scrollerStyle: NSScrollerStyleLegacy];
8574 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8575   else
8576 #endif
8577 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
8578 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
8579   || defined (NS_IMPL_GNUSTEP)
8580     r = [NSScroller scrollerWidth];
8581 #endif
8582   return r;
8585 - (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin
8587   NSTRACE ("[EmacsScroller initFrame: window:]");
8589   if (r.size.width > r.size.height)
8590       horizontal = YES;
8591   else
8592       horizontal = NO;
8594   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8595   [self setContinuous: YES];
8596   [self setEnabled: YES];
8598   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8599      locked against the top and bottom edges, and right edge on macOS, where
8600      scrollers are on right. */
8601 #ifdef NS_IMPL_GNUSTEP
8602   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8603 #else
8604   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8605 #endif
8607   window = XWINDOW (nwin);
8608   condemned = NO;
8609   if (horizontal)
8610     pixel_length = NSWidth (r);
8611   else
8612     pixel_length = NSHeight (r);
8613   if (pixel_length == 0) pixel_length = 1;
8614   min_portion = 20 / pixel_length;
8616   frame = XFRAME (window->frame);
8617   if (FRAME_LIVE_P (frame))
8618     {
8619       int i;
8620       EmacsView *view = FRAME_NS_VIEW (frame);
8621       NSView *sview = [[view window] contentView];
8622       NSArray *subs = [sview subviews];
8624       /* disable optimization stopping redraw of other scrollbars */
8625       view->scrollbarsNeedingUpdate = 0;
8626       for (i =[subs count]-1; i >= 0; i--)
8627         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8628           view->scrollbarsNeedingUpdate++;
8629       [sview addSubview: self];
8630     }
8632 /*  [self setFrame: r]; */
8634   return self;
8638 - (void)setFrame: (NSRect)newRect
8640   NSTRACE ("[EmacsScroller setFrame:]");
8642 /*  block_input (); */
8643   if (horizontal)
8644     pixel_length = NSWidth (newRect);
8645   else
8646     pixel_length = NSHeight (newRect);
8647   if (pixel_length == 0) pixel_length = 1;
8648   min_portion = 20 / pixel_length;
8649   [super setFrame: newRect];
8650 /*  unblock_input (); */
8654 - (void)dealloc
8656   NSTRACE ("[EmacsScroller dealloc]");
8657   if (window)
8658     {
8659       if (horizontal)
8660         wset_horizontal_scroll_bar (window, Qnil);
8661       else
8662         wset_vertical_scroll_bar (window, Qnil);
8663     }
8664   window = 0;
8665   [super dealloc];
8669 - (instancetype)condemn
8671   NSTRACE ("[EmacsScroller condemn]");
8672   condemned =YES;
8673   return self;
8677 - (instancetype)reprieve
8679   NSTRACE ("[EmacsScroller reprieve]");
8680   condemned =NO;
8681   return self;
8685 -(bool)judge
8687   NSTRACE ("[EmacsScroller judge]");
8688   bool ret = condemned;
8689   if (condemned)
8690     {
8691       EmacsView *view;
8692       block_input ();
8693       /* ensure other scrollbar updates after deletion */
8694       view = (EmacsView *)FRAME_NS_VIEW (frame);
8695       if (view != nil)
8696         view->scrollbarsNeedingUpdate++;
8697       if (window)
8698         {
8699           if (horizontal)
8700             wset_horizontal_scroll_bar (window, Qnil);
8701           else
8702             wset_vertical_scroll_bar (window, Qnil);
8703         }
8704       window = 0;
8705       [self removeFromSuperview];
8706       [self release];
8707       unblock_input ();
8708     }
8709   return ret;
8713 - (void)resetCursorRects
8715   NSRect visible = [self visibleRect];
8716   NSTRACE ("[EmacsScroller resetCursorRects]");
8718   if (!NSIsEmptyRect (visible))
8719     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8720   [[NSCursor arrowCursor] setOnMouseEntered: YES];
8724 - (int) checkSamePosition: (int) position portion: (int) portion
8725                     whole: (int) whole
8727   return em_position ==position && em_portion ==portion && em_whole ==whole
8728     && portion != whole; /* needed for resize empty buf */
8732 - (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole
8734   NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8736   em_position = position;
8737   em_portion = portion;
8738   em_whole = whole;
8740   if (portion >= whole)
8741     {
8742 #ifdef NS_IMPL_COCOA
8743       [self setKnobProportion: 1.0];
8744       [self setDoubleValue: 1.0];
8745 #else
8746       [self setFloatValue: 0.0 knobProportion: 1.0];
8747 #endif
8748     }
8749   else
8750     {
8751       float pos;
8752       CGFloat por;
8753       portion = max ((float)whole*min_portion/pixel_length, portion);
8754       pos = (float)position / (whole - portion);
8755       por = (CGFloat)portion/whole;
8756 #ifdef NS_IMPL_COCOA
8757       [self setKnobProportion: por];
8758       [self setDoubleValue: pos];
8759 #else
8760       [self setFloatValue: pos knobProportion: por];
8761 #endif
8762     }
8764   return self;
8767 /* set up emacs_event */
8768 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8770   Lisp_Object win;
8772   NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8774   if (!emacs_event)
8775     return;
8777   emacs_event->part = last_hit_part;
8778   emacs_event->code = 0;
8779   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8780   XSETWINDOW (win, window);
8781   emacs_event->frame_or_window = win;
8782   emacs_event->timestamp = EV_TIMESTAMP (e);
8783   emacs_event->arg = Qnil;
8785   if (horizontal)
8786     {
8787       emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8788       XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8789       XSETINT (emacs_event->y, em_whole);
8790     }
8791   else
8792     {
8793       emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8794       XSETINT (emacs_event->x, loc);
8795       XSETINT (emacs_event->y, pixel_length-20);
8796     }
8798   if (q_event_ptr)
8799     {
8800       n_emacs_events_pending++;
8801       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8802     }
8803   else
8804     hold_event (emacs_event);
8805   EVENT_INIT (*emacs_event);
8806   ns_send_appdefined (-1);
8810 /* called manually thru timer to implement repeated button action w/hold-down */
8811 - (instancetype)repeatScroll: (NSTimer *)scrollEntry
8813   NSEvent *e = [[self window] currentEvent];
8814   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
8815   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8817   NSTRACE ("[EmacsScroller repeatScroll:]");
8819   /* clear timer if need be */
8820   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8821     {
8822         [scroll_repeat_entry invalidate];
8823         [scroll_repeat_entry release];
8824         scroll_repeat_entry = nil;
8826         if (inKnob)
8827           return self;
8829         scroll_repeat_entry
8830           = [[NSTimer scheduledTimerWithTimeInterval:
8831                         SCROLL_BAR_CONTINUOUS_DELAY
8832                                             target: self
8833                                           selector: @selector (repeatScroll:)
8834                                           userInfo: 0
8835                                            repeats: YES]
8836               retain];
8837     }
8839   [self sendScrollEventAtLoc: 0 fromEvent: e];
8840   return self;
8844 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
8845    mouseDragged events without going into a modal loop. */
8846 - (void)mouseDown: (NSEvent *)e
8848   NSRect sr, kr;
8849   /* hitPart is only updated AFTER event is passed on */
8850   NSScrollerPart part = [self testPart: [e locationInWindow]];
8851   CGFloat loc, kloc, pos UNINIT;
8852   int edge = 0;
8854   NSTRACE ("[EmacsScroller mouseDown:]");
8856   switch (part)
8857     {
8858     case NSScrollerDecrementPage:
8859       last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
8860     case NSScrollerIncrementPage:
8861       last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
8862     case NSScrollerDecrementLine:
8863       last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
8864     case NSScrollerIncrementLine:
8865       last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
8866     case NSScrollerKnob:
8867       last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
8868     case NSScrollerKnobSlot:  /* GNUstep-only */
8869       last_hit_part = scroll_bar_move_ratio; break;
8870     default:  /* NSScrollerNoPart? */
8871       fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
8872                (long) part);
8873       return;
8874     }
8876   if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
8877     {
8878       /* handle, or on GNUstep possibly slot */
8879       NSEvent *fake_event;
8880       int length;
8882       /* compute float loc in slot and mouse offset on knob */
8883       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8884                       toView: nil];
8885       if (horizontal)
8886         {
8887           length = NSWidth (sr);
8888           loc = ([e locationInWindow].x - NSMinX (sr));
8889         }
8890       else
8891         {
8892           length = NSHeight (sr);
8893           loc = length - ([e locationInWindow].y - NSMinY (sr));
8894         }
8896       if (loc <= 0.0)
8897         {
8898           loc = 0.0;
8899           edge = -1;
8900         }
8901       else if (loc >= length)
8902         {
8903           loc = length;
8904           edge = 1;
8905         }
8907       if (edge)
8908         kloc = 0.5 * edge;
8909       else
8910         {
8911           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8912                           toView: nil];
8913           if (horizontal)
8914             kloc = ([e locationInWindow].x - NSMinX (kr));
8915           else
8916             kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8917         }
8918       last_mouse_offset = kloc;
8920       if (part != NSScrollerKnob)
8921         /* this is a slot click on GNUstep: go straight there */
8922         pos = loc;
8924       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8925       fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
8926                                       location: [e locationInWindow]
8927                                  modifierFlags: [e modifierFlags]
8928                                      timestamp: [e timestamp]
8929                                   windowNumber: [e windowNumber]
8930                                        context: nil
8931                                    eventNumber: [e eventNumber]
8932                                     clickCount: [e clickCount]
8933                                       pressure: [e pressure]];
8934       [super mouseUp: fake_event];
8935     }
8936   else
8937     {
8938       pos = 0;      /* ignored */
8940       /* set a timer to repeat, as we can't let superclass do this modally */
8941       scroll_repeat_entry
8942         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8943                                             target: self
8944                                           selector: @selector (repeatScroll:)
8945                                           userInfo: 0
8946                                            repeats: YES]
8947             retain];
8948     }
8950   if (part != NSScrollerKnob)
8951     [self sendScrollEventAtLoc: pos fromEvent: e];
8955 /* Called as we manually track scroller drags, rather than superclass. */
8956 - (void)mouseDragged: (NSEvent *)e
8958     NSRect sr;
8959     double loc, pos;
8960     int length;
8962     NSTRACE ("[EmacsScroller mouseDragged:]");
8964       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8965                       toView: nil];
8967       if (horizontal)
8968         {
8969           length = NSWidth (sr);
8970           loc = ([e locationInWindow].x - NSMinX (sr));
8971         }
8972       else
8973         {
8974           length = NSHeight (sr);
8975           loc = length - ([e locationInWindow].y - NSMinY (sr));
8976         }
8978       if (loc <= 0.0)
8979         {
8980           loc = 0.0;
8981         }
8982       else if (loc >= length + last_mouse_offset)
8983         {
8984           loc = length + last_mouse_offset;
8985         }
8987       pos = (loc - last_mouse_offset);
8988       [self sendScrollEventAtLoc: pos fromEvent: e];
8992 - (void)mouseUp: (NSEvent *)e
8994   NSTRACE ("[EmacsScroller mouseUp:]");
8996   if (scroll_repeat_entry)
8997     {
8998       [scroll_repeat_entry invalidate];
8999       [scroll_repeat_entry release];
9000       scroll_repeat_entry = nil;
9001     }
9002   last_hit_part = scroll_bar_above_handle;
9006 /* treat scrollwheel events in the bar as though they were in the main window */
9007 - (void) scrollWheel: (NSEvent *)theEvent
9009   NSTRACE ("[EmacsScroller scrollWheel:]");
9011   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
9012   [view mouseDown: theEvent];
9015 @end  /* EmacsScroller */
9018 #ifdef NS_IMPL_GNUSTEP
9019 /* Dummy class to get rid of startup warnings.  */
9020 @implementation EmacsDocument
9022 @end
9023 #endif
9026 /* ==========================================================================
9028    Font-related functions; these used to be in nsfaces.m
9030    ========================================================================== */
9033 Lisp_Object
9034 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
9036   struct font *font = XFONT_OBJECT (font_object);
9037   EmacsView *view = FRAME_NS_VIEW (f);
9038   int font_ascent, font_descent;
9040   if (fontset < 0)
9041     fontset = fontset_from_font (font_object);
9042   FRAME_FONTSET (f) = fontset;
9044   if (FRAME_FONT (f) == font)
9045     /* This font is already set in frame F.  There's nothing more to
9046        do.  */
9047     return font_object;
9049   FRAME_FONT (f) = font;
9051   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
9052   FRAME_COLUMN_WIDTH (f) = font->average_width;
9053   get_font_ascent_descent (font, &font_ascent, &font_descent);
9054   FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
9056   /* Compute the scroll bar width in character columns.  */
9057   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
9058     {
9059       int wid = FRAME_COLUMN_WIDTH (f);
9060       FRAME_CONFIG_SCROLL_BAR_COLS (f)
9061         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
9062     }
9063   else
9064     {
9065       int wid = FRAME_COLUMN_WIDTH (f);
9066       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
9067     }
9069   /* Compute the scroll bar height in character lines.  */
9070   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
9071     {
9072       int height = FRAME_LINE_HEIGHT (f);
9073       FRAME_CONFIG_SCROLL_BAR_LINES (f)
9074         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
9075     }
9076   else
9077     {
9078       int height = FRAME_LINE_HEIGHT (f);
9079       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
9080     }
9082   /* Now make the frame display the given font.  */
9083   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
9084     adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
9085                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
9086                        false, Qfont);
9088   return font_object;
9092 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
9093 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
9094          in 1.43. */
9096 const char *
9097 ns_xlfd_to_fontname (const char *xlfd)
9098 /* --------------------------------------------------------------------------
9099     Convert an X font name (XLFD) to an NS font name.
9100     Only family is used.
9101     The string returned is temporarily allocated.
9102    -------------------------------------------------------------------------- */
9104   char *name = xmalloc (180);
9105   int i, len;
9106   const char *ret;
9108   if (!strncmp (xlfd, "--", 2))
9109     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
9110   else
9111     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
9113   /* stopgap for malformed XLFD input */
9114   if (strlen (name) == 0)
9115     strcpy (name, "Monaco");
9117   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
9118      also uppercase after '-' or ' ' */
9119   name[0] = c_toupper (name[0]);
9120   for (len =strlen (name), i =0; i<len; i++)
9121     {
9122       if (name[i] == '$')
9123         {
9124           name[i] = '-';
9125           if (i+1<len)
9126             name[i+1] = c_toupper (name[i+1]);
9127         }
9128       else if (name[i] == '_')
9129         {
9130           name[i] = ' ';
9131           if (i+1<len)
9132             name[i+1] = c_toupper (name[i+1]);
9133         }
9134     }
9135 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
9136   ret = [[NSString stringWithUTF8String: name] UTF8String];
9137   xfree (name);
9138   return ret;
9142 void
9143 syms_of_nsterm (void)
9145   NSTRACE ("syms_of_nsterm");
9147   ns_antialias_threshold = 10.0;
9149   /* from 23+ we need to tell emacs what modifiers there are.. */
9150   DEFSYM (Qmodifier_value, "modifier-value");
9151   DEFSYM (Qalt, "alt");
9152   DEFSYM (Qhyper, "hyper");
9153   DEFSYM (Qmeta, "meta");
9154   DEFSYM (Qsuper, "super");
9155   DEFSYM (Qcontrol, "control");
9156   DEFSYM (QUTF8_STRING, "UTF8_STRING");
9158   DEFSYM (Qfile, "file");
9159   DEFSYM (Qurl, "url");
9161   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
9162   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
9163   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
9164   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
9165   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
9167   DEFVAR_LISP ("ns-input-file", ns_input_file,
9168               "The file specified in the last NS event.");
9169   ns_input_file =Qnil;
9171   DEFVAR_LISP ("ns-working-text", ns_working_text,
9172               "String for visualizing working composition sequence.");
9173   ns_working_text =Qnil;
9175   DEFVAR_LISP ("ns-input-font", ns_input_font,
9176               "The font specified in the last NS event.");
9177   ns_input_font =Qnil;
9179   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
9180               "The fontsize specified in the last NS event.");
9181   ns_input_fontsize =Qnil;
9183   DEFVAR_LISP ("ns-input-line", ns_input_line,
9184                "The line specified in the last NS event.");
9185   ns_input_line =Qnil;
9187   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
9188                "The service name specified in the last NS event.");
9189   ns_input_spi_name =Qnil;
9191   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
9192                "The service argument specified in the last NS event.");
9193   ns_input_spi_arg =Qnil;
9195   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
9196                "This variable describes the behavior of the alternate or option key.\n\
9197 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9198 that key.\n\
9199 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9200 at all, allowing it to be used at a lower level for accented character entry.");
9201   ns_alternate_modifier = Qmeta;
9203   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
9204                "This variable describes the behavior of the right alternate or option key.\n\
9205 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9206 that key.\n\
9207 Set to left means be the same key as `ns-alternate-modifier'.\n\
9208 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9209 at all, allowing it to be used at a lower level for accented character entry.");
9210   ns_right_alternate_modifier = Qleft;
9212   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
9213                "This variable describes the behavior of the command key.\n\
9214 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9215 that key.");
9216   ns_command_modifier = Qsuper;
9218   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
9219                "This variable describes the behavior of the right command key.\n\
9220 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9221 that key.\n\
9222 Set to left means be the same key as `ns-command-modifier'.\n\
9223 Set to none means that the command / option key is not interpreted by Emacs\n\
9224 at all, allowing it to be used at a lower level for accented character entry.");
9225   ns_right_command_modifier = Qleft;
9227   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
9228                "This variable describes the behavior of the control key.\n\
9229 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9230 that key.");
9231   ns_control_modifier = Qcontrol;
9233   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
9234                "This variable describes the behavior of the right control key.\n\
9235 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9236 that key.\n\
9237 Set to left means be the same key as `ns-control-modifier'.\n\
9238 Set to none means that the control / option key is not interpreted by Emacs\n\
9239 at all, allowing it to be used at a lower level for accented character entry.");
9240   ns_right_control_modifier = Qleft;
9242   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
9243                "This variable describes the behavior of the function key (on laptops).\n\
9244 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9245 that key.\n\
9246 Set to none means that the function key is not interpreted by Emacs at all,\n\
9247 allowing it to be used at a lower level for accented character entry.");
9248   ns_function_modifier = Qnone;
9250   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
9251                "Non-nil (the default) means to render text antialiased.");
9252   ns_antialias_text = Qt;
9254   DEFVAR_LISP ("ns-use-thin-smoothing", ns_use_thin_smoothing,
9255                "Non-nil turns on a font smoothing method that produces thinner strokes.");
9256   ns_use_thin_smoothing = Qnil;
9258   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
9259                "Whether to confirm application quit using dialog.");
9260   ns_confirm_quit = Qnil;
9262   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
9263                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
9264 Only works on Mac OS X 10.6 or later.  */);
9265   ns_auto_hide_menu_bar = Qnil;
9267   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
9268      doc: /*Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
9269 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
9270 multiple monitors, but lacks tool bar.  This variable is ignored on
9271 Mac OS X < 10.7.  Default is t.  */);
9272   ns_use_native_fullscreen = YES;
9273   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
9275   DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
9276      doc: /*Non-nil means use animation on non-native fullscreen.
9277 For native fullscreen, this does nothing.
9278 Default is nil.  */);
9279   ns_use_fullscreen_animation = NO;
9281   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
9282      doc: /*Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
9283 Note that this does not apply to images.
9284 This variable is ignored on Mac OS X < 10.7 and GNUstep.  */);
9285   ns_use_srgb_colorspace = YES;
9287   DEFVAR_BOOL ("ns-use-mwheel-acceleration",
9288                ns_use_mwheel_acceleration,
9289      doc: /*Non-nil means use macOS's standard mouse wheel acceleration.
9290 This variable is ignored on macOS < 10.7 and GNUstep.  Default is t.  */);
9291   ns_use_mwheel_acceleration = YES;
9293   DEFVAR_LISP ("ns-mwheel-line-height", ns_mwheel_line_height,
9294                doc: /*The number of pixels touchpad scrolling considers one line.
9295 Nil or a non-number means use the default frame line height.
9296 This variable is ignored on macOS < 10.7 and GNUstep.  Default is nil.  */);
9297   ns_mwheel_line_height = Qnil;
9299   DEFVAR_BOOL ("ns-use-mwheel-momentum", ns_use_mwheel_momentum,
9300                doc: /*Non-nil means mouse wheel scrolling uses momentum.
9301 This variable is ignored on macOS < 10.7 and GNUstep.  Default is t.  */);
9302   ns_use_mwheel_momentum = YES;
9304   /* TODO: move to common code */
9305   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
9306                doc: /* Which toolkit scroll bars Emacs uses, if any.
9307 A value of nil means Emacs doesn't use toolkit scroll bars.
9308 With the X Window system, the value is a symbol describing the
9309 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
9310 With MS Windows or Nextstep, the value is t.  */);
9311   Vx_toolkit_scroll_bars = Qt;
9313   DEFVAR_BOOL ("x-use-underline-position-properties",
9314                x_use_underline_position_properties,
9315      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
9316 A value of nil means ignore them.  If you encounter fonts with bogus
9317 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
9318 to 4.1, set this to nil. */);
9319   x_use_underline_position_properties = 0;
9321   DEFVAR_BOOL ("x-underline-at-descent-line",
9322                x_underline_at_descent_line,
9323      doc: /* Non-nil means to draw the underline at the same place as the descent line.
9324 A value of nil means to draw the underline according to the value of the
9325 variable `x-use-underline-position-properties', which is usually at the
9326 baseline level.  The default value is nil.  */);
9327   x_underline_at_descent_line = 0;
9329   /* Tell Emacs about this window system.  */
9330   Fprovide (Qns, Qnil);
9332   DEFSYM (Qcocoa, "cocoa");
9333   DEFSYM (Qgnustep, "gnustep");
9335 #ifdef NS_IMPL_COCOA
9336   Fprovide (Qcocoa, Qnil);
9337   syms_of_macfont ();
9338 #else
9339   Fprovide (Qgnustep, Qnil);
9340   syms_of_nsfont ();
9341 #endif