Warn about incomplete untarring of link files
[emacs.git] / src / nsterm.m
blob1d038cdcb05e43579d5e1d23fc14fca4c70a8360
1 /* NeXT/Open/GNUstep / macOS communication module.      -*- coding: utf-8 -*-
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2017 Free Software
4 Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or (at
11 your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30    interpretation of even the system includes. */
31 #include <config.h>
33 #include <fcntl.h>
34 #include <math.h>
35 #include <pthread.h>
36 #include <sys/types.h>
37 #include <time.h>
38 #include <signal.h>
39 #include <unistd.h>
41 #include <c-ctype.h>
42 #include <c-strcase.h>
43 #include <ftoastr.h>
45 #include "lisp.h"
46 #include "blockinput.h"
47 #include "sysselect.h"
48 #include "nsterm.h"
49 #include "systime.h"
50 #include "character.h"
51 #include "fontset.h"
52 #include "composite.h"
53 #include "ccl.h"
55 #include "termhooks.h"
56 #include "termchar.h"
57 #include "menu.h"
58 #include "window.h"
59 #include "keyboard.h"
60 #include "buffer.h"
61 #include "font.h"
63 #ifdef NS_IMPL_GNUSTEP
64 #include "process.h"
65 #endif
67 #ifdef NS_IMPL_COCOA
68 #include "macfont.h"
69 #endif
71 static EmacsMenu *dockMenu;
72 #ifdef NS_IMPL_COCOA
73 static EmacsMenu *mainMenu;
74 #endif
76 /* ==========================================================================
78    NSTRACE, Trace support.
80    ========================================================================== */
82 #if NSTRACE_ENABLED
84 /* The following use "volatile" since they can be accessed from
85    parallel threads. */
86 volatile int nstrace_num = 0;
87 volatile int nstrace_depth = 0;
89 /* When 0, no trace is emitted.  This is used by NSTRACE_WHEN and
90    NSTRACE_UNLESS to silence functions called.
92    TODO: This should really be a thread-local variable, to avoid that
93    a function with disabled trace thread silence trace output in
94    another.  However, in practice this seldom is a problem. */
95 volatile int nstrace_enabled_global = 1;
97 /* Called when nstrace_enabled goes out of scope. */
98 void nstrace_leave(int * pointer_to_nstrace_enabled)
100   if (*pointer_to_nstrace_enabled)
101     {
102       --nstrace_depth;
103     }
107 /* Called when nstrace_saved_enabled_global goes out of scope. */
108 void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
110   nstrace_enabled_global = *pointer_to_saved_enabled_global;
114 char const * nstrace_fullscreen_type_name (int fs_type)
116   switch (fs_type)
117     {
118     case -1:                   return "-1";
119     case FULLSCREEN_NONE:      return "FULLSCREEN_NONE";
120     case FULLSCREEN_WIDTH:     return "FULLSCREEN_WIDTH";
121     case FULLSCREEN_HEIGHT:    return "FULLSCREEN_HEIGHT";
122     case FULLSCREEN_BOTH:      return "FULLSCREEN_BOTH";
123     case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
124     default:                   return "FULLSCREEN_?????";
125     }
127 #endif
130 /* ==========================================================================
132    NSColor, EmacsColor category.
134    ========================================================================== */
135 @implementation NSColor (EmacsColor)
136 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
137                          blue:(CGFloat)blue alpha:(CGFloat)alpha
139 #ifdef NS_IMPL_COCOA
140 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
141   if (ns_use_srgb_colorspace)
142       return [NSColor colorWithSRGBRed: red
143                                  green: green
144                                   blue: blue
145                                  alpha: alpha];
146 #endif
147 #endif
148   return [NSColor colorWithCalibratedRed: red
149                                    green: green
150                                     blue: blue
151                                    alpha: alpha];
154 - (NSColor *)colorUsingDefaultColorSpace
156 #ifdef NS_IMPL_COCOA
157 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
158   if (ns_use_srgb_colorspace)
159     return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
160 #endif
161 #endif
162   return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
165 @end
167 /* ==========================================================================
169     Local declarations
171    ========================================================================== */
173 /* Convert a symbol indexed with an NSxxx value to a value as defined
174    in keyboard.c (lispy_function_key). I hope this is a correct way
175    of doing things... */
176 static unsigned convert_ns_to_X_keysym[] =
178   NSHomeFunctionKey,            0x50,
179   NSLeftArrowFunctionKey,       0x51,
180   NSUpArrowFunctionKey,         0x52,
181   NSRightArrowFunctionKey,      0x53,
182   NSDownArrowFunctionKey,       0x54,
183   NSPageUpFunctionKey,          0x55,
184   NSPageDownFunctionKey,        0x56,
185   NSEndFunctionKey,             0x57,
186   NSBeginFunctionKey,           0x58,
187   NSSelectFunctionKey,          0x60,
188   NSPrintFunctionKey,           0x61,
189   NSClearLineFunctionKey,       0x0B,
190   NSExecuteFunctionKey,         0x62,
191   NSInsertFunctionKey,          0x63,
192   NSUndoFunctionKey,            0x65,
193   NSRedoFunctionKey,            0x66,
194   NSMenuFunctionKey,            0x67,
195   NSFindFunctionKey,            0x68,
196   NSHelpFunctionKey,            0x6A,
197   NSBreakFunctionKey,           0x6B,
199   NSF1FunctionKey,              0xBE,
200   NSF2FunctionKey,              0xBF,
201   NSF3FunctionKey,              0xC0,
202   NSF4FunctionKey,              0xC1,
203   NSF5FunctionKey,              0xC2,
204   NSF6FunctionKey,              0xC3,
205   NSF7FunctionKey,              0xC4,
206   NSF8FunctionKey,              0xC5,
207   NSF9FunctionKey,              0xC6,
208   NSF10FunctionKey,             0xC7,
209   NSF11FunctionKey,             0xC8,
210   NSF12FunctionKey,             0xC9,
211   NSF13FunctionKey,             0xCA,
212   NSF14FunctionKey,             0xCB,
213   NSF15FunctionKey,             0xCC,
214   NSF16FunctionKey,             0xCD,
215   NSF17FunctionKey,             0xCE,
216   NSF18FunctionKey,             0xCF,
217   NSF19FunctionKey,             0xD0,
218   NSF20FunctionKey,             0xD1,
219   NSF21FunctionKey,             0xD2,
220   NSF22FunctionKey,             0xD3,
221   NSF23FunctionKey,             0xD4,
222   NSF24FunctionKey,             0xD5,
224   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
225   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
226   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
228   NSTabCharacter,               0x09,
229   0x19,                         0x09,  /* left tab->regular since pass shift */
230   NSCarriageReturnCharacter,    0x0D,
231   NSNewlineCharacter,           0x0D,
232   NSEnterCharacter,             0x8D,
234   0x41|NSEventModifierFlagNumericPad,   0xAE,  /* KP_Decimal */
235   0x43|NSEventModifierFlagNumericPad,   0xAA,  /* KP_Multiply */
236   0x45|NSEventModifierFlagNumericPad,   0xAB,  /* KP_Add */
237   0x4B|NSEventModifierFlagNumericPad,   0xAF,  /* KP_Divide */
238   0x4E|NSEventModifierFlagNumericPad,   0xAD,  /* KP_Subtract */
239   0x51|NSEventModifierFlagNumericPad,   0xBD,  /* KP_Equal */
240   0x52|NSEventModifierFlagNumericPad,   0xB0,  /* KP_0 */
241   0x53|NSEventModifierFlagNumericPad,   0xB1,  /* KP_1 */
242   0x54|NSEventModifierFlagNumericPad,   0xB2,  /* KP_2 */
243   0x55|NSEventModifierFlagNumericPad,   0xB3,  /* KP_3 */
244   0x56|NSEventModifierFlagNumericPad,   0xB4,  /* KP_4 */
245   0x57|NSEventModifierFlagNumericPad,   0xB5,  /* KP_5 */
246   0x58|NSEventModifierFlagNumericPad,   0xB6,  /* KP_6 */
247   0x59|NSEventModifierFlagNumericPad,   0xB7,  /* KP_7 */
248   0x5B|NSEventModifierFlagNumericPad,   0xB8,  /* KP_8 */
249   0x5C|NSEventModifierFlagNumericPad,   0xB9,  /* KP_9 */
251   0x1B,                         0x1B   /* escape */
254 /* On macOS picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
255    the maximum font size to NOT antialias.  On GNUstep there is currently
256    no way to control this behavior. */
257 float ns_antialias_threshold;
259 NSArray *ns_send_types = 0, *ns_return_types = 0;
260 static NSArray *ns_drag_types = 0;
261 NSString *ns_app_name = @"Emacs";  /* default changed later */
263 /* Display variables */
264 struct ns_display_info *x_display_list; /* Chain of existing displays */
265 long context_menu_value = 0;
267 /* display update */
268 static struct frame *ns_updating_frame;
269 static NSView *focus_view = NULL;
270 static int ns_window_num = 0;
271 #ifdef NS_IMPL_GNUSTEP
272 static NSRect uRect;            // TODO: This is dead, remove it?
273 #endif
274 static BOOL gsaved = NO;
275 static BOOL ns_fake_keydown = NO;
276 #ifdef NS_IMPL_COCOA
277 static BOOL ns_menu_bar_is_hidden = NO;
278 #endif
279 /*static int debug_lock = 0; */
281 /* event loop */
282 #define NO_APPDEFINED_DATA (-8)
283 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
284 static NSTimer *timed_entry = 0;
285 static NSTimer *scroll_repeat_entry = nil;
286 static NSAutoreleasePool *outerpool;
287 static struct input_event *emacs_event = NULL;
288 static struct input_event *q_event_ptr = NULL;
289 static int n_emacs_events_pending = 0;
290 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
291   *ns_pending_service_args;
292 static BOOL ns_do_open_file = NO;
293 static BOOL ns_last_use_native_fullscreen;
295 /* Non-zero means that a HELP_EVENT has been generated since Emacs
296    start.  */
298 static BOOL any_help_event_p = NO;
300 static struct {
301   struct input_event *q;
302   int nr, cap;
303 } hold_event_q = {
304   NULL, 0, 0
307 static NSString *represented_filename = nil;
308 static struct frame *represented_frame = 0;
310 #ifdef NS_IMPL_COCOA
312  * State for pending menu activation:
313  * MENU_NONE     Normal state
314  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
315  *               run lisp to update the menu.
316  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
317  *               will open.
318  */
319 #define MENU_NONE 0
320 #define MENU_PENDING 1
321 #define MENU_OPENING 2
322 static int menu_will_open_state = MENU_NONE;
324 /* Saved position for menu click.  */
325 static CGPoint menu_mouse_point;
326 #endif
328 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
329 #define NS_FUNCTION_KEY_MASK 0x800000
330 #define NSLeftControlKeyMask    (0x000001 | NSEventModifierFlagControl)
331 #define NSRightControlKeyMask   (0x002000 | NSEventModifierFlagControl)
332 #define NSLeftCommandKeyMask    (0x000008 | NSEventModifierFlagCommand)
333 #define NSRightCommandKeyMask   (0x000010 | NSEventModifierFlagCommand)
334 #define NSLeftAlternateKeyMask  (0x000020 | NSEventModifierFlagOption)
335 #define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption)
336 #define EV_MODIFIERS2(flags)                          \
337     (((flags & NSEventModifierFlagHelp) ?           \
338            hyper_modifier : 0)                        \
339      | (!EQ (ns_right_alternate_modifier, Qleft) && \
340         ((flags & NSRightAlternateKeyMask) \
341          == NSRightAlternateKeyMask) ? \
342            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
343      | ((flags & NSEventModifierFlagOption) ?                 \
344            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
345      | ((flags & NSEventModifierFlagShift) ?     \
346            shift_modifier : 0)                        \
347      | (!EQ (ns_right_control_modifier, Qleft) && \
348         ((flags & NSRightControlKeyMask) \
349          == NSRightControlKeyMask) ? \
350            parse_solitary_modifier (ns_right_control_modifier) : 0) \
351      | ((flags & NSEventModifierFlagControl) ?      \
352            parse_solitary_modifier (ns_control_modifier) : 0)     \
353      | ((flags & NS_FUNCTION_KEY_MASK) ?  \
354            parse_solitary_modifier (ns_function_modifier) : 0)    \
355      | (!EQ (ns_right_command_modifier, Qleft) && \
356         ((flags & NSRightCommandKeyMask) \
357          == NSRightCommandKeyMask) ? \
358            parse_solitary_modifier (ns_right_command_modifier) : 0) \
359      | ((flags & NSEventModifierFlagCommand) ?      \
360            parse_solitary_modifier (ns_command_modifier):0))
361 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
363 #define EV_UDMODIFIERS(e)                                      \
364     ((([e type] == NSEventTypeLeftMouseDown) ? down_modifier : 0)       \
365      | (([e type] == NSEventTypeRightMouseDown) ? down_modifier : 0)    \
366      | (([e type] == NSEventTypeOtherMouseDown) ? down_modifier : 0)    \
367      | (([e type] == NSEventTypeLeftMouseDragged) ? down_modifier : 0)  \
368      | (([e type] == NSEventTypeRightMouseDragged) ? down_modifier : 0) \
369      | (([e type] == NSEventTypeOtherMouseDragged) ? down_modifier : 0) \
370      | (([e type] == NSEventTypeLeftMouseUp)   ? up_modifier   : 0)     \
371      | (([e type] == NSEventTypeRightMouseUp)   ? up_modifier   : 0)    \
372      | (([e type] == NSEventTypeOtherMouseUp)   ? up_modifier   : 0))
374 #define EV_BUTTON(e)                                                         \
375     ((([e type] == NSEventTypeLeftMouseDown) || ([e type] == NSEventTypeLeftMouseUp)) ? 0 :    \
376       (([e type] == NSEventTypeRightMouseDown) || ([e type] == NSEventTypeRightMouseUp)) ? 2 : \
377      [e buttonNumber] - 1)
379 /* Convert the time field to a timestamp in milliseconds. */
380 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
382 /* This is a piece of code which is common to all the event handling
383    methods.  Maybe it should even be a function.  */
384 #define EV_TRAILER(e)                                                   \
385   {                                                                     \
386     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
387     EV_TRAILER2 (e);                                                    \
388   }
390 #define EV_TRAILER2(e)                                                  \
391   {                                                                     \
392       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
393       if (q_event_ptr)                                                  \
394         {                                                               \
395           Lisp_Object tem = Vinhibit_quit;                              \
396           Vinhibit_quit = Qt;                                           \
397           n_emacs_events_pending++;                                     \
398           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
399           Vinhibit_quit = tem;                                          \
400         }                                                               \
401       else                                                              \
402         hold_event (emacs_event);                                       \
403       EVENT_INIT (*emacs_event);                                        \
404       ns_send_appdefined (-1);                                          \
405     }
407 /* TODO: get rid of need for these forward declarations */
408 static void ns_condemn_scroll_bars (struct frame *f);
409 static void ns_judge_scroll_bars (struct frame *f);
412 /* ==========================================================================
414     Utilities
416    ========================================================================== */
418 void
419 ns_set_represented_filename (NSString* fstr, struct frame *f)
421   represented_filename = [fstr retain];
422   represented_frame = f;
425 void
426 ns_init_events (struct input_event* ev)
428   EVENT_INIT (*ev);
429   emacs_event = ev;
432 void
433 ns_finish_events (void)
435   emacs_event = NULL;
438 static void
439 hold_event (struct input_event *event)
441   if (hold_event_q.nr == hold_event_q.cap)
442     {
443       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
444       else hold_event_q.cap *= 2;
445       hold_event_q.q =
446         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
447     }
449   hold_event_q.q[hold_event_q.nr++] = *event;
450   /* Make sure ns_read_socket is called, i.e. we have input.  */
451   raise (SIGIO);
454 static Lisp_Object
455 append2 (Lisp_Object list, Lisp_Object item)
456 /* --------------------------------------------------------------------------
457    Utility to append to a list
458    -------------------------------------------------------------------------- */
460   return CALLN (Fnconc, list, list1 (item));
464 const char *
465 ns_etc_directory (void)
466 /* If running as a self-contained app bundle, return as a string the
467    filename of the etc directory, if present; else nil.  */
469   NSBundle *bundle = [NSBundle mainBundle];
470   NSString *resourceDir = [bundle resourcePath];
471   NSString *resourcePath;
472   NSFileManager *fileManager = [NSFileManager defaultManager];
473   BOOL isDir;
475   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
476   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
477     {
478       if (isDir) return [resourcePath UTF8String];
479     }
480   return NULL;
484 const char *
485 ns_exec_path (void)
486 /* If running as a self-contained app bundle, return as a path string
487    the filenames of the libexec and bin directories, ie libexec:bin.
488    Otherwise, return nil.
489    Normally, Emacs does not add its own bin/ directory to the PATH.
490    However, a self-contained NS build has a different layout, with
491    bin/ and libexec/ subdirectories in the directory that contains
492    Emacs.app itself.
493    We put libexec first, because init_callproc_1 uses the first
494    element to initialize exec-directory.  An alternative would be
495    for init_callproc to check for invocation-directory/libexec.
498   NSBundle *bundle = [NSBundle mainBundle];
499   NSString *resourceDir = [bundle resourcePath];
500   NSString *binDir = [bundle bundlePath];
501   NSString *resourcePath, *resourcePaths;
502   NSRange range;
503   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
504   NSFileManager *fileManager = [NSFileManager defaultManager];
505   NSArray *paths;
506   NSEnumerator *pathEnum;
507   BOOL isDir;
509   range = [resourceDir rangeOfString: @"Contents"];
510   if (range.location != NSNotFound)
511     {
512       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
513 #ifdef NS_IMPL_COCOA
514       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
515 #endif
516     }
518   paths = [binDir stringsByAppendingPaths:
519                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
520   pathEnum = [paths objectEnumerator];
521   resourcePaths = @"";
523   while ((resourcePath = [pathEnum nextObject]))
524     {
525       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
526         if (isDir)
527           {
528             if ([resourcePaths length] > 0)
529               resourcePaths
530                 = [resourcePaths stringByAppendingString: pathSeparator];
531             resourcePaths
532               = [resourcePaths stringByAppendingString: resourcePath];
533           }
534     }
535   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
537   return NULL;
541 const char *
542 ns_load_path (void)
543 /* If running as a self-contained app bundle, return as a path string
544    the filenames of the site-lisp and lisp directories.
545    Ie, site-lisp:lisp.  Otherwise, return nil.  */
547   NSBundle *bundle = [NSBundle mainBundle];
548   NSString *resourceDir = [bundle resourcePath];
549   NSString *resourcePath, *resourcePaths;
550   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
551   NSFileManager *fileManager = [NSFileManager defaultManager];
552   BOOL isDir;
553   NSArray *paths = [resourceDir stringsByAppendingPaths:
554                               [NSArray arrayWithObjects:
555                                          @"site-lisp", @"lisp", nil]];
556   NSEnumerator *pathEnum = [paths objectEnumerator];
557   resourcePaths = @"";
559   /* Hack to skip site-lisp.  */
560   if (no_site_lisp) resourcePath = [pathEnum nextObject];
562   while ((resourcePath = [pathEnum nextObject]))
563     {
564       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
565         if (isDir)
566           {
567             if ([resourcePaths length] > 0)
568               resourcePaths
569                 = [resourcePaths stringByAppendingString: pathSeparator];
570             resourcePaths
571               = [resourcePaths stringByAppendingString: resourcePath];
572           }
573     }
574   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
576   return NULL;
580 void
581 ns_init_locale (void)
582 /* macOS doesn't set any environment variables for the locale when run
583    from the GUI. Get the locale from the OS and set LANG. */
585   NSLocale *locale = [NSLocale currentLocale];
587   NSTRACE ("ns_init_locale");
589   @try
590     {
591       /* It seems macOS should probably use UTF-8 everywhere.
592          'localeIdentifier' does not specify the encoding, and I can't
593          find any way to get the OS to tell us which encoding to use,
594          so hard-code '.UTF-8'. */
595       NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
596                                      [locale localeIdentifier]];
598       /* Set LANG to locale, but not if LANG is already set. */
599       setenv("LANG", [localeID UTF8String], 0);
600     }
601   @catch (NSException *e)
602     {
603       NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
604     }
608 void
609 ns_release_object (void *obj)
610 /* --------------------------------------------------------------------------
611     Release an object (callable from C)
612    -------------------------------------------------------------------------- */
614     [(id)obj release];
618 void
619 ns_retain_object (void *obj)
620 /* --------------------------------------------------------------------------
621     Retain an object (callable from C)
622    -------------------------------------------------------------------------- */
624     [(id)obj retain];
628 void *
629 ns_alloc_autorelease_pool (void)
630 /* --------------------------------------------------------------------------
631      Allocate a pool for temporary objects (callable from C)
632    -------------------------------------------------------------------------- */
634   return [[NSAutoreleasePool alloc] init];
638 void
639 ns_release_autorelease_pool (void *pool)
640 /* --------------------------------------------------------------------------
641      Free a pool and temporary objects it refers to (callable from C)
642    -------------------------------------------------------------------------- */
644   ns_release_object (pool);
648 static BOOL
649 ns_menu_bar_should_be_hidden (void)
650 /* True, if the menu bar should be hidden.  */
652   return !NILP (ns_auto_hide_menu_bar)
653     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
657 struct EmacsMargins
659   CGFloat top;
660   CGFloat bottom;
661   CGFloat left;
662   CGFloat right;
666 static struct EmacsMargins
667 ns_screen_margins (NSScreen *screen)
668 /* The parts of SCREEN used by the operating system.  */
670   NSTRACE ("ns_screen_margins");
672   struct EmacsMargins margins;
674   NSRect screenFrame = [screen frame];
675   NSRect screenVisibleFrame = [screen visibleFrame];
677   /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
678      menu bar, check this explicitly.  */
679   if (ns_menu_bar_should_be_hidden())
680     {
681       margins.top = 0;
682     }
683   else
684     {
685       CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
686       CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
687                                  + screenVisibleFrame.size.height);
689       margins.top = frameTop - visibleFrameTop;
690     }
692   {
693     CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
694     CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
695                                  + screenVisibleFrame.size.width);
696     margins.right = frameRight - visibleFrameRight;
697   }
699   margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
700   margins.left   = screenVisibleFrame.origin.x - screenFrame.origin.x;
702   NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
703                margins.left,
704                margins.right,
705                margins.top,
706                margins.bottom);
708   return margins;
712 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
713    assumed to contain a hidden dock.  macOS currently use 4 pixels for
714    this, however, to be future compatible, a larger value is used.  */
715 #define DOCK_IGNORE_LIMIT 6
717 static struct EmacsMargins
718 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
719 /* The parts of SCREEN used by the operating system, excluding the parts
720 reserved for an hidden dock.  */
722   NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
724   struct EmacsMargins margins = ns_screen_margins(screen);
726   /* macOS (currently) reserved 4 pixels along the edge where a hidden
727      dock is located.  Unfortunately, it's not possible to find the
728      location and information about if the dock is hidden.  Instead,
729      it is assumed that if the margin of an edge is less than
730      DOCK_IGNORE_LIMIT, it contains a hidden dock.  */
731   if (margins.left <= DOCK_IGNORE_LIMIT)
732     {
733       margins.left = 0;
734     }
735   if (margins.right <= DOCK_IGNORE_LIMIT)
736     {
737       margins.right = 0;
738     }
739   if (margins.top <= DOCK_IGNORE_LIMIT)
740     {
741       margins.top = 0;
742     }
743   /* Note: This doesn't occur in current versions of macOS, but
744      included for completeness and future compatibility.  */
745   if (margins.bottom <= DOCK_IGNORE_LIMIT)
746     {
747       margins.bottom = 0;
748     }
750   NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
751                margins.left,
752                margins.right,
753                margins.top,
754                margins.bottom);
756   return margins;
760 static CGFloat
761 ns_menu_bar_height (NSScreen *screen)
762 /* The height of the menu bar, if visible.
764    Note: Don't use this when fullscreen is enabled -- the screen
765    sometimes includes, sometimes excludes the menu bar area.  */
767   struct EmacsMargins margins = ns_screen_margins(screen);
769   CGFloat res = margins.top;
771   NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
773   return res;
777 /* ==========================================================================
779     Focus (clipping) and screen update
781    ========================================================================== */
784 // Window constraining
785 // -------------------
787 // To ensure that the windows are not placed under the menu bar, they
788 // are typically moved by the call-back constrainFrameRect. However,
789 // by overriding it, it's possible to inhibit this, leaving the window
790 // in it's original position.
792 // It's possible to hide the menu bar. However, technically, it's only
793 // possible to hide it when the application is active. To ensure that
794 // this work properly, the menu bar and window constraining are
795 // deferred until the application becomes active.
797 // Even though it's not possible to manually move a window above the
798 // top of the screen, it is allowed if it's done programmatically,
799 // when the menu is hidden. This allows the editable area to cover the
800 // full screen height.
802 // Test cases
803 // ----------
805 // Use the following extra files:
807 //    init.el:
808 //       ;; Hide menu and place frame slightly above the top of the screen.
809 //       (setq ns-auto-hide-menu-bar t)
810 //       (set-frame-position (selected-frame) 0 -20)
812 // Test 1:
814 //    emacs -Q -l init.el
816 //    Result: No menu bar, and the title bar should be above the screen.
818 // Test 2:
820 //    emacs -Q
822 //    Result: Menu bar visible, frame placed immediately below the menu.
825 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
827   NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
828              NSTRACE_ARG_RECT (frameRect));
830   // --------------------
831   // Collect information about the screen the frame is covering.
832   //
834   NSArray *screens = [NSScreen screens];
835   NSUInteger nr_screens = [screens count];
837   int i;
839   // The height of the menu bar, if present in any screen the frame is
840   // displayed in.
841   int menu_bar_height = 0;
843   // A rectangle covering all the screen the frame is displayed in.
844   NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
845   for (i = 0; i < nr_screens; ++i )
846     {
847       NSScreen *s = [screens objectAtIndex: i];
848       NSRect scrRect = [s frame];
850       NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
851                    i, NSTRACE_ARG_RECT (scrRect));
853       if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
854         {
855           multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
857           if (!isFullscreen)
858             {
859               CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
860               menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
861             }
862         }
863     }
865   NSTRACE_RECT ("multiscreenRect", multiscreenRect);
867   NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
869   if (multiscreenRect.size.width == 0
870       || multiscreenRect.size.height == 0)
871     {
872       // Failed to find any monitor, give up.
873       NSTRACE_MSG ("multiscreenRect empty");
874       NSTRACE_RETURN_RECT (frameRect);
875       return frameRect;
876     }
879   // --------------------
880   // Find a suitable placement.
881   //
883   if (ns_menu_bar_should_be_hidden())
884     {
885       // When the menu bar is hidden, the user may place part of the
886       // frame above the top of the screen, for example to hide the
887       // title bar.
888       //
889       // Hence, keep the original position.
890     }
891   else
892     {
893       // Ensure that the frame is below the menu bar, or below the top
894       // of the screen.
895       //
896       // This assume that the menu bar is placed at the top in the
897       // rectangle that covers the monitors.  (It doesn't have to be,
898       // but if it's not it's hard to do anything useful.)
899       CGFloat topOfWorkArea = (multiscreenRect.origin.y
900                                + multiscreenRect.size.height
901                                - menu_bar_height);
903       CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
904       if (topOfFrame > topOfWorkArea)
905         {
906           frameRect.origin.y -= topOfFrame - topOfWorkArea;
907           NSTRACE_RECT ("After placement adjust", frameRect);
908         }
909     }
911   // Include the following section to restrict frame to the screens.
912   // (If so, update it to allow the frame to stretch down below the
913   // screen.)
914 #if 0
915   // --------------------
916   // Ensure frame doesn't stretch below the screens.
917   //
919   CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
921   if (diff > 0)
922     {
923       frameRect.origin.y = multiscreenRect.origin.y;
924       frameRect.size.height -= diff;
925     }
926 #endif
928   NSTRACE_RETURN_RECT (frameRect);
929   return frameRect;
933 static void
934 ns_constrain_all_frames (void)
935 /* --------------------------------------------------------------------------
936      Ensure that the menu bar doesn't cover any frames.
937    -------------------------------------------------------------------------- */
939   Lisp_Object tail, frame;
941   NSTRACE ("ns_constrain_all_frames");
943   block_input ();
945   FOR_EACH_FRAME (tail, frame)
946     {
947       struct frame *f = XFRAME (frame);
948       if (FRAME_NS_P (f))
949         {
950           EmacsView *view = FRAME_NS_VIEW (f);
952           if (![view isFullscreen])
953             {
954               [[view window]
955                 setFrame:constrain_frame_rect([[view window] frame], false)
956                  display:NO];
957             }
958         }
959     }
961   unblock_input ();
965 static void
966 ns_update_auto_hide_menu_bar (void)
967 /* --------------------------------------------------------------------------
968      Show or hide the menu bar, based on user setting.
969    -------------------------------------------------------------------------- */
971 #ifdef NS_IMPL_COCOA
972   NSTRACE ("ns_update_auto_hide_menu_bar");
974   block_input ();
976   if (NSApp != nil && [NSApp isActive])
977     {
978       // Note, "setPresentationOptions" triggers an error unless the
979       // application is active.
980       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
982       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
983         {
984           NSApplicationPresentationOptions options
985             = NSApplicationPresentationDefault;
987           if (menu_bar_should_be_hidden)
988             options |= NSApplicationPresentationAutoHideMenuBar
989               | NSApplicationPresentationAutoHideDock;
991           [NSApp setPresentationOptions: options];
993           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
995           if (!ns_menu_bar_is_hidden)
996             {
997               ns_constrain_all_frames ();
998             }
999         }
1000     }
1002   unblock_input ();
1003 #endif
1007 static void
1008 ns_update_begin (struct frame *f)
1009 /* --------------------------------------------------------------------------
1010    Prepare for a grouped sequence of drawing calls
1011    external (RIF) call; whole frame, called before update_window_begin
1012    -------------------------------------------------------------------------- */
1014   EmacsView *view = FRAME_NS_VIEW (f);
1015   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1017   ns_update_auto_hide_menu_bar ();
1019 #ifdef NS_IMPL_COCOA
1020   if ([view isFullscreen] && [view fsIsNative])
1021   {
1022     // Fix reappearing tool bar in fullscreen for Mac OS X 10.7
1023     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1024     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1025     if (! tbar_visible != ! [toolbar isVisible])
1026       [toolbar setVisible: tbar_visible];
1027   }
1028 #endif
1030   ns_updating_frame = f;
1031   [view lockFocus];
1033   /* drawRect may have been called for say the minibuffer, and then clip path
1034      is for the minibuffer.  But the display engine may draw more because
1035      we have set the frame as garbaged.  So reset clip path to the whole
1036      view.  */
1037 #ifdef NS_IMPL_COCOA
1038   {
1039     NSBezierPath *bp;
1040     NSRect r = [view frame];
1041     NSRect cr = [[view window] frame];
1042     /* If a large frame size is set, r may be larger than the window frame
1043        before constrained.  In that case don't change the clip path, as we
1044        will clear in to the tool bar and title bar.  */
1045     if (r.size.height
1046         + FRAME_NS_TITLEBAR_HEIGHT (f)
1047         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1048       {
1049         bp = [[NSBezierPath bezierPathWithRect: r] retain];
1050         [bp setClip];
1051         [bp release];
1052       }
1053   }
1054 #endif
1056 #ifdef NS_IMPL_GNUSTEP
1057   uRect = NSMakeRect (0, 0, 0, 0);
1058 #endif
1062 static void
1063 ns_update_window_begin (struct window *w)
1064 /* --------------------------------------------------------------------------
1065    Prepare for a grouped sequence of drawing calls
1066    external (RIF) call; for one window, called after update_begin
1067    -------------------------------------------------------------------------- */
1069   struct frame *f = XFRAME (WINDOW_FRAME (w));
1070   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1072   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1073   w->output_cursor = w->cursor;
1075   block_input ();
1077   if (f == hlinfo->mouse_face_mouse_frame)
1078     {
1079       /* Don't do highlighting for mouse motion during the update.  */
1080       hlinfo->mouse_face_defer = 1;
1082         /* If the frame needs to be redrawn,
1083            simply forget about any prior mouse highlighting.  */
1084       if (FRAME_GARBAGED_P (f))
1085         hlinfo->mouse_face_window = Qnil;
1087       /* (further code for mouse faces ifdef'd out in other terms elided) */
1088     }
1090   unblock_input ();
1094 static void
1095 ns_update_window_end (struct window *w, bool cursor_on_p,
1096                       bool mouse_face_overwritten_p)
1097 /* --------------------------------------------------------------------------
1098    Finished a grouped sequence of drawing calls
1099    external (RIF) call; for one window called before update_end
1100    -------------------------------------------------------------------------- */
1102   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1104   /* note: this fn is nearly identical in all terms */
1105   if (!w->pseudo_window_p)
1106     {
1107       block_input ();
1109       if (cursor_on_p)
1110         display_and_set_cursor (w, 1,
1111                                 w->output_cursor.hpos, w->output_cursor.vpos,
1112                                 w->output_cursor.x, w->output_cursor.y);
1114       if (draw_window_fringes (w, 1))
1115         {
1116           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1117             x_draw_right_divider (w);
1118           else
1119             x_draw_vertical_border (w);
1120         }
1122       unblock_input ();
1123     }
1125   /* If a row with mouse-face was overwritten, arrange for
1126      frame_up_to_date to redisplay the mouse highlight.  */
1127   if (mouse_face_overwritten_p)
1128     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1132 static void
1133 ns_update_end (struct frame *f)
1134 /* --------------------------------------------------------------------------
1135    Finished a grouped sequence of drawing calls
1136    external (RIF) call; for whole frame, called after update_window_end
1137    -------------------------------------------------------------------------- */
1139   EmacsView *view = FRAME_NS_VIEW (f);
1141   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1143 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1144   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1146   block_input ();
1148   [view unlockFocus];
1149   [[view window] flushWindow];
1151   unblock_input ();
1152   ns_updating_frame = NULL;
1155 static void
1156 ns_focus (struct frame *f, NSRect *r, int n)
1157 /* --------------------------------------------------------------------------
1158    Internal: Focus on given frame.  During small local updates this is used to
1159      draw, however during large updates, ns_update_begin and ns_update_end are
1160      called to wrap the whole thing, in which case these calls are stubbed out.
1161      Except, on GNUstep, we accumulate the rectangle being drawn into, because
1162      the back end won't do this automatically, and will just end up flushing
1163      the entire window.
1164    -------------------------------------------------------------------------- */
1166   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1167   if (r != NULL)
1168     {
1169       NSTRACE_RECT ("r", *r);
1170     }
1172   if (f != ns_updating_frame)
1173     {
1174       NSView *view = FRAME_NS_VIEW (f);
1175       if (view != focus_view)
1176         {
1177           if (focus_view != NULL)
1178             {
1179               [focus_view unlockFocus];
1180               [[focus_view window] flushWindow];
1181 /*debug_lock--; */
1182             }
1184           if (view)
1185             [view lockFocus];
1186           focus_view = view;
1187 /*if (view) debug_lock++; */
1188         }
1189     }
1191   /* clipping */
1192   if (r)
1193     {
1194       [[NSGraphicsContext currentContext] saveGraphicsState];
1195       if (n == 2)
1196         NSRectClipList (r, 2);
1197       else
1198         NSRectClip (*r);
1199       gsaved = YES;
1200     }
1204 static void
1205 ns_unfocus (struct frame *f)
1206 /* --------------------------------------------------------------------------
1207      Internal: Remove focus on given frame
1208    -------------------------------------------------------------------------- */
1210   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1212   if (gsaved)
1213     {
1214       [[NSGraphicsContext currentContext] restoreGraphicsState];
1215       gsaved = NO;
1216     }
1218   if (f != ns_updating_frame)
1219     {
1220       if (focus_view != NULL)
1221         {
1222           [focus_view unlockFocus];
1223           [[focus_view window] flushWindow];
1224           focus_view = NULL;
1225 /*debug_lock--; */
1226         }
1227     }
1231 static void
1232 ns_clip_to_row (struct window *w, struct glyph_row *row,
1233                 enum glyph_row_area area, BOOL gc)
1234 /* --------------------------------------------------------------------------
1235      Internal (but parallels other terms): Focus drawing on given row
1236    -------------------------------------------------------------------------- */
1238   struct frame *f = XFRAME (WINDOW_FRAME (w));
1239   NSRect clip_rect;
1240   int window_x, window_y, window_width;
1242   window_box (w, area, &window_x, &window_y, &window_width, 0);
1244   clip_rect.origin.x = window_x;
1245   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1246   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1247   clip_rect.size.width = window_width;
1248   clip_rect.size.height = row->visible_height;
1250   ns_focus (f, &clip_rect, 1);
1254 /* ==========================================================================
1256     Visible bell and beep.
1258    ========================================================================== */
1261 // This bell implementation shows the visual bell image asynchronously
1262 // from the rest of Emacs. This is done by adding a NSView to the
1263 // superview of the Emacs window and removing it using a timer.
1265 // Unfortunately, some Emacs operations, like scrolling, is done using
1266 // low-level primitives that copy the content of the window, including
1267 // the bell image. To some extent, this is handled by removing the
1268 // image prior to scrolling and marking that the window is in need for
1269 // redisplay.
1271 // To test this code, make sure that there is no artifacts of the bell
1272 // image in the following situations. Use a non-empty buffer (like the
1273 // tutorial) to ensure that a scroll is performed:
1275 // * Single-window: C-g C-v
1277 // * Side-by-windows: C-x 3 C-g C-v
1279 // * Windows above each other: C-x 2 C-g C-v
1281 @interface EmacsBell : NSImageView
1283   // Number of currently active bell:s.
1284   unsigned int nestCount;
1285   NSView * mView;
1286   bool isAttached;
1288 - (void)show:(NSView *)view;
1289 - (void)hide;
1290 - (void)remove;
1291 @end
1293 @implementation EmacsBell
1295 - (id)init;
1297   NSTRACE ("[EmacsBell init]");
1298   if ((self = [super init]))
1299     {
1300       nestCount = 0;
1301       isAttached = false;
1302 #ifdef NS_IMPL_GNUSTEP
1303       // GNUstep doesn't provide named images.  This was reported in
1304       // 2011, see https://savannah.gnu.org/bugs/?33396
1305       //
1306       // As a drop in replacement, a semitransparent gray square is used.
1307       self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1308       [self.image lockFocus];
1309       [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1310       NSRectFill(NSMakeRect(0, 0, 32, 32));
1311       [self.image unlockFocus];
1312 #else
1313       self.image = [NSImage imageNamed:NSImageNameCaution];
1314       [self.image setSize:NSMakeSize(self.image.size.width * 5,
1315                                      self.image.size.height * 5)];
1316 #endif
1317     }
1318   return self;
1321 - (void)show:(NSView *)view
1323   NSTRACE ("[EmacsBell show:]");
1324   NSTRACE_MSG ("nestCount: %u", nestCount);
1326   // Show the image, unless it's already shown.
1327   if (nestCount == 0)
1328     {
1329       NSRect rect = [view bounds];
1330       NSPoint pos;
1331       pos.x = rect.origin.x + (rect.size.width  - self.image.size.width )/2;
1332       pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1334       [self setFrameOrigin:pos];
1335       [self setFrameSize:self.image.size];
1337       isAttached = true;
1338       mView = view;
1339       [[[view window] contentView] addSubview:self
1340                                    positioned:NSWindowAbove
1341                                    relativeTo:nil];
1342     }
1344   ++nestCount;
1346   [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1350 - (void)hide
1352   // Note: Trace output from this method isn't shown, reason unknown.
1353   // NSTRACE ("[EmacsBell hide]");
1355   if (nestCount > 0)
1356     --nestCount;
1358   // Remove the image once the last bell became inactive.
1359   if (nestCount == 0)
1360     {
1361       [self remove];
1362     }
1366 -(void)remove
1368   NSTRACE ("[EmacsBell remove]");
1369   if (isAttached)
1370     {
1371       NSTRACE_MSG ("removeFromSuperview");
1372       [self removeFromSuperview];
1373       mView.needsDisplay = YES;
1374       isAttached = false;
1375     }
1378 @end
1381 static EmacsBell * bell_view = nil;
1383 static void
1384 ns_ring_bell (struct frame *f)
1385 /* --------------------------------------------------------------------------
1386      "Beep" routine
1387    -------------------------------------------------------------------------- */
1389   NSTRACE ("ns_ring_bell");
1390   if (visible_bell)
1391     {
1392       struct frame *frame = SELECTED_FRAME ();
1393       NSView *view;
1395       if (bell_view == nil)
1396         {
1397           bell_view = [[EmacsBell alloc] init];
1398           [bell_view retain];
1399         }
1401       block_input ();
1403       view = FRAME_NS_VIEW (frame);
1404       if (view != nil)
1405         {
1406           [bell_view show:view];
1407         }
1409       unblock_input ();
1410     }
1411   else
1412     {
1413       NSBeep ();
1414     }
1418 static void
1419 hide_bell (void)
1420 /* --------------------------------------------------------------------------
1421      Ensure the bell is hidden.
1422    -------------------------------------------------------------------------- */
1424   NSTRACE ("hide_bell");
1426   if (bell_view != nil)
1427     {
1428       [bell_view remove];
1429     }
1433 /* ==========================================================================
1435     Frame / window manager related functions
1437    ========================================================================== */
1440 static void
1441 ns_raise_frame (struct frame *f)
1442 /* --------------------------------------------------------------------------
1443      Bring window to foreground and make it active
1444    -------------------------------------------------------------------------- */
1446   NSView *view;
1448   check_window_system (f);
1449   view = FRAME_NS_VIEW (f);
1450   block_input ();
1451   if (FRAME_VISIBLE_P (f))
1452     [[view window] makeKeyAndOrderFront: NSApp];
1453   unblock_input ();
1457 static void
1458 ns_lower_frame (struct frame *f)
1459 /* --------------------------------------------------------------------------
1460      Send window to back
1461    -------------------------------------------------------------------------- */
1463   NSView *view;
1465   check_window_system (f);
1466   view = FRAME_NS_VIEW (f);
1467   block_input ();
1468   [[view window] orderBack: NSApp];
1469   unblock_input ();
1473 static void
1474 ns_frame_raise_lower (struct frame *f, bool raise)
1475 /* --------------------------------------------------------------------------
1476      External (hook)
1477    -------------------------------------------------------------------------- */
1479   NSTRACE ("ns_frame_raise_lower");
1481   if (raise)
1482     ns_raise_frame (f);
1483   else
1484     ns_lower_frame (f);
1488 static void
1489 ns_frame_rehighlight (struct frame *frame)
1490 /* --------------------------------------------------------------------------
1491      External (hook): called on things like window switching within frame
1492    -------------------------------------------------------------------------- */
1494   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1495   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1497   NSTRACE ("ns_frame_rehighlight");
1498   if (dpyinfo->x_focus_frame)
1499     {
1500       dpyinfo->x_highlight_frame
1501         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1502            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1503            : dpyinfo->x_focus_frame);
1504       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1505         {
1506           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1507           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1508         }
1509     }
1510   else
1511       dpyinfo->x_highlight_frame = 0;
1513   if (dpyinfo->x_highlight_frame &&
1514          dpyinfo->x_highlight_frame != old_highlight)
1515     {
1516       if (old_highlight)
1517         {
1518           x_update_cursor (old_highlight, 1);
1519           x_set_frame_alpha (old_highlight);
1520         }
1521       if (dpyinfo->x_highlight_frame)
1522         {
1523           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1524           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1525         }
1526     }
1530 void
1531 x_make_frame_visible (struct frame *f)
1532 /* --------------------------------------------------------------------------
1533      External: Show the window (X11 semantics)
1534    -------------------------------------------------------------------------- */
1536   NSTRACE ("x_make_frame_visible");
1537   /* XXX: at some points in past this was not needed, as the only place that
1538      called this (frame.c:Fraise_frame ()) also called raise_lower;
1539      if this ends up the case again, comment this out again. */
1540   if (!FRAME_VISIBLE_P (f))
1541     {
1542       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1544       SET_FRAME_VISIBLE (f, 1);
1545       ns_raise_frame (f);
1547       /* Making a new frame from a fullscreen frame will make the new frame
1548          fullscreen also.  So skip handleFS as this will print an error.  */
1549       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1550           && [view isFullscreen])
1551         return;
1553       if (f->want_fullscreen != FULLSCREEN_NONE)
1554         {
1555           block_input ();
1556           [view handleFS];
1557           unblock_input ();
1558         }
1559     }
1563 void
1564 x_make_frame_invisible (struct frame *f)
1565 /* --------------------------------------------------------------------------
1566      External: Hide the window (X11 semantics)
1567    -------------------------------------------------------------------------- */
1569   NSView *view;
1570   NSTRACE ("x_make_frame_invisible");
1571   check_window_system (f);
1572   view = FRAME_NS_VIEW (f);
1573   [[view window] orderOut: NSApp];
1574   SET_FRAME_VISIBLE (f, 0);
1575   SET_FRAME_ICONIFIED (f, 0);
1579 void
1580 x_iconify_frame (struct frame *f)
1581 /* --------------------------------------------------------------------------
1582      External: Iconify window
1583    -------------------------------------------------------------------------- */
1585   NSView *view;
1586   struct ns_display_info *dpyinfo;
1588   NSTRACE ("x_iconify_frame");
1589   check_window_system (f);
1590   view = FRAME_NS_VIEW (f);
1591   dpyinfo = FRAME_DISPLAY_INFO (f);
1593   if (dpyinfo->x_highlight_frame == f)
1594     dpyinfo->x_highlight_frame = 0;
1596   if ([[view window] windowNumber] <= 0)
1597     {
1598       /* the window is still deferred.  Make it very small, bring it
1599          on screen and order it out. */
1600       NSRect s = { { 100, 100}, {0, 0} };
1601       NSRect t;
1602       t = [[view window] frame];
1603       [[view window] setFrame: s display: NO];
1604       [[view window] orderBack: NSApp];
1605       [[view window] orderOut: NSApp];
1606       [[view window] setFrame: t display: NO];
1607     }
1609   /* Processing input while Emacs is being minimized can cause a
1610      crash, so block it for the duration. */
1611   block_input();
1612   [[view window] miniaturize: NSApp];
1613   unblock_input();
1616 /* Free X resources of frame F.  */
1618 void
1619 x_free_frame_resources (struct frame *f)
1621   NSView *view;
1622   struct ns_display_info *dpyinfo;
1623   Mouse_HLInfo *hlinfo;
1625   NSTRACE ("x_free_frame_resources");
1626   check_window_system (f);
1627   view = FRAME_NS_VIEW (f);
1628   dpyinfo = FRAME_DISPLAY_INFO (f);
1629   hlinfo = MOUSE_HL_INFO (f);
1631   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1633   block_input ();
1635   free_frame_menubar (f);
1636   free_frame_faces (f);
1638   if (f == dpyinfo->x_focus_frame)
1639     dpyinfo->x_focus_frame = 0;
1640   if (f == dpyinfo->x_highlight_frame)
1641     dpyinfo->x_highlight_frame = 0;
1642   if (f == hlinfo->mouse_face_mouse_frame)
1643     reset_mouse_highlight (hlinfo);
1645   if (f->output_data.ns->miniimage != nil)
1646     [f->output_data.ns->miniimage release];
1648   [[view window] close];
1649   [view release];
1651   xfree (f->output_data.ns);
1653   unblock_input ();
1656 void
1657 x_destroy_window (struct frame *f)
1658 /* --------------------------------------------------------------------------
1659      External: Delete the window
1660    -------------------------------------------------------------------------- */
1662   NSTRACE ("x_destroy_window");
1663   check_window_system (f);
1664   x_free_frame_resources (f);
1665   ns_window_num--;
1669 void
1670 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1671 /* --------------------------------------------------------------------------
1672      External: Position the window
1673    -------------------------------------------------------------------------- */
1675   NSView *view = FRAME_NS_VIEW (f);
1676   NSArray *screens = [NSScreen screens];
1677   NSScreen *fscreen = [screens objectAtIndex: 0];
1678   NSScreen *screen = [[view window] screen];
1680   NSTRACE ("x_set_offset");
1682   block_input ();
1684   f->left_pos = xoff;
1685   f->top_pos = yoff;
1687   if (view != nil && screen && fscreen)
1688     {
1689       f->left_pos = f->size_hint_flags & XNegative
1690         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1691         : f->left_pos;
1692       /* We use visibleFrame here to take menu bar into account.
1693          Ideally we should also adjust left/top with visibleFrame.origin.  */
1695       f->top_pos = f->size_hint_flags & YNegative
1696         ? ([screen visibleFrame].size.height + f->top_pos
1697            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1698            - FRAME_TOOLBAR_HEIGHT (f))
1699         : f->top_pos;
1700 #ifdef NS_IMPL_GNUSTEP
1701       if (f->left_pos < 100)
1702         f->left_pos = 100;  /* don't overlap menu */
1703 #endif
1704       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1705          menu bar.  */
1706       NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos),
1707                                 SCREENMAXBOUND ([fscreen frame].size.height
1708                                                 - NS_TOP_POS (f)));
1709       NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1710       [[view window] setFrameTopLeftPoint: pt];
1711       f->size_hint_flags &= ~(XNegative|YNegative);
1712     }
1714   unblock_input ();
1718 void
1719 x_set_window_size (struct frame *f,
1720                    bool change_gravity,
1721                    int width,
1722                    int height,
1723                    bool pixelwise)
1724 /* --------------------------------------------------------------------------
1725      Adjust window pixel size based on given character grid size
1726      Impl is a bit more complex than other terms, need to do some
1727      internal clipping.
1728    -------------------------------------------------------------------------- */
1730   EmacsView *view = FRAME_NS_VIEW (f);
1731   NSWindow *window = [view window];
1732   NSRect wr = [window frame];
1733   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1734   int pixelwidth, pixelheight;
1735   int orig_height = wr.size.height;
1737   NSTRACE ("x_set_window_size");
1739   if (view == nil)
1740     return;
1742   NSTRACE_RECT ("current", wr);
1743   NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1744   NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1746   block_input ();
1748   if (pixelwise)
1749     {
1750       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1751       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1752     }
1753   else
1754     {
1755       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1756       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1757     }
1759   /* If we have a toolbar, take its height into account. */
1760   if (tb && ! [view isFullscreen])
1761     {
1762     /* NOTE: previously this would generate wrong result if toolbar not
1763              yet displayed and fixing toolbar_height=32 helped, but
1764              now (200903) seems no longer needed */
1765     FRAME_TOOLBAR_HEIGHT (f) =
1766       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1767         - FRAME_NS_TITLEBAR_HEIGHT (f);
1768 #if 0
1769       /* Only breaks things here, removed by martin 2015-09-30.  */
1770 #ifdef NS_IMPL_GNUSTEP
1771       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1772 #endif
1773 #endif
1774     }
1775   else
1776     FRAME_TOOLBAR_HEIGHT (f) = 0;
1778   wr.size.width = pixelwidth + f->border_width;
1779   wr.size.height = pixelheight;
1780   if (! [view isFullscreen])
1781     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1782       + FRAME_TOOLBAR_HEIGHT (f);
1784   /* Do not try to constrain to this screen.  We may have multiple
1785      screens, and want Emacs to span those.  Constraining to screen
1786      prevents that, and that is not nice to the user.  */
1787  if (f->output_data.ns->zooming)
1788    f->output_data.ns->zooming = 0;
1789  else
1790    wr.origin.y += orig_height - wr.size.height;
1792  frame_size_history_add
1793    (f, Qx_set_window_size_1, width, height,
1794     list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1795            Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1796            make_number (f->border_width),
1797            make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1798            make_number (FRAME_TOOLBAR_HEIGHT (f))));
1800   [window setFrame: wr display: YES];
1802   [view updateFrameSize: NO];
1803   unblock_input ();
1807 static void
1808 ns_fullscreen_hook (struct frame *f)
1810   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1812   NSTRACE ("ns_fullscreen_hook");
1814   if (!FRAME_VISIBLE_P (f))
1815     return;
1817    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1818     {
1819       /* Old style fs don't initiate correctly if created from
1820          init/default-frame alist, so use a timer (not nice...).
1821       */
1822       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1823                                      selector: @selector (handleFS)
1824                                      userInfo: nil repeats: NO];
1825       return;
1826     }
1828   block_input ();
1829   [view handleFS];
1830   unblock_input ();
1833 /* ==========================================================================
1835     Color management
1837    ========================================================================== */
1840 NSColor *
1841 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1843   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1844   if (idx < 1 || idx >= color_table->avail)
1845     return nil;
1846   return color_table->colors[idx];
1850 unsigned long
1851 ns_index_color (NSColor *color, struct frame *f)
1853   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1854   ptrdiff_t idx;
1855   ptrdiff_t i;
1857   if (!color_table->colors)
1858     {
1859       color_table->size = NS_COLOR_CAPACITY;
1860       color_table->avail = 1; /* skip idx=0 as marker */
1861       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1862       color_table->colors[0] = nil;
1863       color_table->empty_indices = [[NSMutableSet alloc] init];
1864     }
1866   /* Do we already have this color?  */
1867   for (i = 1; i < color_table->avail; i++)
1868     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1869       return i;
1871   if ([color_table->empty_indices count] > 0)
1872     {
1873       NSNumber *index = [color_table->empty_indices anyObject];
1874       [color_table->empty_indices removeObject: index];
1875       idx = [index unsignedLongValue];
1876     }
1877   else
1878     {
1879       if (color_table->avail == color_table->size)
1880         color_table->colors =
1881           xpalloc (color_table->colors, &color_table->size, 1,
1882                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1883       idx = color_table->avail++;
1884     }
1886   color_table->colors[idx] = color;
1887   [color retain];
1888 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1889   return idx;
1893 static int
1894 ns_get_color (const char *name, NSColor **col)
1895 /* --------------------------------------------------------------------------
1896      Parse a color name
1897    -------------------------------------------------------------------------- */
1898 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1899    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1900    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1902   NSColor *new = nil;
1903   static char hex[20];
1904   int scaling = 0;
1905   float r = -1.0, g, b;
1906   NSString *nsname = [NSString stringWithUTF8String: name];
1908   NSTRACE ("ns_get_color(%s, **)", name);
1910   block_input ();
1912   if ([nsname isEqualToString: @"ns_selection_bg_color"])
1913     {
1914 #ifdef NS_IMPL_COCOA
1915       NSString *defname = [[NSUserDefaults standardUserDefaults]
1916                             stringForKey: @"AppleHighlightColor"];
1917       if (defname != nil)
1918         nsname = defname;
1919       else
1920 #endif
1921       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1922         {
1923           *col = [new colorUsingDefaultColorSpace];
1924           unblock_input ();
1925           return 0;
1926         }
1927       else
1928         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1930       name = [nsname UTF8String];
1931     }
1932   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1933     {
1934       /* NOTE: macOS applications normally don't set foreground
1935          selection, but text may be unreadable if we don't.
1936       */
1937       if ((new = [NSColor selectedTextColor]) != nil)
1938         {
1939           *col = [new colorUsingDefaultColorSpace];
1940           unblock_input ();
1941           return 0;
1942         }
1944       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1945       name = [nsname UTF8String];
1946     }
1948   /* First, check for some sort of numeric specification. */
1949   hex[0] = '\0';
1951   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1952     {
1953       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1954       [scanner scanFloat: &r];
1955       [scanner scanFloat: &g];
1956       [scanner scanFloat: &b];
1957     }
1958   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1959     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1960   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1961     {
1962       int len = (strlen(name) - 1);
1963       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1964       int i;
1965       scaling = strlen(name+start) / 3;
1966       for (i = 0; i < 3; i++)
1967         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1968                  name + start + i * scaling);
1969       hex[3 * (scaling + 1) - 1] = '\0';
1970     }
1972   if (hex[0])
1973     {
1974       unsigned int rr, gg, bb;
1975       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1976       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1977         {
1978           r = rr / fscale;
1979           g = gg / fscale;
1980           b = bb / fscale;
1981         }
1982     }
1984   if (r >= 0.0F)
1985     {
1986       *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
1987       unblock_input ();
1988       return 0;
1989     }
1991   /* Otherwise, color is expected to be from a list */
1992   {
1993     NSEnumerator *lenum, *cenum;
1994     NSString *name;
1995     NSColorList *clist;
1997 #ifdef NS_IMPL_GNUSTEP
1998     /* XXX: who is wrong, the requestor or the implementation? */
1999     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2000         == NSOrderedSame)
2001       nsname = @"highlightColor";
2002 #endif
2004     lenum = [[NSColorList availableColorLists] objectEnumerator];
2005     while ( (clist = [lenum nextObject]) && new == nil)
2006       {
2007         cenum = [[clist allKeys] objectEnumerator];
2008         while ( (name = [cenum nextObject]) && new == nil )
2009           {
2010             if ([name compare: nsname
2011                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
2012               new = [clist colorWithKey: name];
2013           }
2014       }
2015   }
2017   if (new)
2018     *col = [new colorUsingDefaultColorSpace];
2019   unblock_input ();
2020   return new ? 0 : 1;
2025 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2026 /* --------------------------------------------------------------------------
2027      Convert a Lisp string object to a NS color
2028    -------------------------------------------------------------------------- */
2030   NSTRACE ("ns_lisp_to_color");
2031   if (STRINGP (color))
2032     return ns_get_color (SSDATA (color), col);
2033   else if (SYMBOLP (color))
2034     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2035   return 1;
2039 void
2040 ns_query_color(void *col, XColor *color_def, int setPixel)
2041 /* --------------------------------------------------------------------------
2042          Get ARGB values out of NSColor col and put them into color_def.
2043          If setPixel, set the pixel to a concatenated version.
2044          and set color_def pixel to the resulting index.
2045    -------------------------------------------------------------------------- */
2047   EmacsCGFloat r, g, b, a;
2049   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2050   color_def->red   = r * 65535;
2051   color_def->green = g * 65535;
2052   color_def->blue  = b * 65535;
2054   if (setPixel == YES)
2055     color_def->pixel
2056       = ARGB_TO_ULONG((int)(a*255),
2057                       (int)(r*255), (int)(g*255), (int)(b*255));
2061 bool
2062 ns_defined_color (struct frame *f,
2063                   const char *name,
2064                   XColor *color_def,
2065                   bool alloc,
2066                   bool makeIndex)
2067 /* --------------------------------------------------------------------------
2068          Return true if named color found, and set color_def rgb accordingly.
2069          If makeIndex and alloc are nonzero put the color in the color_table,
2070          and set color_def pixel to the resulting index.
2071          If makeIndex is zero, set color_def pixel to ARGB.
2072          Return false if not found
2073    -------------------------------------------------------------------------- */
2075   NSColor *col;
2076   NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2078   block_input ();
2079   if (ns_get_color (name, &col) != 0) /* Color not found  */
2080     {
2081       unblock_input ();
2082       return 0;
2083     }
2084   if (makeIndex && alloc)
2085     color_def->pixel = ns_index_color (col, f);
2086   ns_query_color (col, color_def, !makeIndex);
2087   unblock_input ();
2088   return 1;
2092 void
2093 x_set_frame_alpha (struct frame *f)
2094 /* --------------------------------------------------------------------------
2095      change the entire-frame transparency
2096    -------------------------------------------------------------------------- */
2098   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2099   double alpha = 1.0;
2100   double alpha_min = 1.0;
2102   NSTRACE ("x_set_frame_alpha");
2104   if (dpyinfo->x_highlight_frame == f)
2105     alpha = f->alpha[0];
2106   else
2107     alpha = f->alpha[1];
2109   if (FLOATP (Vframe_alpha_lower_limit))
2110     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2111   else if (INTEGERP (Vframe_alpha_lower_limit))
2112     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2114   if (alpha < 0.0)
2115     return;
2116   else if (1.0 < alpha)
2117     alpha = 1.0;
2118   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2119     alpha = alpha_min;
2121 #ifdef NS_IMPL_COCOA
2122   {
2123     EmacsView *view = FRAME_NS_VIEW (f);
2124   [[view window] setAlphaValue: alpha];
2125   }
2126 #endif
2130 /* ==========================================================================
2132     Mouse handling
2134    ========================================================================== */
2137 void
2138 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2139 /* --------------------------------------------------------------------------
2140      Programmatically reposition mouse pointer in pixel coordinates
2141    -------------------------------------------------------------------------- */
2143   NSTRACE ("frame_set_mouse_pixel_position");
2144   ns_raise_frame (f);
2145 #if 0
2146   /* FIXME: this does not work, and what about GNUstep? */
2147 #ifdef NS_IMPL_COCOA
2148   [FRAME_NS_VIEW (f) lockFocus];
2149   PSsetmouse ((float)pix_x, (float)pix_y);
2150   [FRAME_NS_VIEW (f) unlockFocus];
2151 #endif
2152 #endif
2155 static int
2156 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2157 /*   ------------------------------------------------------------------------
2158      Called by EmacsView on mouseMovement events.  Passes on
2159      to emacs mainstream code if we moved off of a rect of interest
2160      known as last_mouse_glyph.
2161      ------------------------------------------------------------------------ */
2163   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2164   NSRect *r;
2166 //  NSTRACE ("note_mouse_movement");
2168   dpyinfo->last_mouse_motion_frame = frame;
2169   r = &dpyinfo->last_mouse_glyph;
2171   /* Note, this doesn't get called for enter/leave, since we don't have a
2172      position.  Those are taken care of in the corresponding NSView methods. */
2174   /* has movement gone beyond last rect we were tracking? */
2175   if (x < r->origin.x || x >= r->origin.x + r->size.width
2176       || y < r->origin.y || y >= r->origin.y + r->size.height)
2177     {
2178       ns_update_begin (frame);
2179       frame->mouse_moved = 1;
2180       note_mouse_highlight (frame, x, y);
2181       remember_mouse_glyph (frame, x, y, r);
2182       ns_update_end (frame);
2183       return 1;
2184     }
2186   return 0;
2190 static void
2191 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2192                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2193                    Time *time)
2194 /* --------------------------------------------------------------------------
2195     External (hook): inform emacs about mouse position and hit parts.
2196     If a scrollbar is being dragged, set bar_window, part, x, y, time.
2197     x & y should be position in the scrollbar (the whole bar, not the handle)
2198     and length of scrollbar respectively
2199    -------------------------------------------------------------------------- */
2201   id view;
2202   NSPoint position;
2203   Lisp_Object frame, tail;
2204   struct frame *f;
2205   struct ns_display_info *dpyinfo;
2207   NSTRACE ("ns_mouse_position");
2209   if (*fp == NULL)
2210     {
2211       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2212       return;
2213     }
2215   dpyinfo = FRAME_DISPLAY_INFO (*fp);
2217   block_input ();
2219   /* Clear the mouse-moved flag for every frame on this display.  */
2220   FOR_EACH_FRAME (tail, frame)
2221     if (FRAME_NS_P (XFRAME (frame))
2222         && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2223       XFRAME (frame)->mouse_moved = 0;
2225   dpyinfo->last_mouse_scroll_bar = nil;
2226   if (dpyinfo->last_mouse_frame
2227       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2228     f = dpyinfo->last_mouse_frame;
2229   else
2230     f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2232   if (f && FRAME_NS_P (f))
2233     {
2234       view = FRAME_NS_VIEW (*fp);
2236       position = [[view window] mouseLocationOutsideOfEventStream];
2237       position = [view convertPoint: position fromView: nil];
2238       remember_mouse_glyph (f, position.x, position.y,
2239                             &dpyinfo->last_mouse_glyph);
2240       NSTRACE_POINT ("position", position);
2242       if (bar_window) *bar_window = Qnil;
2243       if (part) *part = scroll_bar_above_handle;
2245       if (x) XSETINT (*x, lrint (position.x));
2246       if (y) XSETINT (*y, lrint (position.y));
2247       if (time)
2248         *time = dpyinfo->last_mouse_movement_time;
2249       *fp = f;
2250     }
2252   unblock_input ();
2256 static void
2257 ns_frame_up_to_date (struct frame *f)
2258 /* --------------------------------------------------------------------------
2259     External (hook): Fix up mouse highlighting right after a full update.
2260     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2261    -------------------------------------------------------------------------- */
2263   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2265   if (FRAME_NS_P (f))
2266     {
2267       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2268       if (f == hlinfo->mouse_face_mouse_frame)
2269         {
2270           block_input ();
2271           ns_update_begin(f);
2272           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2273                                 hlinfo->mouse_face_mouse_x,
2274                                 hlinfo->mouse_face_mouse_y);
2275           ns_update_end(f);
2276           unblock_input ();
2277         }
2278     }
2282 static void
2283 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2284 /* --------------------------------------------------------------------------
2285     External (RIF): set frame mouse pointer type.
2286    -------------------------------------------------------------------------- */
2288   NSTRACE ("ns_define_frame_cursor");
2289   if (FRAME_POINTER_TYPE (f) != cursor)
2290     {
2291       EmacsView *view = FRAME_NS_VIEW (f);
2292       FRAME_POINTER_TYPE (f) = cursor;
2293       [[view window] invalidateCursorRectsForView: view];
2294       /* Redisplay assumes this function also draws the changed frame
2295          cursor, but this function doesn't, so do it explicitly.  */
2296       x_update_cursor (f, 1);
2297     }
2302 /* ==========================================================================
2304     Keyboard handling
2306    ========================================================================== */
2309 static unsigned
2310 ns_convert_key (unsigned code)
2311 /* --------------------------------------------------------------------------
2312     Internal call used by NSView-keyDown.
2313    -------------------------------------------------------------------------- */
2315   const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2316   unsigned keysym;
2317   /* An array would be faster, but less easy to read. */
2318   for (keysym = 0; keysym < last_keysym; keysym += 2)
2319     if (code == convert_ns_to_X_keysym[keysym])
2320       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2321   return 0;
2322 /* if decide to use keyCode and Carbon table, use this line:
2323      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2327 char *
2328 x_get_keysym_name (int keysym)
2329 /* --------------------------------------------------------------------------
2330     Called by keyboard.c.  Not sure if the return val is important, except
2331     that it be unique.
2332    -------------------------------------------------------------------------- */
2334   static char value[16];
2335   NSTRACE ("x_get_keysym_name");
2336   sprintf (value, "%d", keysym);
2337   return value;
2342 /* ==========================================================================
2344     Block drawing operations
2346    ========================================================================== */
2349 static void
2350 ns_redraw_scroll_bars (struct frame *f)
2352   int i;
2353   id view;
2354   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2355   NSTRACE ("ns_redraw_scroll_bars");
2356   for (i =[subviews count]-1; i >= 0; i--)
2357     {
2358       view = [subviews objectAtIndex: i];
2359       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2360       [view display];
2361     }
2365 void
2366 ns_clear_frame (struct frame *f)
2367 /* --------------------------------------------------------------------------
2368       External (hook): Erase the entire frame
2369    -------------------------------------------------------------------------- */
2371   NSView *view = FRAME_NS_VIEW (f);
2372   NSRect r;
2374   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2376  /* comes on initial frame because we have
2377     after-make-frame-functions = select-frame */
2378  if (!FRAME_DEFAULT_FACE (f))
2379    return;
2381   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2383   r = [view bounds];
2385   block_input ();
2386   ns_focus (f, &r, 1);
2387   [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2388                             (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
2389   NSRectFill (r);
2390   ns_unfocus (f);
2392   /* as of 2006/11 or so this is now needed */
2393   ns_redraw_scroll_bars (f);
2394   unblock_input ();
2398 static void
2399 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2400 /* --------------------------------------------------------------------------
2401     External (RIF):  Clear section of frame
2402    -------------------------------------------------------------------------- */
2404   NSRect r = NSMakeRect (x, y, width, height);
2405   NSView *view = FRAME_NS_VIEW (f);
2406   struct face *face = FRAME_DEFAULT_FACE (f);
2408   if (!view || !face)
2409     return;
2411   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2413   r = NSIntersectionRect (r, [view frame]);
2414   ns_focus (f, &r, 1);
2415   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2417   NSRectFill (r);
2419   ns_unfocus (f);
2420   return;
2423 static void
2424 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2426   NSTRACE ("ns_copy_bits");
2428   if (FRAME_NS_VIEW (f))
2429     {
2430       hide_bell();              // Ensure the bell image isn't scrolled.
2432       ns_focus (f, &dest, 1);
2433       [FRAME_NS_VIEW (f) scrollRect: src
2434                                  by: NSMakeSize (dest.origin.x - src.origin.x,
2435                                                  dest.origin.y - src.origin.y)];
2436       ns_unfocus (f);
2437     }
2440 static void
2441 ns_scroll_run (struct window *w, struct run *run)
2442 /* --------------------------------------------------------------------------
2443     External (RIF):  Insert or delete n lines at line vpos
2444    -------------------------------------------------------------------------- */
2446   struct frame *f = XFRAME (w->frame);
2447   int x, y, width, height, from_y, to_y, bottom_y;
2449   NSTRACE ("ns_scroll_run");
2451   /* begin copy from other terms */
2452   /* Get frame-relative bounding box of the text display area of W,
2453      without mode lines.  Include in this box the left and right
2454      fringe of W.  */
2455   window_box (w, ANY_AREA, &x, &y, &width, &height);
2457   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2458   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2459   bottom_y = y + height;
2461   if (to_y < from_y)
2462     {
2463       /* Scrolling up.  Make sure we don't copy part of the mode
2464          line at the bottom.  */
2465       if (from_y + run->height > bottom_y)
2466         height = bottom_y - from_y;
2467       else
2468         height = run->height;
2469     }
2470   else
2471     {
2472       /* Scrolling down.  Make sure we don't copy over the mode line.
2473          at the bottom.  */
2474       if (to_y + run->height > bottom_y)
2475         height = bottom_y - to_y;
2476       else
2477         height = run->height;
2478     }
2479   /* end copy from other terms */
2481   if (height == 0)
2482       return;
2484   block_input ();
2486   x_clear_cursor (w);
2488   {
2489     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2490     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2492     ns_copy_bits (f, srcRect , dstRect);
2493   }
2495   unblock_input ();
2499 static void
2500 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2501 /* --------------------------------------------------------------------------
2502     External (RIF): preparatory to fringe update after text was updated
2503    -------------------------------------------------------------------------- */
2505   struct frame *f;
2506   int width, height;
2508   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2510   /* begin copy from other terms */
2511   eassert (w);
2513   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2514     desired_row->redraw_fringe_bitmaps_p = 1;
2516   /* When a window has disappeared, make sure that no rest of
2517      full-width rows stays visible in the internal border.  */
2518   if (windows_or_buffers_changed
2519       && desired_row->full_width_p
2520       && (f = XFRAME (w->frame),
2521           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2522           width != 0)
2523       && (height = desired_row->visible_height,
2524           height > 0))
2525     {
2526       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2528       block_input ();
2529       ns_clear_frame_area (f, 0, y, width, height);
2530       ns_clear_frame_area (f,
2531                            FRAME_PIXEL_WIDTH (f) - width,
2532                            y, width, height);
2533       unblock_input ();
2534     }
2538 static void
2539 ns_shift_glyphs_for_insert (struct frame *f,
2540                            int x, int y, int width, int height,
2541                            int shift_by)
2542 /* --------------------------------------------------------------------------
2543     External (RIF): copy an area horizontally, don't worry about clearing src
2544    -------------------------------------------------------------------------- */
2546   NSRect srcRect = NSMakeRect (x, y, width, height);
2547   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2549   NSTRACE ("ns_shift_glyphs_for_insert");
2551   ns_copy_bits (f, srcRect, dstRect);
2556 /* ==========================================================================
2558     Character encoding and metrics
2560    ========================================================================== */
2563 static void
2564 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2565 /* --------------------------------------------------------------------------
2566      External (RIF); compute left/right overhang of whole string and set in s
2567    -------------------------------------------------------------------------- */
2569   struct font *font = s->font;
2571   if (s->char2b)
2572     {
2573       struct font_metrics metrics;
2574       unsigned int codes[2];
2575       codes[0] = *(s->char2b);
2576       codes[1] = *(s->char2b + s->nchars - 1);
2578       font->driver->text_extents (font, codes, 2, &metrics);
2579       s->left_overhang = -metrics.lbearing;
2580       s->right_overhang
2581         = metrics.rbearing > metrics.width
2582         ? metrics.rbearing - metrics.width : 0;
2583     }
2584   else
2585     {
2586       s->left_overhang = 0;
2587       if (EQ (font->driver->type, Qns))
2588         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2589           FONT_HEIGHT (font) * 0.2 : 0;
2590       else
2591         s->right_overhang = 0;
2592     }
2597 /* ==========================================================================
2599     Fringe and cursor drawing
2601    ========================================================================== */
2604 extern int max_used_fringe_bitmap;
2605 static void
2606 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2607                       struct draw_fringe_bitmap_params *p)
2608 /* --------------------------------------------------------------------------
2609     External (RIF); fringe-related
2610    -------------------------------------------------------------------------- */
2612   /* Fringe bitmaps comes in two variants, normal and periodic.  A
2613      periodic bitmap is used to create a continuous pattern.  Since a
2614      bitmap is rendered one text line at a time, the start offset (dh)
2615      of the bitmap varies.  Concretely, this is used for the empty
2616      line indicator.
2618      For a bitmap, "h + dh" is the full height and is always
2619      invariant.  For a normal bitmap "dh" is zero.
2621      For example, when the period is three and the full height is 72
2622      the following combinations exists:
2624        h=72 dh=0
2625        h=71 dh=1
2626        h=70 dh=2 */
2628   struct frame *f = XFRAME (WINDOW_FRAME (w));
2629   struct face *face = p->face;
2630   static EmacsImage **bimgs = NULL;
2631   static int nBimgs = 0;
2633   NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2634   NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2635                p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2637   /* grow bimgs if needed */
2638   if (nBimgs < max_used_fringe_bitmap)
2639     {
2640       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2641       memset (bimgs + nBimgs, 0,
2642               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2643       nBimgs = max_used_fringe_bitmap;
2644     }
2646   /* Must clip because of partially visible lines.  */
2647   ns_clip_to_row (w, row, ANY_AREA, YES);
2649   if (!p->overlay_p)
2650     {
2651       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2653       if (bx >= 0 && nx > 0)
2654         {
2655           NSRect r = NSMakeRect (bx, by, nx, ny);
2656           NSRectClip (r);
2657           [ns_lookup_indexed_color (face->background, f) set];
2658           NSRectFill (r);
2659         }
2660     }
2662   if (p->which)
2663     {
2664       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2665       EmacsImage *img = bimgs[p->which - 1];
2667       if (!img)
2668         {
2669           // Note: For "periodic" images, allocate one EmacsImage for
2670           // the base image, and use it for all dh:s.
2671           unsigned short *bits = p->bits;
2672           int full_height = p->h + p->dh;
2673           int i;
2674           unsigned char *cbits = xmalloc (full_height);
2676           for (i = 0; i < full_height; i++)
2677             cbits[i] = bits[i];
2678           img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2679                                          height: full_height
2680                                              fg: 0 bg: 0];
2681           bimgs[p->which - 1] = img;
2682           xfree (cbits);
2683         }
2685       NSTRACE_RECT ("r", r);
2687       NSRectClip (r);
2688       /* Since we composite the bitmap instead of just blitting it, we need
2689          to erase the whole background. */
2690       [ns_lookup_indexed_color(face->background, f) set];
2691       NSRectFill (r);
2693       {
2694         NSColor *bm_color;
2695         if (!p->cursor_p)
2696           bm_color = ns_lookup_indexed_color(face->foreground, f);
2697         else if (p->overlay_p)
2698           bm_color = ns_lookup_indexed_color(face->background, f);
2699         else
2700           bm_color = f->output_data.ns->cursor_color;
2701         [img setXBMColor: bm_color];
2702       }
2704 #ifdef NS_IMPL_COCOA
2705       // Note: For periodic images, the full image height is "h + hd".
2706       // By using the height h, a suitable part of the image is used.
2707       NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2709       NSTRACE_RECT ("fromRect", fromRect);
2711       [img drawInRect: r
2712               fromRect: fromRect
2713              operation: NSCompositingOperationSourceOver
2714               fraction: 1.0
2715            respectFlipped: YES
2716                 hints: nil];
2717 #else
2718       {
2719         NSPoint pt = r.origin;
2720         pt.y += p->h;
2721         [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
2722       }
2723 #endif
2724     }
2725   ns_unfocus (f);
2729 static void
2730 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2731                        int x, int y, enum text_cursor_kinds cursor_type,
2732                        int cursor_width, bool on_p, bool active_p)
2733 /* --------------------------------------------------------------------------
2734      External call (RIF): draw cursor.
2735      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2736    -------------------------------------------------------------------------- */
2738   NSRect r, s;
2739   int fx, fy, h, cursor_height;
2740   struct frame *f = WINDOW_XFRAME (w);
2741   struct glyph *phys_cursor_glyph;
2742   struct glyph *cursor_glyph;
2743   struct face *face;
2744   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2746   /* If cursor is out of bounds, don't draw garbage.  This can happen
2747      in mini-buffer windows when switching between echo area glyphs
2748      and mini-buffer.  */
2750   NSTRACE ("ns_draw_window_cursor");
2752   if (!on_p)
2753     return;
2755   w->phys_cursor_type = cursor_type;
2756   w->phys_cursor_on_p = on_p;
2758   if (cursor_type == NO_CURSOR)
2759     {
2760       w->phys_cursor_width = 0;
2761       return;
2762     }
2764   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2765     {
2766       if (glyph_row->exact_window_width_line_p
2767           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2768         {
2769           glyph_row->cursor_in_fringe_p = 1;
2770           draw_fringe_bitmap (w, glyph_row, 0);
2771         }
2772       return;
2773     }
2775   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2776      (other terminals do it the other way round).  We must set
2777      w->phys_cursor_width to the cursor width.  For bar cursors, that
2778      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2779   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2781   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2782      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2783   if (cursor_type == BAR_CURSOR)
2784     {
2785       if (cursor_width < 1)
2786         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2788       /* The bar cursor should never be wider than the glyph. */
2789       if (cursor_width < w->phys_cursor_width)
2790         w->phys_cursor_width = cursor_width;
2791     }
2792   /* If we have an HBAR, "cursor_width" MAY specify height. */
2793   else if (cursor_type == HBAR_CURSOR)
2794     {
2795       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2796       if (cursor_height > glyph_row->height)
2797         cursor_height = glyph_row->height;
2798       if (h > cursor_height) // Cursor smaller than line height, move down
2799         fy += h - cursor_height;
2800       h = cursor_height;
2801     }
2803   r.origin.x = fx, r.origin.y = fy;
2804   r.size.height = h;
2805   r.size.width = w->phys_cursor_width;
2807   /* Prevent the cursor from being drawn outside the text area. */
2808   ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2811   face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
2812   if (face && NS_FACE_BACKGROUND (face)
2813       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2814     {
2815       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2816       hollow_color = FRAME_CURSOR_COLOR (f);
2817     }
2818   else
2819     [FRAME_CURSOR_COLOR (f) set];
2821 #ifdef NS_IMPL_COCOA
2822   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2823            atomic.  Cleaner ways of doing this should be investigated.
2824            One way would be to set a global variable DRAWING_CURSOR
2825            when making the call to draw_phys..(), don't focus in that
2826            case, then move the ns_unfocus() here after that call. */
2827   NSDisableScreenUpdates ();
2828 #endif
2830   switch (cursor_type)
2831     {
2832     case DEFAULT_CURSOR:
2833     case NO_CURSOR:
2834       break;
2835     case FILLED_BOX_CURSOR:
2836       NSRectFill (r);
2837       break;
2838     case HOLLOW_BOX_CURSOR:
2839       NSRectFill (r);
2840       [hollow_color set];
2841       NSRectFill (NSInsetRect (r, 1, 1));
2842       [FRAME_CURSOR_COLOR (f) set];
2843       break;
2844     case HBAR_CURSOR:
2845       NSRectFill (r);
2846       break;
2847     case BAR_CURSOR:
2848       s = r;
2849       /* If the character under cursor is R2L, draw the bar cursor
2850          on the right of its glyph, rather than on the left.  */
2851       cursor_glyph = get_phys_cursor_glyph (w);
2852       if ((cursor_glyph->resolved_level & 1) != 0)
2853         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2855       NSRectFill (s);
2856       break;
2857     }
2858   ns_unfocus (f);
2860   /* draw the character under the cursor */
2861   if (cursor_type != NO_CURSOR)
2862     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2864 #ifdef NS_IMPL_COCOA
2865   NSEnableScreenUpdates ();
2866 #endif
2871 static void
2872 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2873 /* --------------------------------------------------------------------------
2874      External (RIF): Draw a vertical line.
2875    -------------------------------------------------------------------------- */
2877   struct frame *f = XFRAME (WINDOW_FRAME (w));
2878   struct face *face;
2879   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2881   NSTRACE ("ns_draw_vertical_window_border");
2883   face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
2885   ns_focus (f, &r, 1);
2886   if (face)
2887     [ns_lookup_indexed_color(face->foreground, f) set];
2889   NSRectFill(r);
2890   ns_unfocus (f);
2894 static void
2895 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2896 /* --------------------------------------------------------------------------
2897      External (RIF): Draw a window divider.
2898    -------------------------------------------------------------------------- */
2900   struct frame *f = XFRAME (WINDOW_FRAME (w));
2901   struct face *face;
2902   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2904   NSTRACE ("ns_draw_window_divider");
2906   face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
2908   ns_focus (f, &r, 1);
2909   if (face)
2910     [ns_lookup_indexed_color(face->foreground, f) set];
2912   NSRectFill(r);
2913   ns_unfocus (f);
2916 static void
2917 ns_show_hourglass (struct frame *f)
2919   /* TODO: add NSProgressIndicator to all frames.  */
2922 static void
2923 ns_hide_hourglass (struct frame *f)
2925   /* TODO: remove NSProgressIndicator from all frames.  */
2928 /* ==========================================================================
2930     Glyph drawing operations
2932    ========================================================================== */
2934 static int
2935 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2936 /* --------------------------------------------------------------------------
2937     Wrapper utility to account for internal border width on full-width lines,
2938     and allow top full-width rows to hit the frame top.  nr should be pointer
2939     to two successive NSRects.  Number of rects actually used is returned.
2940    -------------------------------------------------------------------------- */
2942   int n = get_glyph_string_clip_rects (s, nr, 2);
2943   return n;
2946 /* --------------------------------------------------------------------
2947    Draw a wavy line under glyph string s. The wave fills wave_height
2948    pixels from y.
2950                     x          wave_length = 2
2951                                  --
2952                 y    *   *   *   *   *
2953                      |* * * * * * * * *
2954     wave_height = 3  | *   *   *   *
2955   --------------------------------------------------------------------- */
2957 static void
2958 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2960   int wave_height = 3, wave_length = 2;
2961   int y, dx, dy, odd, xmax;
2962   NSPoint a, b;
2963   NSRect waveClip;
2965   dx = wave_length;
2966   dy = wave_height - 1;
2967   y =  s->ybase - wave_height + 3;
2968   xmax = x + width;
2970   /* Find and set clipping rectangle */
2971   waveClip = NSMakeRect (x, y, width, wave_height);
2972   [[NSGraphicsContext currentContext] saveGraphicsState];
2973   NSRectClip (waveClip);
2975   /* Draw the waves */
2976   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2977   b.x = a.x + dx;
2978   odd = (int)(a.x/dx) % 2;
2979   a.y = b.y = y + 0.5;
2981   if (odd)
2982     a.y += dy;
2983   else
2984     b.y += dy;
2986   while (a.x <= xmax)
2987     {
2988       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2989       a.x = b.x, a.y = b.y;
2990       b.x += dx, b.y = y + 0.5 + odd*dy;
2991       odd = !odd;
2992     }
2994   /* Restore previous clipping rectangle(s) */
2995   [[NSGraphicsContext currentContext] restoreGraphicsState];
3000 static void
3001 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3002                          NSColor *defaultCol, CGFloat width, CGFloat x)
3003 /* --------------------------------------------------------------------------
3004    Draw underline, overline, and strike-through on glyph string s.
3005    -------------------------------------------------------------------------- */
3007   if (s->for_overlaps)
3008     return;
3010   /* Do underline. */
3011   if (face->underline_p)
3012     {
3013       if (s->face->underline_type == FACE_UNDER_WAVE)
3014         {
3015           if (face->underline_defaulted_p)
3016             [defaultCol set];
3017           else
3018             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3020           ns_draw_underwave (s, width, x);
3021         }
3022       else if (s->face->underline_type == FACE_UNDER_LINE)
3023         {
3025           NSRect r;
3026           unsigned long thickness, position;
3028           /* If the prev was underlined, match its appearance. */
3029           if (s->prev && s->prev->face->underline_p
3030               && s->prev->face->underline_type == FACE_UNDER_LINE
3031               && s->prev->underline_thickness > 0)
3032             {
3033               thickness = s->prev->underline_thickness;
3034               position = s->prev->underline_position;
3035             }
3036           else
3037             {
3038               struct font *font;
3039               unsigned long descent;
3041               font=s->font;
3042               descent = s->y + s->height - s->ybase;
3044               /* Use underline thickness of font, defaulting to 1. */
3045               thickness = (font && font->underline_thickness > 0)
3046                 ? font->underline_thickness : 1;
3048               /* Determine the offset of underlining from the baseline. */
3049               if (x_underline_at_descent_line)
3050                 position = descent - thickness;
3051               else if (x_use_underline_position_properties
3052                        && font && font->underline_position >= 0)
3053                 position = font->underline_position;
3054               else if (font)
3055                 position = lround (font->descent / 2);
3056               else
3057                 position = underline_minimum_offset;
3059               position = max (position, underline_minimum_offset);
3061               /* Ensure underlining is not cropped. */
3062               if (descent <= position)
3063                 {
3064                   position = descent - 1;
3065                   thickness = 1;
3066                 }
3067               else if (descent < position + thickness)
3068                 thickness = 1;
3069             }
3071           s->underline_thickness = thickness;
3072           s->underline_position = position;
3074           r = NSMakeRect (x, s->ybase + position, width, thickness);
3076           if (face->underline_defaulted_p)
3077             [defaultCol set];
3078           else
3079             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3080           NSRectFill (r);
3081         }
3082     }
3083   /* Do overline. We follow other terms in using a thickness of 1
3084      and ignoring overline_margin. */
3085   if (face->overline_p)
3086     {
3087       NSRect r;
3088       r = NSMakeRect (x, s->y, width, 1);
3090       if (face->overline_color_defaulted_p)
3091         [defaultCol set];
3092       else
3093         [ns_lookup_indexed_color (face->overline_color, s->f) set];
3094       NSRectFill (r);
3095     }
3097   /* Do strike-through.  We follow other terms for thickness and
3098      vertical position.*/
3099   if (face->strike_through_p)
3100     {
3101       NSRect r;
3102       unsigned long dy;
3104       dy = lrint ((s->height - 1) / 2);
3105       r = NSMakeRect (x, s->y + dy, width, 1);
3107       if (face->strike_through_color_defaulted_p)
3108         [defaultCol set];
3109       else
3110         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3111       NSRectFill (r);
3112     }
3115 static void
3116 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3117              char left_p, char right_p)
3118 /* --------------------------------------------------------------------------
3119     Draw an unfilled rect inside r, optionally leaving left and/or right open.
3120     Note we can't just use an NSDrawRect command, because of the possibility
3121     of some sides not being drawn, and because the rect will be filled.
3122    -------------------------------------------------------------------------- */
3124   NSRect s = r;
3125   [col set];
3127   /* top, bottom */
3128   s.size.height = thickness;
3129   NSRectFill (s);
3130   s.origin.y += r.size.height - thickness;
3131   NSRectFill (s);
3133   s.size.height = r.size.height;
3134   s.origin.y = r.origin.y;
3136   /* left, right (optional) */
3137   s.size.width = thickness;
3138   if (left_p)
3139     NSRectFill (s);
3140   if (right_p)
3141     {
3142       s.origin.x += r.size.width - thickness;
3143       NSRectFill (s);
3144     }
3148 static void
3149 ns_draw_relief (NSRect r, int thickness, char raised_p,
3150                char top_p, char bottom_p, char left_p, char right_p,
3151                struct glyph_string *s)
3152 /* --------------------------------------------------------------------------
3153     Draw a relief rect inside r, optionally leaving some sides open.
3154     Note we can't just use an NSDrawBezel command, because of the possibility
3155     of some sides not being drawn, and because the rect will be filled.
3156    -------------------------------------------------------------------------- */
3158   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3159   NSColor *newBaseCol = nil;
3160   NSRect sr = r;
3162   NSTRACE ("ns_draw_relief");
3164   /* set up colors */
3166   if (s->face->use_box_color_for_shadows_p)
3167     {
3168       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3169     }
3170 /*     else if (s->first_glyph->type == IMAGE_GLYPH
3171            && s->img->pixmap
3172            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3173        {
3174          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
3175        } */
3176   else
3177     {
3178       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3179     }
3181   if (newBaseCol == nil)
3182     newBaseCol = [NSColor grayColor];
3184   if (newBaseCol != baseCol)  /* TODO: better check */
3185     {
3186       [baseCol release];
3187       baseCol = [newBaseCol retain];
3188       [lightCol release];
3189       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3190       [darkCol release];
3191       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3192     }
3194   [(raised_p ? lightCol : darkCol) set];
3196   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3198   /* top */
3199   sr.size.height = thickness;
3200   if (top_p) NSRectFill (sr);
3202   /* left */
3203   sr.size.height = r.size.height;
3204   sr.size.width = thickness;
3205   if (left_p) NSRectFill (sr);
3207   [(raised_p ? darkCol : lightCol) set];
3209   /* bottom */
3210   sr.size.width = r.size.width;
3211   sr.size.height = thickness;
3212   sr.origin.y += r.size.height - thickness;
3213   if (bottom_p) NSRectFill (sr);
3215   /* right */
3216   sr.size.height = r.size.height;
3217   sr.origin.y = r.origin.y;
3218   sr.size.width = thickness;
3219   sr.origin.x += r.size.width - thickness;
3220   if (right_p) NSRectFill (sr);
3224 static void
3225 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3226 /* --------------------------------------------------------------------------
3227       Function modeled after x_draw_glyph_string_box ().
3228       Sets up parameters for drawing.
3229    -------------------------------------------------------------------------- */
3231   int right_x, last_x;
3232   char left_p, right_p;
3233   struct glyph *last_glyph;
3234   NSRect r;
3235   int thickness;
3236   struct face *face;
3238   if (s->hl == DRAW_MOUSE_FACE)
3239     {
3240       face = FACE_FROM_ID_OR_NULL (s->f,
3241                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3242       if (!face)
3243         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3244     }
3245   else
3246     face = s->face;
3248   thickness = face->box_line_width;
3250   NSTRACE ("ns_dumpglyphs_box_or_relief");
3252   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3253             ? WINDOW_RIGHT_EDGE_X (s->w)
3254             : window_box_right (s->w, s->area));
3255   last_glyph = (s->cmp || s->img
3256                 ? s->first_glyph : s->first_glyph + s->nchars-1);
3258   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3259               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3261   left_p = (s->first_glyph->left_box_line_p
3262             || (s->hl == DRAW_MOUSE_FACE
3263                 && (s->prev == NULL || s->prev->hl != s->hl)));
3264   right_p = (last_glyph->right_box_line_p
3265              || (s->hl == DRAW_MOUSE_FACE
3266                  && (s->next == NULL || s->next->hl != s->hl)));
3268   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3270   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3271   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3272     {
3273       ns_draw_box (r, abs (thickness),
3274                    ns_lookup_indexed_color (face->box_color, s->f),
3275                   left_p, right_p);
3276     }
3277   else
3278     {
3279       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3280                      1, 1, left_p, right_p, s);
3281     }
3285 static void
3286 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3287 /* --------------------------------------------------------------------------
3288       Modeled after x_draw_glyph_string_background, which draws BG in
3289       certain cases.  Others are left to the text rendering routine.
3290    -------------------------------------------------------------------------- */
3292   NSTRACE ("ns_maybe_dumpglyphs_background");
3294   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3295     {
3296       int box_line_width = max (s->face->box_line_width, 0);
3297       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3298           /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3299              dimensions, since the actual glyphs might be much
3300              smaller.  So in that case we always clear the rectangle
3301              with background color.  */
3302           || FONT_TOO_HIGH (s->font)
3303           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3304         {
3305           struct face *face;
3306           if (s->hl == DRAW_MOUSE_FACE)
3307             {
3308               face
3309                 = FACE_FROM_ID_OR_NULL (s->f,
3310                                         MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3311               if (!face)
3312                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3313             }
3314           else
3315             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3316           if (!face->stipple)
3317             [(NS_FACE_BACKGROUND (face) != 0
3318               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3319               : FRAME_BACKGROUND_COLOR (s->f)) set];
3320           else
3321             {
3322               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3323               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3324             }
3326           if (s->hl != DRAW_CURSOR)
3327             {
3328               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3329                                     s->background_width,
3330                                     s->height-2*box_line_width);
3331               NSRectFill (r);
3332             }
3334           s->background_filled_p = 1;
3335         }
3336     }
3340 static void
3341 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3342 /* --------------------------------------------------------------------------
3343       Renders an image and associated borders.
3344    -------------------------------------------------------------------------- */
3346   EmacsImage *img = s->img->pixmap;
3347   int box_line_vwidth = max (s->face->box_line_width, 0);
3348   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3349   int bg_x, bg_y, bg_height;
3350   int th;
3351   char raised_p;
3352   NSRect br;
3353   struct face *face;
3354   NSColor *tdCol;
3356   NSTRACE ("ns_dumpglyphs_image");
3358   if (s->face->box != FACE_NO_BOX
3359       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3360     x += abs (s->face->box_line_width);
3362   bg_x = x;
3363   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3364   bg_height = s->height;
3365   /* other terms have this, but was causing problems w/tabbar mode */
3366   /* - 2 * box_line_vwidth; */
3368   if (s->slice.x == 0) x += s->img->hmargin;
3369   if (s->slice.y == 0) y += s->img->vmargin;
3371   /* Draw BG: if we need larger area than image itself cleared, do that,
3372      otherwise, since we composite the image under NS (instead of mucking
3373      with its background color), we must clear just the image area. */
3374   if (s->hl == DRAW_MOUSE_FACE)
3375     {
3376       face = FACE_FROM_ID_OR_NULL (s->f,
3377                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3378       if (!face)
3379        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3380     }
3381   else
3382     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3384   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3386   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3387       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3388     {
3389       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3390       s->background_filled_p = 1;
3391     }
3392   else
3393     {
3394       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3395     }
3397   NSRectFill (br);
3399   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3400   if (img != nil)
3401     {
3402 #ifdef NS_IMPL_COCOA
3403       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3404       NSRect ir = NSMakeRect (s->slice.x,
3405                               s->img->height - s->slice.y - s->slice.height,
3406                               s->slice.width, s->slice.height);
3407       [img drawInRect: dr
3408              fromRect: ir
3409              operation: NSCompositingOperationSourceOver
3410               fraction: 1.0
3411            respectFlipped: YES
3412                 hints: nil];
3413 #else
3414       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3415                   operation: NSCompositingOperationSourceOver];
3416 #endif
3417     }
3419   if (s->hl == DRAW_CURSOR)
3420     {
3421     [FRAME_CURSOR_COLOR (s->f) set];
3422     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3423       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3424     else
3425       /* Currently on NS img->mask is always 0. Since
3426          get_window_cursor_type specifies a hollow box cursor when on
3427          a non-masked image we never reach this clause. But we put it
3428          in in anticipation of better support for image masks on
3429          NS. */
3430       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3431     }
3432   else
3433     {
3434       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3435     }
3437   /* Draw underline, overline, strike-through. */
3438   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3440   /* Draw relief, if requested */
3441   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3442     {
3443       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3444         {
3445           th = tool_bar_button_relief >= 0 ?
3446             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3447           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3448         }
3449       else
3450         {
3451           th = abs (s->img->relief);
3452           raised_p = (s->img->relief > 0);
3453         }
3455       r.origin.x = x - th;
3456       r.origin.y = y - th;
3457       r.size.width = s->slice.width + 2*th-1;
3458       r.size.height = s->slice.height + 2*th-1;
3459       ns_draw_relief (r, th, raised_p,
3460                       s->slice.y == 0,
3461                       s->slice.y + s->slice.height == s->img->height,
3462                       s->slice.x == 0,
3463                       s->slice.x + s->slice.width == s->img->width, s);
3464     }
3466   /* If there is no mask, the background won't be seen,
3467      so draw a rectangle on the image for the cursor.
3468      Do this for all images, getting transparency right is not reliable.  */
3469   if (s->hl == DRAW_CURSOR)
3470     {
3471       int thickness = abs (s->img->relief);
3472       if (thickness == 0) thickness = 1;
3473       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3474     }
3478 static void
3479 ns_dumpglyphs_stretch (struct glyph_string *s)
3481   NSRect r[2];
3482   int n, i;
3483   struct face *face;
3484   NSColor *fgCol, *bgCol;
3486   if (!s->background_filled_p)
3487     {
3488       n = ns_get_glyph_string_clip_rect (s, r);
3489       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3491       ns_focus (s->f, r, n);
3493       if (s->hl == DRAW_MOUSE_FACE)
3494        {
3495          face = FACE_FROM_ID_OR_NULL (s->f,
3496                                       MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3497          if (!face)
3498            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3499        }
3500       else
3501        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3503       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3504       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3506       for (i = 0; i < n; ++i)
3507         {
3508           if (!s->row->full_width_p)
3509             {
3510               int overrun, leftoverrun;
3512               /* truncate to avoid overwriting fringe and/or scrollbar */
3513               overrun = max (0, (s->x + s->background_width)
3514                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3515                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3516               r[i].size.width -= overrun;
3518               /* truncate to avoid overwriting to left of the window box */
3519               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3520                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3522               if (leftoverrun > 0)
3523                 {
3524                   r[i].origin.x += leftoverrun;
3525                   r[i].size.width -= leftoverrun;
3526                 }
3528               /* XXX: Try to work between problem where a stretch glyph on
3529                  a partially-visible bottom row will clear part of the
3530                  modeline, and another where list-buffers headers and similar
3531                  rows erroneously have visible_height set to 0.  Not sure
3532                  where this is coming from as other terms seem not to show. */
3533               r[i].size.height = min (s->height, s->row->visible_height);
3534             }
3536           [bgCol set];
3538           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3539              overwriting cursor (usually when cursor on a tab) */
3540           if (s->hl == DRAW_CURSOR)
3541             {
3542               CGFloat x, width;
3544               x = r[i].origin.x;
3545               width = s->w->phys_cursor_width;
3546               r[i].size.width -= width;
3547               r[i].origin.x += width;
3549               NSRectFill (r[i]);
3551               /* Draw overlining, etc. on the cursor. */
3552               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3553                 ns_draw_text_decoration (s, face, bgCol, width, x);
3554               else
3555                 ns_draw_text_decoration (s, face, fgCol, width, x);
3556             }
3557           else
3558             {
3559               NSRectFill (r[i]);
3560             }
3562           /* Draw overlining, etc. on the stretch glyph (or the part
3563              of the stretch glyph after the cursor). */
3564           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3565                                    r[i].origin.x);
3566         }
3567       ns_unfocus (s->f);
3568       s->background_filled_p = 1;
3569     }
3573 static void
3574 ns_draw_glyph_string_foreground (struct glyph_string *s)
3576   int x, flags;
3577   struct font *font = s->font;
3579   /* If first glyph of S has a left box line, start drawing the text
3580      of S to the right of that box line.  */
3581   if (s->face && s->face->box != FACE_NO_BOX
3582       && s->first_glyph->left_box_line_p)
3583     x = s->x + eabs (s->face->box_line_width);
3584   else
3585     x = s->x;
3587   flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3588     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3589      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3590       NS_DUMPGLYPH_NORMAL));
3592   font->driver->draw
3593     (s, s->cmp_from, s->nchars, x, s->ybase,
3594      (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3595      || flags == NS_DUMPGLYPH_MOUSEFACE);
3599 static void
3600 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3602   int i, j, x;
3603   struct font *font = s->font;
3605   /* If first glyph of S has a left box line, start drawing the text
3606      of S to the right of that box line.  */
3607   if (s->face && s->face->box != FACE_NO_BOX
3608       && s->first_glyph->left_box_line_p)
3609     x = s->x + eabs (s->face->box_line_width);
3610   else
3611     x = s->x;
3613   /* S is a glyph string for a composition.  S->cmp_from is the index
3614      of the first character drawn for glyphs of this composition.
3615      S->cmp_from == 0 means we are drawing the very first character of
3616      this composition.  */
3618   /* Draw a rectangle for the composition if the font for the very
3619      first character of the composition could not be loaded.  */
3620   if (s->font_not_found_p)
3621     {
3622       if (s->cmp_from == 0)
3623         {
3624           NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3625           ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3626         }
3627     }
3628   else if (! s->first_glyph->u.cmp.automatic)
3629     {
3630       int y = s->ybase;
3632       for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3633         /* TAB in a composition means display glyphs with padding
3634            space on the left or right.  */
3635         if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3636           {
3637             int xx = x + s->cmp->offsets[j * 2];
3638             int yy = y - s->cmp->offsets[j * 2 + 1];
3640             font->driver->draw (s, j, j + 1, xx, yy, false);
3641             if (s->face->overstrike)
3642               font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3643           }
3644     }
3645   else
3646     {
3647       Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3648       Lisp_Object glyph;
3649       int y = s->ybase;
3650       int width = 0;
3652       for (i = j = s->cmp_from; i < s->cmp_to; i++)
3653         {
3654           glyph = LGSTRING_GLYPH (gstring, i);
3655           if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3656             width += LGLYPH_WIDTH (glyph);
3657           else
3658             {
3659               int xoff, yoff, wadjust;
3661               if (j < i)
3662                 {
3663                   font->driver->draw (s, j, i, x, y, false);
3664                   if (s->face->overstrike)
3665                     font->driver->draw (s, j, i, x + 1, y, false);
3666                   x += width;
3667                 }
3668               xoff = LGLYPH_XOFF (glyph);
3669               yoff = LGLYPH_YOFF (glyph);
3670               wadjust = LGLYPH_WADJUST (glyph);
3671               font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3672               if (s->face->overstrike)
3673                 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3674                                     false);
3675               x += wadjust;
3676               j = i + 1;
3677               width = 0;
3678             }
3679         }
3680       if (j < i)
3681         {
3682           font->driver->draw (s, j, i, x, y, false);
3683           if (s->face->overstrike)
3684             font->driver->draw (s, j, i, x + 1, y, false);
3685         }
3686     }
3689 static void
3690 ns_draw_glyph_string (struct glyph_string *s)
3691 /* --------------------------------------------------------------------------
3692       External (RIF): Main draw-text call.
3693    -------------------------------------------------------------------------- */
3695   /* TODO (optimize): focus for box and contents draw */
3696   NSRect r[2];
3697   int n;
3698   char box_drawn_p = 0;
3699   struct font *font = s->face->font;
3700   if (! font) font = FRAME_FONT (s->f);
3702   NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3704   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3705     {
3706       int width;
3707       struct glyph_string *next;
3709       for (width = 0, next = s->next;
3710            next && width < s->right_overhang;
3711            width += next->width, next = next->next)
3712         if (next->first_glyph->type != IMAGE_GLYPH)
3713           {
3714             if (next->first_glyph->type != STRETCH_GLYPH)
3715               {
3716                 n = ns_get_glyph_string_clip_rect (s->next, r);
3717                 ns_focus (s->f, r, n);
3718                 ns_maybe_dumpglyphs_background (s->next, 1);
3719                 ns_unfocus (s->f);
3720               }
3721             else
3722               {
3723                 ns_dumpglyphs_stretch (s->next);
3724               }
3725             next->num_clips = 0;
3726           }
3727     }
3729   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3730         && (s->first_glyph->type == CHAR_GLYPH
3731             || s->first_glyph->type == COMPOSITE_GLYPH))
3732     {
3733       n = ns_get_glyph_string_clip_rect (s, r);
3734       ns_focus (s->f, r, n);
3735       ns_maybe_dumpglyphs_background (s, 1);
3736       ns_dumpglyphs_box_or_relief (s);
3737       ns_unfocus (s->f);
3738       box_drawn_p = 1;
3739     }
3741   switch (s->first_glyph->type)
3742     {
3744     case IMAGE_GLYPH:
3745       n = ns_get_glyph_string_clip_rect (s, r);
3746       ns_focus (s->f, r, n);
3747       ns_dumpglyphs_image (s, r[0]);
3748       ns_unfocus (s->f);
3749       break;
3751     case STRETCH_GLYPH:
3752       ns_dumpglyphs_stretch (s);
3753       break;
3755     case CHAR_GLYPH:
3756     case COMPOSITE_GLYPH:
3757       n = ns_get_glyph_string_clip_rect (s, r);
3758       ns_focus (s->f, r, n);
3760       if (s->for_overlaps || (s->cmp_from > 0
3761                               && ! s->first_glyph->u.cmp.automatic))
3762         s->background_filled_p = 1;
3763       else
3764         ns_maybe_dumpglyphs_background
3765           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3767       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3768         {
3769           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3770           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3771           NS_FACE_FOREGROUND (s->face) = tmp;
3772         }
3774       {
3775         BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3777         if (isComposite)
3778           ns_draw_composite_glyph_string_foreground (s);
3779         else
3780           ns_draw_glyph_string_foreground (s);
3781       }
3783       {
3784         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3785                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3786                                                    s->f)
3787                         : FRAME_FOREGROUND_COLOR (s->f));
3788         [col set];
3790         /* Draw underline, overline, strike-through. */
3791         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3792       }
3794       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3795         {
3796           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3797           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3798           NS_FACE_FOREGROUND (s->face) = tmp;
3799         }
3801       ns_unfocus (s->f);
3802       break;
3804     case GLYPHLESS_GLYPH:
3805       n = ns_get_glyph_string_clip_rect (s, r);
3806       ns_focus (s->f, r, n);
3808       if (s->for_overlaps || (s->cmp_from > 0
3809                               && ! s->first_glyph->u.cmp.automatic))
3810         s->background_filled_p = 1;
3811       else
3812         ns_maybe_dumpglyphs_background
3813           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3814       /* ... */
3815       /* Not yet implemented.  */
3816       /* ... */
3817       ns_unfocus (s->f);
3818       break;
3820     default:
3821       emacs_abort ();
3822     }
3824   /* Draw box if not done already. */
3825   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3826     {
3827       n = ns_get_glyph_string_clip_rect (s, r);
3828       ns_focus (s->f, r, n);
3829       ns_dumpglyphs_box_or_relief (s);
3830       ns_unfocus (s->f);
3831     }
3833   s->num_clips = 0;
3838 /* ==========================================================================
3840     Event loop
3842    ========================================================================== */
3845 static void
3846 ns_send_appdefined (int value)
3847 /* --------------------------------------------------------------------------
3848     Internal: post an appdefined event which EmacsApp-sendEvent will
3849               recognize and take as a command to halt the event loop.
3850    -------------------------------------------------------------------------- */
3852   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
3854   // GNUstep needs postEvent to happen on the main thread.
3855   // Cocoa needs nextEventMatchingMask to happen on the main thread too.
3856   if (! [[NSThread currentThread] isMainThread])
3857     {
3858       EmacsApp *app = (EmacsApp *)NSApp;
3859       app->nextappdefined = value;
3860       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3861                             withObject:nil
3862                          waitUntilDone:YES];
3863       return;
3864     }
3866   /* Only post this event if we haven't already posted one.  This will
3867      end the [NXApp run] main loop after having processed all events
3868      queued at this moment.  */
3869   NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
3870                                       untilDate:[NSDate distantPast]
3871                                          inMode:NSDefaultRunLoopMode
3872                                         dequeue:NO];
3873   if (! appev)
3874     {
3875       NSEvent *nxev;
3877       /* Don't need wakeup timer any more */
3878       if (timed_entry)
3879         {
3880           [timed_entry invalidate];
3881           [timed_entry release];
3882           timed_entry = nil;
3883         }
3885       nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
3886                                 location: NSMakePoint (0, 0)
3887                            modifierFlags: 0
3888                                timestamp: 0
3889                             windowNumber: [[NSApp mainWindow] windowNumber]
3890                                  context: [NSApp context]
3891                                  subtype: 0
3892                                    data1: value
3893                                    data2: 0];
3895       /* Post an application defined event on the event queue.  When this is
3896          received the [NXApp run] will return, thus having processed all
3897          events which are currently queued.  */
3898       [NSApp postEvent: nxev atStart: NO];
3899     }
3902 #ifdef HAVE_NATIVE_FS
3903 static void
3904 check_native_fs ()
3906   Lisp_Object frame, tail;
3908   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3909     return;
3911   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3913   FOR_EACH_FRAME (tail, frame)
3914     {
3915       struct frame *f = XFRAME (frame);
3916       if (FRAME_NS_P (f))
3917         {
3918           EmacsView *view = FRAME_NS_VIEW (f);
3919           [view updateCollectionBehavior];
3920         }
3921     }
3923 #endif
3925 /* GNUstep does not have cancelTracking.  */
3926 #ifdef NS_IMPL_COCOA
3927 /* Check if menu open should be canceled or continued as normal.  */
3928 void
3929 ns_check_menu_open (NSMenu *menu)
3931   /* Click in menu bar? */
3932   NSArray *a = [[NSApp mainMenu] itemArray];
3933   int i;
3934   BOOL found = NO;
3936   if (menu == nil) // Menu tracking ended.
3937     {
3938       if (menu_will_open_state == MENU_OPENING)
3939         menu_will_open_state = MENU_NONE;
3940       return;
3941     }
3943   for (i = 0; ! found && i < [a count]; i++)
3944     found = menu == [[a objectAtIndex:i] submenu];
3945   if (found)
3946     {
3947       if (menu_will_open_state == MENU_NONE && emacs_event)
3948         {
3949           NSEvent *theEvent = [NSApp currentEvent];
3950           struct frame *emacsframe = SELECTED_FRAME ();
3952           [menu cancelTracking];
3953           menu_will_open_state = MENU_PENDING;
3954           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3955           EV_TRAILER (theEvent);
3957           CGEventRef ourEvent = CGEventCreate (NULL);
3958           menu_mouse_point = CGEventGetLocation (ourEvent);
3959           CFRelease (ourEvent);
3960         }
3961       else if (menu_will_open_state == MENU_OPENING)
3962         {
3963           menu_will_open_state = MENU_NONE;
3964         }
3965     }
3968 /* Redo saved menu click if state is MENU_PENDING.  */
3969 void
3970 ns_check_pending_open_menu ()
3972   if (menu_will_open_state == MENU_PENDING)
3973     {
3974       CGEventSourceRef source
3975         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3977       CGEventRef event = CGEventCreateMouseEvent (source,
3978                                                   kCGEventLeftMouseDown,
3979                                                   menu_mouse_point,
3980                                                   kCGMouseButtonLeft);
3981       CGEventSetType (event, kCGEventLeftMouseDown);
3982       CGEventPost (kCGHIDEventTap, event);
3983       CFRelease (event);
3984       CFRelease (source);
3986       menu_will_open_state = MENU_OPENING;
3987     }
3989 #endif /* NS_IMPL_COCOA */
3992 static int
3993 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3994 /* --------------------------------------------------------------------------
3995      External (hook): Post an event to ourself and keep reading events until
3996      we read it back again.  In effect process all events which were waiting.
3997      From 21+ we have to manage the event buffer ourselves.
3998    -------------------------------------------------------------------------- */
4000   struct input_event ev;
4001   int nevents = 0;
4003   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4005 #ifdef HAVE_NATIVE_FS
4006   check_native_fs ();
4007 #endif
4009   if ([NSApp modalWindow] != nil)
4010     return -1;
4012   if (hold_event_q.nr > 0)
4013     {
4014       int i;
4015       for (i = 0; i < hold_event_q.nr; ++i)
4016         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4017       hold_event_q.nr = 0;
4018       return i;
4019     }
4021   if ([NSThread isMainThread])
4022     {
4023       block_input ();
4024       n_emacs_events_pending = 0;
4025       ns_init_events (&ev);
4026       q_event_ptr = hold_quit;
4028       /* we manage autorelease pools by allocate/reallocate each time around
4029          the loop; strict nesting is occasionally violated but seems not to
4030          matter.. earlier methods using full nesting caused major memory leaks */
4031       [outerpool release];
4032       outerpool = [[NSAutoreleasePool alloc] init];
4034       /* If have pending open-file requests, attend to the next one of those. */
4035       if (ns_pending_files && [ns_pending_files count] != 0
4036           && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4037         {
4038           [ns_pending_files removeObjectAtIndex: 0];
4039         }
4040       /* Deal with pending service requests. */
4041       else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4042                && [(EmacsApp *)
4043                     NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4044                                  withArg: [ns_pending_service_args objectAtIndex: 0]])
4045         {
4046           [ns_pending_service_names removeObjectAtIndex: 0];
4047           [ns_pending_service_args removeObjectAtIndex: 0];
4048         }
4049       else
4050         {
4051           /* Run and wait for events.  We must always send one NX_APPDEFINED event
4052              to ourself, otherwise [NXApp run] will never exit.  */
4053           ns_send_appdefined (-1);
4055           [NSApp run];
4056         }
4058       nevents = n_emacs_events_pending;
4059       n_emacs_events_pending = 0;
4060       ns_finish_events ();
4061       q_event_ptr = NULL;
4062       unblock_input ();
4063     }
4065   return nevents;
4070 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4071            fd_set *exceptfds, struct timespec const *timeout,
4072            sigset_t const *sigmask)
4073 /* --------------------------------------------------------------------------
4074      Replacement for select, checking for events
4075    -------------------------------------------------------------------------- */
4077   int result;
4078   NSDate *timeout_date = nil;
4079   NSEvent *ns_event;
4081   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4083 #ifdef HAVE_NATIVE_FS
4084   check_native_fs ();
4085 #endif
4087   if (hold_event_q.nr > 0)
4088     {
4089       /* We already have events pending. */
4090       raise (SIGIO);
4091       errno = EINTR;
4092       return -1;
4093     }
4095   if (NSApp == nil
4096       || ![NSThread isMainThread]
4097       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4098     return pselect(nfds, readfds, writefds,
4099                    exceptfds, timeout, sigmask);
4101   result = pselect(nfds, readfds, writefds, exceptfds,
4102                    &(struct timespec){.tv_sec = 0, .tv_nsec = 100},
4103                    sigmask);
4105   [outerpool release];
4106   outerpool = [[NSAutoreleasePool alloc] init];
4108   if (timeout)
4109     {
4110       double time = timespectod (*timeout);
4111       timeout_date = [NSDate dateWithTimeIntervalSinceNow:time];
4112     }
4114   /* Listen for a new NSEvent. */
4115   ns_event = [NSApp nextEventMatchingMask:NSEventMaskAny
4116                                 untilDate:timeout_date
4117                                    inMode:NSDefaultRunLoopMode
4118                                   dequeue:NO];
4120   if (ns_event != nil)
4121     {
4122       raise (SIGIO);
4123     }
4125   return result;
4130 /* ==========================================================================
4132     Scrollbar handling
4134    ========================================================================== */
4137 static void
4138 ns_set_vertical_scroll_bar (struct window *window,
4139                            int portion, int whole, int position)
4140 /* --------------------------------------------------------------------------
4141       External (hook): Update or add scrollbar
4142    -------------------------------------------------------------------------- */
4144   Lisp_Object win;
4145   NSRect r, v;
4146   struct frame *f = XFRAME (WINDOW_FRAME (window));
4147   EmacsView *view = FRAME_NS_VIEW (f);
4148   EmacsScroller *bar;
4149   int window_y, window_height;
4150   int top, left, height, width;
4151   BOOL update_p = YES;
4153   /* optimization; display engine sends WAY too many of these.. */
4154   if (!NILP (window->vertical_scroll_bar))
4155     {
4156       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4157       if ([bar checkSamePosition: position portion: portion whole: whole])
4158         {
4159           if (view->scrollbarsNeedingUpdate == 0)
4160             {
4161               if (!windows_or_buffers_changed)
4162                   return;
4163             }
4164           else
4165             view->scrollbarsNeedingUpdate--;
4166           update_p = NO;
4167         }
4168     }
4170   NSTRACE ("ns_set_vertical_scroll_bar");
4172   /* Get dimensions.  */
4173   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4174   top = window_y;
4175   height = window_height;
4176   width = NS_SCROLL_BAR_WIDTH (f);
4177   left = WINDOW_SCROLL_BAR_AREA_X (window);
4179   r = NSMakeRect (left, top, width, height);
4180   /* the parent view is flipped, so we need to flip y value */
4181   v = [view frame];
4182   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4184   XSETWINDOW (win, window);
4185   block_input ();
4187   /* we want at least 5 lines to display a scrollbar */
4188   if (WINDOW_TOTAL_LINES (window) < 5)
4189     {
4190       if (!NILP (window->vertical_scroll_bar))
4191         {
4192           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4193           [bar removeFromSuperview];
4194           wset_vertical_scroll_bar (window, Qnil);
4195           [bar release];
4196         }
4197       ns_clear_frame_area (f, left, top, width, height);
4198       unblock_input ();
4199       return;
4200     }
4202   if (NILP (window->vertical_scroll_bar))
4203     {
4204       if (width > 0 && height > 0)
4205         ns_clear_frame_area (f, left, top, width, height);
4207       bar = [[EmacsScroller alloc] initFrame: r window: win];
4208       wset_vertical_scroll_bar (window, make_save_ptr (bar));
4209       update_p = YES;
4210     }
4211   else
4212     {
4213       NSRect oldRect;
4214       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4215       oldRect = [bar frame];
4216       r.size.width = oldRect.size.width;
4217       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4218         {
4219           if (oldRect.origin.x != r.origin.x)
4220               ns_clear_frame_area (f, left, top, width, height);
4221           [bar setFrame: r];
4222         }
4223     }
4225   if (update_p)
4226     [bar setPosition: position portion: portion whole: whole];
4227   unblock_input ();
4231 static void
4232 ns_set_horizontal_scroll_bar (struct window *window,
4233                               int portion, int whole, int position)
4234 /* --------------------------------------------------------------------------
4235       External (hook): Update or add scrollbar
4236    -------------------------------------------------------------------------- */
4238   Lisp_Object win;
4239   NSRect r, v;
4240   struct frame *f = XFRAME (WINDOW_FRAME (window));
4241   EmacsView *view = FRAME_NS_VIEW (f);
4242   EmacsScroller *bar;
4243   int top, height, left, width;
4244   int window_x, window_width;
4245   BOOL update_p = YES;
4247   /* optimization; display engine sends WAY too many of these.. */
4248   if (!NILP (window->horizontal_scroll_bar))
4249     {
4250       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4251       if ([bar checkSamePosition: position portion: portion whole: whole])
4252         {
4253           if (view->scrollbarsNeedingUpdate == 0)
4254             {
4255               if (!windows_or_buffers_changed)
4256                   return;
4257             }
4258           else
4259             view->scrollbarsNeedingUpdate--;
4260           update_p = NO;
4261         }
4262     }
4264   NSTRACE ("ns_set_horizontal_scroll_bar");
4266   /* Get dimensions.  */
4267   window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4268   left = window_x;
4269   width = window_width;
4270   height = NS_SCROLL_BAR_HEIGHT (f);
4271   top = WINDOW_SCROLL_BAR_AREA_Y (window);
4273   r = NSMakeRect (left, top, width, height);
4274   /* the parent view is flipped, so we need to flip y value */
4275   v = [view frame];
4276   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4278   XSETWINDOW (win, window);
4279   block_input ();
4281   if (NILP (window->horizontal_scroll_bar))
4282     {
4283       if (width > 0 && height > 0)
4284         ns_clear_frame_area (f, left, top, width, height);
4286       bar = [[EmacsScroller alloc] initFrame: r window: win];
4287       wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4288       update_p = YES;
4289     }
4290   else
4291     {
4292       NSRect oldRect;
4293       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4294       oldRect = [bar frame];
4295       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4296         {
4297           if (oldRect.origin.y != r.origin.y)
4298             ns_clear_frame_area (f, left, top, width, height);
4299           [bar setFrame: r];
4300           update_p = YES;
4301         }
4302     }
4304   /* If there are both horizontal and vertical scroll-bars they leave
4305      a square that belongs to neither. We need to clear it otherwise
4306      it fills with junk. */
4307   if (!NILP (window->vertical_scroll_bar))
4308     ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4309                          NS_SCROLL_BAR_HEIGHT (f), height);
4311   if (update_p)
4312     [bar setPosition: position portion: portion whole: whole];
4313   unblock_input ();
4317 static void
4318 ns_condemn_scroll_bars (struct frame *f)
4319 /* --------------------------------------------------------------------------
4320      External (hook): arrange for all frame's scrollbars to be removed
4321      at next call to judge_scroll_bars, except for those redeemed.
4322    -------------------------------------------------------------------------- */
4324   int i;
4325   id view;
4326   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4328   NSTRACE ("ns_condemn_scroll_bars");
4330   for (i =[subviews count]-1; i >= 0; i--)
4331     {
4332       view = [subviews objectAtIndex: i];
4333       if ([view isKindOfClass: [EmacsScroller class]])
4334         [view condemn];
4335     }
4339 static void
4340 ns_redeem_scroll_bar (struct window *window)
4341 /* --------------------------------------------------------------------------
4342      External (hook): arrange to spare this window's scrollbar
4343      at next call to judge_scroll_bars.
4344    -------------------------------------------------------------------------- */
4346   id bar;
4347   NSTRACE ("ns_redeem_scroll_bar");
4348   if (!NILP (window->vertical_scroll_bar)
4349       && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4350     {
4351       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4352       [bar reprieve];
4353     }
4355   if (!NILP (window->horizontal_scroll_bar)
4356       && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4357     {
4358       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4359       [bar reprieve];
4360     }
4364 static void
4365 ns_judge_scroll_bars (struct frame *f)
4366 /* --------------------------------------------------------------------------
4367      External (hook): destroy all scrollbars on frame that weren't
4368      redeemed after call to condemn_scroll_bars.
4369    -------------------------------------------------------------------------- */
4371   int i;
4372   id view;
4373   EmacsView *eview = FRAME_NS_VIEW (f);
4374   NSArray *subviews = [[eview superview] subviews];
4375   BOOL removed = NO;
4377   NSTRACE ("ns_judge_scroll_bars");
4378   for (i = [subviews count]-1; i >= 0; --i)
4379     {
4380       view = [subviews objectAtIndex: i];
4381       if (![view isKindOfClass: [EmacsScroller class]]) continue;
4382       if ([view judge])
4383         removed = YES;
4384     }
4386   if (removed)
4387     [eview updateFrameSize: NO];
4390 /* ==========================================================================
4392     Initialization
4394    ========================================================================== */
4397 x_display_pixel_height (struct ns_display_info *dpyinfo)
4399   NSArray *screens = [NSScreen screens];
4400   NSEnumerator *enumerator = [screens objectEnumerator];
4401   NSScreen *screen;
4402   NSRect frame;
4404   frame = NSZeroRect;
4405   while ((screen = [enumerator nextObject]) != nil)
4406     frame = NSUnionRect (frame, [screen frame]);
4408   return NSHeight (frame);
4412 x_display_pixel_width (struct ns_display_info *dpyinfo)
4414   NSArray *screens = [NSScreen screens];
4415   NSEnumerator *enumerator = [screens objectEnumerator];
4416   NSScreen *screen;
4417   NSRect frame;
4419   frame = NSZeroRect;
4420   while ((screen = [enumerator nextObject]) != nil)
4421     frame = NSUnionRect (frame, [screen frame]);
4423   return NSWidth (frame);
4427 static Lisp_Object ns_string_to_lispmod (const char *s)
4428 /* --------------------------------------------------------------------------
4429      Convert modifier name to lisp symbol
4430    -------------------------------------------------------------------------- */
4432   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4433     return Qmeta;
4434   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4435     return Qsuper;
4436   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4437     return Qcontrol;
4438   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4439     return Qalt;
4440   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4441     return Qhyper;
4442   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4443     return Qnone;
4444   else
4445     return Qnil;
4449 static void
4450 ns_default (const char *parameter, Lisp_Object *result,
4451            Lisp_Object yesval, Lisp_Object noval,
4452            BOOL is_float, BOOL is_modstring)
4453 /* --------------------------------------------------------------------------
4454       Check a parameter value in user's preferences
4455    -------------------------------------------------------------------------- */
4457   const char *value = ns_get_defaults_value (parameter);
4459   if (value)
4460     {
4461       double f;
4462       char *pos;
4463       if (c_strcasecmp (value, "YES") == 0)
4464         *result = yesval;
4465       else if (c_strcasecmp (value, "NO") == 0)
4466         *result = noval;
4467       else if (is_float && (f = strtod (value, &pos), pos != value))
4468         *result = make_float (f);
4469       else if (is_modstring && value)
4470         *result = ns_string_to_lispmod (value);
4471       else fprintf (stderr,
4472                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4473     }
4477 static void
4478 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4479 /* --------------------------------------------------------------------------
4480       Initialize global info and storage for display.
4481    -------------------------------------------------------------------------- */
4483     NSScreen *screen = [NSScreen mainScreen];
4484     NSWindowDepth depth = [screen depth];
4486     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4487     dpyinfo->resy = 72.27;
4488     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4489                                                   NSColorSpaceFromDepth (depth)]
4490                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4491                                                  NSColorSpaceFromDepth (depth)];
4492     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4493     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4494     dpyinfo->color_table->colors = NULL;
4495     dpyinfo->root_window = 42; /* a placeholder.. */
4496     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4497     dpyinfo->n_fonts = 0;
4498     dpyinfo->smallest_font_height = 1;
4499     dpyinfo->smallest_char_width = 1;
4501     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4505 /* This and next define (many of the) public functions in this file. */
4506 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4507          with using despite presence in the "system dependent" redisplay
4508          interface.  In addition, many of the ns_ methods have code that is
4509          shared with all terms, indicating need for further refactoring. */
4510 extern frame_parm_handler ns_frame_parm_handlers[];
4511 static struct redisplay_interface ns_redisplay_interface =
4513   ns_frame_parm_handlers,
4514   x_produce_glyphs,
4515   x_write_glyphs,
4516   x_insert_glyphs,
4517   x_clear_end_of_line,
4518   ns_scroll_run,
4519   ns_after_update_window_line,
4520   ns_update_window_begin,
4521   ns_update_window_end,
4522   0, /* flush_display */
4523   x_clear_window_mouse_face,
4524   x_get_glyph_overhangs,
4525   x_fix_overlapping_area,
4526   ns_draw_fringe_bitmap,
4527   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4528   0, /* destroy_fringe_bitmap */
4529   ns_compute_glyph_string_overhangs,
4530   ns_draw_glyph_string,
4531   ns_define_frame_cursor,
4532   ns_clear_frame_area,
4533   ns_draw_window_cursor,
4534   ns_draw_vertical_window_border,
4535   ns_draw_window_divider,
4536   ns_shift_glyphs_for_insert,
4537   ns_show_hourglass,
4538   ns_hide_hourglass
4542 static void
4543 ns_delete_display (struct ns_display_info *dpyinfo)
4545   /* TODO... */
4549 /* This function is called when the last frame on a display is deleted. */
4550 static void
4551 ns_delete_terminal (struct terminal *terminal)
4553   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4555   NSTRACE ("ns_delete_terminal");
4557   /* Protect against recursive calls.  delete_frame in
4558      delete_terminal calls us back when it deletes our last frame.  */
4559   if (!terminal->name)
4560     return;
4562   block_input ();
4564   x_destroy_all_bitmaps (dpyinfo);
4565   ns_delete_display (dpyinfo);
4566   unblock_input ();
4570 static struct terminal *
4571 ns_create_terminal (struct ns_display_info *dpyinfo)
4572 /* --------------------------------------------------------------------------
4573       Set up use of NS before we make the first connection.
4574    -------------------------------------------------------------------------- */
4576   struct terminal *terminal;
4578   NSTRACE ("ns_create_terminal");
4580   terminal = create_terminal (output_ns, &ns_redisplay_interface);
4582   terminal->display_info.ns = dpyinfo;
4583   dpyinfo->terminal = terminal;
4585   terminal->clear_frame_hook = ns_clear_frame;
4586   terminal->ring_bell_hook = ns_ring_bell;
4587   terminal->update_begin_hook = ns_update_begin;
4588   terminal->update_end_hook = ns_update_end;
4589   terminal->read_socket_hook = ns_read_socket;
4590   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4591   terminal->mouse_position_hook = ns_mouse_position;
4592   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4593   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4594   terminal->fullscreen_hook = ns_fullscreen_hook;
4595   terminal->menu_show_hook = ns_menu_show;
4596   terminal->popup_dialog_hook = ns_popup_dialog;
4597   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4598   terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4599   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4600   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4601   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4602   terminal->delete_frame_hook = x_destroy_window;
4603   terminal->delete_terminal_hook = ns_delete_terminal;
4604   /* Other hooks are NULL by default.  */
4606   return terminal;
4610 struct ns_display_info *
4611 ns_term_init (Lisp_Object display_name)
4612 /* --------------------------------------------------------------------------
4613      Start the Application and get things rolling.
4614    -------------------------------------------------------------------------- */
4616   struct terminal *terminal;
4617   struct ns_display_info *dpyinfo;
4618   static int ns_initialized = 0;
4619   Lisp_Object tmp;
4621   if (ns_initialized) return x_display_list;
4622   ns_initialized = 1;
4624   block_input ();
4626   NSTRACE ("ns_term_init");
4628   [outerpool release];
4629   outerpool = [[NSAutoreleasePool alloc] init];
4631   /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */
4632   /*GSDebugAllocationActive (YES); */
4633   block_input ();
4635   baud_rate = 38400;
4636   Fset_input_interrupt_mode (Qnil);
4638   ns_pending_files = [[NSMutableArray alloc] init];
4639   ns_pending_service_names = [[NSMutableArray alloc] init];
4640   ns_pending_service_args = [[NSMutableArray alloc] init];
4642 /* Start app and create the main menu, window, view.
4643      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4644      The view will then ask the NSApp to stop and return to Emacs. */
4645   [EmacsApp sharedApplication];
4646   if (NSApp == nil)
4647     return NULL;
4648   [NSApp setDelegate: NSApp];
4650   /* debugging: log all notifications */
4651   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4652                                          selector: @selector (logNotification:)
4653                                              name: nil object: nil]; */
4655   dpyinfo = xzalloc (sizeof *dpyinfo);
4657   ns_initialize_display_info (dpyinfo);
4658   terminal = ns_create_terminal (dpyinfo);
4660   terminal->kboard = allocate_kboard (Qns);
4661   /* Don't let the initial kboard remain current longer than necessary.
4662      That would cause problems if a file loaded on startup tries to
4663      prompt in the mini-buffer.  */
4664   if (current_kboard == initial_kboard)
4665     current_kboard = terminal->kboard;
4666   terminal->kboard->reference_count++;
4668   dpyinfo->next = x_display_list;
4669   x_display_list = dpyinfo;
4671   dpyinfo->name_list_element = Fcons (display_name, Qnil);
4673   terminal->name = xlispstrdup (display_name);
4675   unblock_input ();
4677   if (!inhibit_x_resources)
4678     {
4679       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4680                  Qt, Qnil, NO, NO);
4681       tmp = Qnil;
4682       /* this is a standard variable */
4683       ns_default ("AppleAntiAliasingThreshold", &tmp,
4684                  make_float (10.0), make_float (6.0), YES, NO);
4685       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4686     }
4688   NSTRACE_MSG ("Colors");
4690   {
4691     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4693     if ( cl == nil )
4694       {
4695         Lisp_Object color_file, color_map, color;
4696         unsigned long c;
4697         char *name;
4699         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4700                          Fsymbol_value (intern ("data-directory")));
4702         color_map = Fx_load_color_file (color_file);
4703         if (NILP (color_map))
4704           fatal ("Could not read %s.\n", SDATA (color_file));
4706         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4707         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4708           {
4709             color = XCAR (color_map);
4710             name = SSDATA (XCAR (color));
4711             c = XINT (XCDR (color));
4712             [cl setColor:
4713                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4714                                       green: GREEN_FROM_ULONG (c) / 255.0
4715                                        blue: BLUE_FROM_ULONG (c) / 255.0
4716                                       alpha: 1.0]
4717                   forKey: [NSString stringWithUTF8String: name]];
4718           }
4719         [cl writeToFile: nil];
4720       }
4721   }
4723   NSTRACE_MSG ("Versions");
4725   {
4726 #ifdef NS_IMPL_GNUSTEP
4727     Vwindow_system_version = build_string (gnustep_base_version);
4728 #else
4729     /*PSnextrelease (128, c); */
4730     char c[DBL_BUFSIZE_BOUND];
4731     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4732     Vwindow_system_version = make_unibyte_string (c, len);
4733 #endif
4734   }
4736   delete_keyboard_wait_descriptor (0);
4738   ns_app_name = [[NSProcessInfo processInfo] processName];
4740   /* Set up macOS app menu */
4742   NSTRACE_MSG ("Menu init");
4744 #ifdef NS_IMPL_COCOA
4745   {
4746     NSMenu *appMenu;
4747     NSMenuItem *item;
4748     /* set up the application menu */
4749     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4750     [svcsMenu setAutoenablesItems: NO];
4751     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4752     [appMenu setAutoenablesItems: NO];
4753     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4754     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4756     [appMenu insertItemWithTitle: @"About Emacs"
4757                           action: @selector (orderFrontStandardAboutPanel:)
4758                    keyEquivalent: @""
4759                          atIndex: 0];
4760     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4761     [appMenu insertItemWithTitle: @"Preferences..."
4762                           action: @selector (showPreferencesWindow:)
4763                    keyEquivalent: @","
4764                          atIndex: 2];
4765     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4766     item = [appMenu insertItemWithTitle: @"Services"
4767                                  action: @selector (menuDown:)
4768                           keyEquivalent: @""
4769                                 atIndex: 4];
4770     [appMenu setSubmenu: svcsMenu forItem: item];
4771     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4772     [appMenu insertItemWithTitle: @"Hide Emacs"
4773                           action: @selector (hide:)
4774                    keyEquivalent: @"h"
4775                          atIndex: 6];
4776     item =  [appMenu insertItemWithTitle: @"Hide Others"
4777                           action: @selector (hideOtherApplications:)
4778                    keyEquivalent: @"h"
4779                          atIndex: 7];
4780     [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption];
4781     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4782     [appMenu insertItemWithTitle: @"Quit Emacs"
4783                           action: @selector (terminate:)
4784                    keyEquivalent: @"q"
4785                          atIndex: 9];
4787     item = [mainMenu insertItemWithTitle: ns_app_name
4788                                   action: @selector (menuDown:)
4789                            keyEquivalent: @""
4790                                  atIndex: 0];
4791     [mainMenu setSubmenu: appMenu forItem: item];
4792     [dockMenu insertItemWithTitle: @"New Frame"
4793                            action: @selector (newFrame:)
4794                     keyEquivalent: @""
4795                           atIndex: 0];
4797     [NSApp setMainMenu: mainMenu];
4798     [NSApp setAppleMenu: appMenu];
4799     [NSApp setServicesMenu: svcsMenu];
4800     /* Needed at least on Cocoa, to get dock menu to show windows */
4801     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4803     [[NSNotificationCenter defaultCenter]
4804       addObserver: mainMenu
4805          selector: @selector (trackingNotification:)
4806              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4807     [[NSNotificationCenter defaultCenter]
4808       addObserver: mainMenu
4809          selector: @selector (trackingNotification:)
4810              name: NSMenuDidEndTrackingNotification object: mainMenu];
4811   }
4812 #endif /* macOS menu setup */
4814   /* Register our external input/output types, used for determining
4815      applicable services and also drag/drop eligibility. */
4817   NSTRACE_MSG ("Input/output types");
4819   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4820   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4821                       retain];
4822   ns_drag_types = [[NSArray arrayWithObjects:
4823                             NSStringPboardType,
4824                             NSTabularTextPboardType,
4825                             NSFilenamesPboardType,
4826                             NSURLPboardType, nil] retain];
4828   /* If fullscreen is in init/default-frame-alist, focus isn't set
4829      right for fullscreen windows, so set this.  */
4830   [NSApp activateIgnoringOtherApps:YES];
4832   NSTRACE_MSG ("Call NSApp run");
4834   [NSApp run];
4835   ns_do_open_file = YES;
4837 #ifdef NS_IMPL_GNUSTEP
4838   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4839      We must re-catch it so subprocess works.  */
4840   catch_child_signal ();
4841 #endif
4843   NSTRACE_MSG ("ns_term_init done");
4845   unblock_input ();
4847   return dpyinfo;
4851 void
4852 ns_term_shutdown (int sig)
4854   [[NSUserDefaults standardUserDefaults] synchronize];
4856   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4857   if (STRINGP (Vauto_save_list_file_name))
4858     unlink (SSDATA (Vauto_save_list_file_name));
4860   if (sig == 0 || sig == SIGTERM)
4861     {
4862       [NSApp terminate: NSApp];
4863     }
4864   else // force a stack trace to happen
4865     {
4866       emacs_abort ();
4867     }
4871 /* ==========================================================================
4873     EmacsApp implementation
4875    ========================================================================== */
4878 @implementation EmacsApp
4880 - (id)init
4882   NSTRACE ("[EmacsApp init]");
4884   if ((self = [super init]))
4885     {
4886 #ifdef NS_IMPL_COCOA
4887       self->isFirst = YES;
4888 #endif
4889 #ifdef NS_IMPL_GNUSTEP
4890       self->applicationDidFinishLaunchingCalled = NO;
4891 #endif
4892     }
4894   return self;
4897 #ifdef NS_IMPL_COCOA
4898 - (void)run
4900   NSTRACE ("[EmacsApp run]");
4902 #ifndef NSAppKitVersionNumber10_9
4903 #define NSAppKitVersionNumber10_9 1265
4904 #endif
4906     if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
4907       {
4908         [super run];
4909         return;
4910       }
4912   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4914   if (isFirst) [self finishLaunching];
4915   isFirst = NO;
4917   shouldKeepRunning = YES;
4918   do
4919     {
4920       [pool release];
4921       pool = [[NSAutoreleasePool alloc] init];
4923       NSEvent *event =
4924         [self nextEventMatchingMask:NSEventMaskAny
4925                           untilDate:[NSDate distantFuture]
4926                              inMode:NSDefaultRunLoopMode
4927                             dequeue:YES];
4929       [self sendEvent:event];
4930       [self updateWindows];
4931     } while (shouldKeepRunning);
4933   [pool release];
4936 - (void)stop: (id)sender
4938   NSTRACE ("[EmacsApp stop:]");
4940     shouldKeepRunning = NO;
4941     // Stop possible dialog also.  Noop if no dialog present.
4942     // The file dialog still leaks 7k - 10k on 10.9 though.
4943     [super stop:sender];
4945 #endif /* NS_IMPL_COCOA */
4947 - (void)logNotification: (NSNotification *)notification
4949   NSTRACE ("[EmacsApp logNotification:]");
4951   const char *name = [[notification name] UTF8String];
4952   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4953       && !strstr (name, "WindowNumber"))
4954     NSLog (@"notification: '%@'", [notification name]);
4958 - (void)sendEvent: (NSEvent *)theEvent
4959 /* --------------------------------------------------------------------------
4960      Called when NSApp is running for each event received.  Used to stop
4961      the loop when we choose, since there's no way to just run one iteration.
4962    -------------------------------------------------------------------------- */
4964   int type = [theEvent type];
4965   NSWindow *window = [theEvent window];
4967   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
4968   NSTRACE_MSG ("Type: %d", type);
4970 #ifdef NS_IMPL_GNUSTEP
4971   // Keyboard events aren't propagated to file dialogs for some reason.
4972   if ([NSApp modalWindow] != nil &&
4973       (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged))
4974     {
4975       [[NSApp modalWindow] sendEvent: theEvent];
4976       return;
4977     }
4978 #endif
4980   if (represented_filename != nil && represented_frame)
4981     {
4982       NSString *fstr = represented_filename;
4983       NSView *view = FRAME_NS_VIEW (represented_frame);
4984 #ifdef NS_IMPL_COCOA
4985       /* work around a bug observed on 10.3 and later where
4986          setTitleWithRepresentedFilename does not clear out previous state
4987          if given filename does not exist */
4988       if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
4989         [[view window] setRepresentedFilename: @""];
4990 #endif
4991       [[view window] setRepresentedFilename: fstr];
4992       [represented_filename release];
4993       represented_filename = nil;
4994       represented_frame = NULL;
4995     }
4997   if (type == NSEventTypeApplicationDefined)
4998     {
4999       switch ([theEvent data2])
5000         {
5001 #ifdef NS_IMPL_COCOA
5002         case NSAPP_DATA2_RUNASSCRIPT:
5003           ns_run_ascript ();
5004           [self stop: self];
5005           return;
5006 #endif
5007         case NSAPP_DATA2_RUNFILEDIALOG:
5008           ns_run_file_dialog ();
5009           [self stop: self];
5010           return;
5011         }
5012     }
5014   if (type == NSEventTypeCursorUpdate && window == nil)
5015     {
5016       fprintf (stderr, "Dropping external cursor update event.\n");
5017       return;
5018     }
5020   if (type == NSEventTypeApplicationDefined)
5021     {
5022       /* Events posted by ns_send_appdefined interrupt the run loop here.
5023          But, if a modal window is up, an appdefined can still come through,
5024          (e.g., from a makeKeyWindow event) but stopping self also stops the
5025          modal loop. Just defer it until later. */
5026       if ([NSApp modalWindow] == nil)
5027         {
5028           last_appdefined_event_data = [theEvent data1];
5029           [self stop: self];
5030         }
5031     }
5034 #ifdef NS_IMPL_COCOA
5035   /* If no dialog and none of our frames have focus and it is a move, skip it.
5036      It is a mouse move in an auxiliary menu, i.e. on the top right on macOS,
5037      such as Wifi, sound, date or similar.
5038      This prevents "spooky" highlighting in the frame under the menu.  */
5039   if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil)
5040     {
5041       struct ns_display_info *di;
5042       BOOL has_focus = NO;
5043       for (di = x_display_list; ! has_focus && di; di = di->next)
5044         has_focus = di->x_focus_frame != 0;
5045       if (! has_focus)
5046         return;
5047     }
5048 #endif
5050   NSTRACE_UNSILENCE();
5052   [super sendEvent: theEvent];
5056 - (void)showPreferencesWindow: (id)sender
5058   struct frame *emacsframe = SELECTED_FRAME ();
5059   NSEvent *theEvent = [NSApp currentEvent];
5061   if (!emacs_event)
5062     return;
5063   emacs_event->kind = NS_NONKEY_EVENT;
5064   emacs_event->code = KEY_NS_SHOW_PREFS;
5065   emacs_event->modifiers = 0;
5066   EV_TRAILER (theEvent);
5070 - (void)newFrame: (id)sender
5072   NSTRACE ("[EmacsApp newFrame:]");
5074   struct frame *emacsframe = SELECTED_FRAME ();
5075   NSEvent *theEvent = [NSApp currentEvent];
5077   if (!emacs_event)
5078     return;
5079   emacs_event->kind = NS_NONKEY_EVENT;
5080   emacs_event->code = KEY_NS_NEW_FRAME;
5081   emacs_event->modifiers = 0;
5082   EV_TRAILER (theEvent);
5086 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5087 - (BOOL) openFile: (NSString *)fileName
5089   NSTRACE ("[EmacsApp openFile:]");
5091   struct frame *emacsframe = SELECTED_FRAME ();
5092   NSEvent *theEvent = [NSApp currentEvent];
5094   if (!emacs_event)
5095     return NO;
5097   emacs_event->kind = NS_NONKEY_EVENT;
5098   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5099   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5100   ns_input_line = Qnil; /* can be start or cons start,end */
5101   emacs_event->modifiers =0;
5102   EV_TRAILER (theEvent);
5104   return YES;
5108 /* **************************************************************************
5110       EmacsApp delegate implementation
5112    ************************************************************************** */
5114 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5115 /* --------------------------------------------------------------------------
5116      When application is loaded, terminate event loop in ns_term_init
5117    -------------------------------------------------------------------------- */
5119   NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5121 #ifdef NS_IMPL_GNUSTEP
5122   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5123 #endif
5124   [NSApp setServicesProvider: NSApp];
5126   [self antialiasThresholdDidChange:nil];
5127 #ifdef NS_IMPL_COCOA
5128   [[NSNotificationCenter defaultCenter]
5129     addObserver:self
5130        selector:@selector(antialiasThresholdDidChange:)
5131            name:NSAntialiasThresholdChangedNotification
5132          object:nil];
5133 #endif
5135   ns_send_appdefined (-2);
5138 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5140 #ifdef NS_IMPL_COCOA
5141   macfont_update_antialias_threshold ();
5142 #endif
5146 /* Termination sequences:
5147     C-x C-c:
5148     Cmd-Q:
5149     MenuBar | File | Exit:
5150     Select Quit from App menubar:
5151         -terminate
5152         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5153         ns_term_shutdown()
5155     Select Quit from Dock menu:
5156     Logout attempt:
5157         -appShouldTerminate
5158           Cancel -> Nothing else
5159           Accept ->
5161           -terminate
5162           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5163           ns_term_shutdown()
5167 - (void) terminate: (id)sender
5169   NSTRACE ("[EmacsApp terminate:]");
5171   struct frame *emacsframe = SELECTED_FRAME ();
5173   if (!emacs_event)
5174     return;
5176   emacs_event->kind = NS_NONKEY_EVENT;
5177   emacs_event->code = KEY_NS_POWER_OFF;
5178   emacs_event->arg = Qt; /* mark as non-key event */
5179   EV_TRAILER ((id)nil);
5182 static bool
5183 runAlertPanel(NSString *title,
5184               NSString *msgFormat,
5185               NSString *defaultButton,
5186               NSString *alternateButton)
5188 #if !defined (NS_IMPL_COCOA) || \
5189   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
5190   return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5191     == NSAlertDefaultReturn;
5192 #else
5193   NSAlert *alert = [[NSAlert alloc] init];
5194   [alert setAlertStyle: NSAlertStyleCritical];
5195   [alert setMessageText: msgFormat];
5196   [alert addButtonWithTitle: defaultButton];
5197   [alert addButtonWithTitle: alternateButton];
5198   NSInteger ret = [alert runModal];
5199   [alert release];
5200   return ret == NSAlertFirstButtonReturn;
5201 #endif
5205 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5207   NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5209   bool ret;
5211   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
5212     return NSTerminateNow;
5214   ret = runAlertPanel(ns_app_name,
5215                       @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
5216                       @"Save Buffers and Exit", @"Cancel");
5218   return ret ? NSTerminateNow : NSTerminateCancel;
5221 static int
5222 not_in_argv (NSString *arg)
5224   int k;
5225   const char *a = [arg UTF8String];
5226   for (k = 1; k < initial_argc; ++k)
5227     if (strcmp (a, initial_argv[k]) == 0) return 0;
5228   return 1;
5231 /*   Notification from the Workspace to open a file */
5232 - (BOOL)application: sender openFile: (NSString *)file
5234   if (ns_do_open_file || not_in_argv (file))
5235     [ns_pending_files addObject: file];
5236   return YES;
5240 /*   Open a file as a temporary file */
5241 - (BOOL)application: sender openTempFile: (NSString *)file
5243   if (ns_do_open_file || not_in_argv (file))
5244     [ns_pending_files addObject: file];
5245   return YES;
5249 /*   Notification from the Workspace to open a file noninteractively (?) */
5250 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5252   if (ns_do_open_file || not_in_argv (file))
5253     [ns_pending_files addObject: file];
5254   return YES;
5257 /*   Notification from the Workspace to open multiple files */
5258 - (void)application: sender openFiles: (NSArray *)fileList
5260   NSEnumerator *files = [fileList objectEnumerator];
5261   NSString *file;
5262   /* Don't open files from the command line unconditionally,
5263      Cocoa parses the command line wrong, --option value tries to open value
5264      if --option is the last option.  */
5265   while ((file = [files nextObject]) != nil)
5266     if (ns_do_open_file || not_in_argv (file))
5267       [ns_pending_files addObject: file];
5269   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5274 /* Handle dock menu requests.  */
5275 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5277   return dockMenu;
5281 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5282 - (void)applicationWillBecomeActive: (NSNotification *)notification
5284   NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5285   //ns_app_active=YES;
5288 - (void)applicationDidBecomeActive: (NSNotification *)notification
5290   NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5292 #ifdef NS_IMPL_GNUSTEP
5293   if (! applicationDidFinishLaunchingCalled)
5294     [self applicationDidFinishLaunching:notification];
5295 #endif
5296   //ns_app_active=YES;
5298   ns_update_auto_hide_menu_bar ();
5299   // No constraining takes place when the application is not active.
5300   ns_constrain_all_frames ();
5302 - (void)applicationDidResignActive: (NSNotification *)notification
5304   NSTRACE ("[EmacsApp applicationDidResignActive:]");
5306   //ns_app_active=NO;
5307   ns_send_appdefined (-1);
5312 /* ==========================================================================
5314     EmacsApp aux handlers for managing event loop
5316    ========================================================================== */
5319 - (void)timeout_handler: (NSTimer *)timedEntry
5320 /* --------------------------------------------------------------------------
5321      The timeout specified to ns_select has passed.
5322    -------------------------------------------------------------------------- */
5324   /*NSTRACE ("timeout_handler"); */
5325   ns_send_appdefined (-2);
5328 - (void)sendFromMainThread:(id)unused
5330   ns_send_appdefined (nextappdefined);
5335 /* ==========================================================================
5337     Service provision
5339    ========================================================================== */
5341 /* called from system: queue for next pass through event loop */
5342 - (void)requestService: (NSPasteboard *)pboard
5343               userData: (NSString *)userData
5344                  error: (NSString **)error
5346   [ns_pending_service_names addObject: userData];
5347   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5348       SSDATA (ns_string_from_pasteboard (pboard))]];
5352 /* called from ns_read_socket to clear queue */
5353 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5355   struct frame *emacsframe = SELECTED_FRAME ();
5356   NSEvent *theEvent = [NSApp currentEvent];
5358   NSTRACE ("[EmacsApp fulfillService:withArg:]");
5360   if (!emacs_event)
5361     return NO;
5363   emacs_event->kind = NS_NONKEY_EVENT;
5364   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5365   ns_input_spi_name = build_string ([name UTF8String]);
5366   ns_input_spi_arg = build_string ([arg UTF8String]);
5367   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5368   EV_TRAILER (theEvent);
5370   return YES;
5374 @end  /* EmacsApp */
5378 /* ==========================================================================
5380     EmacsView implementation
5382    ========================================================================== */
5385 @implementation EmacsView
5387 /* needed to inform when window closed from LISP */
5388 - (void) setWindowClosing: (BOOL)closing
5390   NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5392   windowClosing = closing;
5396 - (void)dealloc
5398   NSTRACE ("[EmacsView dealloc]");
5399   [toolbar release];
5400   if (fs_state == FULLSCREEN_BOTH)
5401     [nonfs_window release];
5402   [super dealloc];
5406 /* called on font panel selection */
5407 - (void)changeFont: (id)sender
5409   NSEvent *e = [[self window] currentEvent];
5410   struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID);
5411   struct font *font = face->font;
5412   id newFont;
5413   CGFloat size;
5414   NSFont *nsfont;
5416   NSTRACE ("[EmacsView changeFont:]");
5418   if (!emacs_event)
5419     return;
5421 #ifdef NS_IMPL_GNUSTEP
5422   nsfont = ((struct nsfont_info *)font)->nsfont;
5423 #endif
5424 #ifdef NS_IMPL_COCOA
5425   nsfont = (NSFont *) macfont_get_nsctfont (font);
5426 #endif
5428   if ((newFont = [sender convertFont: nsfont]))
5429     {
5430       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5432       emacs_event->kind = NS_NONKEY_EVENT;
5433       emacs_event->modifiers = 0;
5434       emacs_event->code = KEY_NS_CHANGE_FONT;
5436       size = [newFont pointSize];
5437       ns_input_fontsize = make_number (lrint (size));
5438       ns_input_font = build_string ([[newFont familyName] UTF8String]);
5439       EV_TRAILER (e);
5440     }
5444 - (BOOL)acceptsFirstResponder
5446   NSTRACE ("[EmacsView acceptsFirstResponder]");
5447   return YES;
5451 - (void)resetCursorRects
5453   NSRect visible = [self visibleRect];
5454   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5455   NSTRACE ("[EmacsView resetCursorRects]");
5457   if (currentCursor == nil)
5458     currentCursor = [NSCursor arrowCursor];
5460   if (!NSIsEmptyRect (visible))
5461     [self addCursorRect: visible cursor: currentCursor];
5462   [currentCursor setOnMouseEntered: YES];
5467 /*****************************************************************************/
5468 /* Keyboard handling. */
5469 #define NS_KEYLOG 0
5471 - (void)keyDown: (NSEvent *)theEvent
5473   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5474   int code;
5475   unsigned fnKeysym = 0;
5476   static NSMutableArray *nsEvArray;
5477   int left_is_none;
5478   unsigned int flags = [theEvent modifierFlags];
5480   NSTRACE ("[EmacsView keyDown:]");
5482   /* Rhapsody and macOS give up and down events for the arrow keys */
5483   if (ns_fake_keydown == YES)
5484     ns_fake_keydown = NO;
5485   else if ([theEvent type] != NSEventTypeKeyDown)
5486     return;
5488   if (!emacs_event)
5489     return;
5491  if (![[self window] isKeyWindow]
5492      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5493      /* we must avoid an infinite loop here. */
5494      && (EmacsView *)[[theEvent window] delegate] != self)
5495    {
5496      /* XXX: There is an occasional condition in which, when Emacs display
5497          updates a different frame from the current one, and temporarily
5498          selects it, then processes some interrupt-driven input
5499          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5500          for some reason that window has its first responder set to the NSView
5501          most recently updated (I guess), which is not the correct one. */
5502      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5503      return;
5504    }
5506   if (nsEvArray == nil)
5507     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5509   [NSCursor setHiddenUntilMouseMoves: YES];
5511   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5512     {
5513       clear_mouse_face (hlinfo);
5514       hlinfo->mouse_face_hidden = 1;
5515     }
5517   if (!processingCompose)
5518     {
5519       /* When using screen sharing, no left or right information is sent,
5520          so use Left key in those cases.  */
5521       int is_left_key, is_right_key;
5523       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5524         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5526       /* (Carbon way: [theEvent keyCode]) */
5528       /* is it a "function key"? */
5529       /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad
5530          flag set (this is probably a bug in the OS).
5531       */
5532       if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad))
5533         {
5534           fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad);
5535         }
5536       if (fnKeysym == 0)
5537         {
5538           fnKeysym = ns_convert_key (code);
5539         }
5541       if (fnKeysym)
5542         {
5543           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5544              because Emacs treats Delete and KP-Delete same (in simple.el). */
5545           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5546 #ifdef NS_IMPL_GNUSTEP
5547               /*  GNUstep uses incompatible keycodes, even for those that are
5548                   supposed to be hardware independent.  Just check for delete.
5549                   Keypad delete does not have keysym 0xFFFF.
5550                   See http://savannah.gnu.org/bugs/?25395
5551               */
5552               || (fnKeysym == 0xFFFF && code == 127)
5553 #endif
5554             )
5555             code = 0xFF08; /* backspace */
5556           else
5557             code = fnKeysym;
5558         }
5560       /* are there modifiers? */
5561       emacs_event->modifiers = 0;
5563       if (flags & NSEventModifierFlagHelp)
5564           emacs_event->modifiers |= hyper_modifier;
5566       if (flags & NSEventModifierFlagShift)
5567         emacs_event->modifiers |= shift_modifier;
5569       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5570       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5571         || (! is_right_key && (flags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand);
5573       if (is_right_key)
5574         emacs_event->modifiers |= parse_solitary_modifier
5575           (EQ (ns_right_command_modifier, Qleft)
5576            ? ns_command_modifier
5577            : ns_right_command_modifier);
5579       if (is_left_key)
5580         {
5581           emacs_event->modifiers |= parse_solitary_modifier
5582             (ns_command_modifier);
5584           /* if super (default), take input manager's word so things like
5585              dvorak / qwerty layout work */
5586           if (EQ (ns_command_modifier, Qsuper)
5587               && !fnKeysym
5588               && [[theEvent characters] length] != 0)
5589             {
5590               /* XXX: the code we get will be unshifted, so if we have
5591                  a shift modifier, must convert ourselves */
5592               if (!(flags & NSEventModifierFlagShift))
5593                 code = [[theEvent characters] characterAtIndex: 0];
5594 #if 0
5595               /* this is ugly and also requires linking w/Carbon framework
5596                  (for LMGetKbdType) so for now leave this rare (?) case
5597                  undealt with.. in future look into CGEvent methods */
5598               else
5599                 {
5600                   long smv = GetScriptManagerVariable (smKeyScript);
5601                   Handle uchrHandle = GetResource
5602                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5603                   UInt32 dummy = 0;
5604                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5605                                  [[theEvent characters] characterAtIndex: 0],
5606                                  kUCKeyActionDisplay,
5607                                  (flags & ~NSEventModifierFlagCommand) >> 8,
5608                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5609                                  &dummy, 1, &dummy, &code);
5610                   code &= 0xFF;
5611                 }
5612 #endif
5613             }
5614         }
5616       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5617       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5618         || (! is_right_key && (flags & NSEventModifierFlagControl) == NSEventModifierFlagControl);
5620       if (is_right_key)
5621           emacs_event->modifiers |= parse_solitary_modifier
5622               (EQ (ns_right_control_modifier, Qleft)
5623                ? ns_control_modifier
5624                : ns_right_control_modifier);
5626       if (is_left_key)
5627         emacs_event->modifiers |= parse_solitary_modifier
5628           (ns_control_modifier);
5630       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5631           emacs_event->modifiers |=
5632             parse_solitary_modifier (ns_function_modifier);
5634       left_is_none = NILP (ns_alternate_modifier)
5635         || EQ (ns_alternate_modifier, Qnone);
5637       is_right_key = (flags & NSRightAlternateKeyMask)
5638         == NSRightAlternateKeyMask;
5639       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5640         || (! is_right_key
5641             && (flags & NSEventModifierFlagOption) == NSEventModifierFlagOption);
5643       if (is_right_key)
5644         {
5645           if ((NILP (ns_right_alternate_modifier)
5646                || EQ (ns_right_alternate_modifier, Qnone)
5647                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5648               && !fnKeysym)
5649             {   /* accept pre-interp alt comb */
5650               if ([[theEvent characters] length] > 0)
5651                 code = [[theEvent characters] characterAtIndex: 0];
5652               /*HACK: clear lone shift modifier to stop next if from firing */
5653               if (emacs_event->modifiers == shift_modifier)
5654                 emacs_event->modifiers = 0;
5655             }
5656           else
5657             emacs_event->modifiers |= parse_solitary_modifier
5658               (EQ (ns_right_alternate_modifier, Qleft)
5659                ? ns_alternate_modifier
5660                : ns_right_alternate_modifier);
5661         }
5663       if (is_left_key) /* default = meta */
5664         {
5665           if (left_is_none && !fnKeysym)
5666             {   /* accept pre-interp alt comb */
5667               if ([[theEvent characters] length] > 0)
5668                 code = [[theEvent characters] characterAtIndex: 0];
5669               /*HACK: clear lone shift modifier to stop next if from firing */
5670               if (emacs_event->modifiers == shift_modifier)
5671                 emacs_event->modifiers = 0;
5672             }
5673           else
5674               emacs_event->modifiers |=
5675                 parse_solitary_modifier (ns_alternate_modifier);
5676         }
5678   if (NS_KEYLOG)
5679     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5680              (unsigned) code, fnKeysym, flags, emacs_event->modifiers);
5682       /* if it was a function key or had modifiers, pass it directly to emacs */
5683       if (fnKeysym || (emacs_event->modifiers
5684                        && (emacs_event->modifiers != shift_modifier)
5685                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5686 /*[[theEvent characters] length] */
5687         {
5688           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5689           if (code < 0x20)
5690             code |= (1<<28)|(3<<16);
5691           else if (code == 0x7f)
5692             code |= (1<<28)|(3<<16);
5693           else if (!fnKeysym)
5694             emacs_event->kind = code > 0xFF
5695               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5697           emacs_event->code = code;
5698           EV_TRAILER (theEvent);
5699           processingCompose = NO;
5700           return;
5701         }
5702     }
5705   if (NS_KEYLOG && !processingCompose)
5706     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5708   processingCompose = YES;
5709   [nsEvArray addObject: theEvent];
5710   [self interpretKeyEvents: nsEvArray];
5711   [nsEvArray removeObject: theEvent];
5715 #ifdef NS_IMPL_COCOA
5716 /* Needed to pick up Ctrl-tab and possibly other events that Mac OS X
5717    decided not to send key-down for.
5718    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5719    This only applies on Tiger and earlier.
5720    If it matches one of these, send it on to keyDown. */
5721 -(void)keyUp: (NSEvent *)theEvent
5723   int flags = [theEvent modifierFlags];
5724   int code = [theEvent keyCode];
5726   NSTRACE ("[EmacsView keyUp:]");
5728   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5729       code == 0x30 && (flags & NSEventModifierFlagControl) && !(flags & NSEventModifierFlagCommand))
5730     {
5731       if (NS_KEYLOG)
5732         fprintf (stderr, "keyUp: passed test");
5733       ns_fake_keydown = YES;
5734       [self keyDown: theEvent];
5735     }
5737 #endif
5740 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5743 /* <NSTextInput>: called when done composing;
5744    NOTE: also called when we delete over working text, followed immed.
5745          by doCommandBySelector: deleteBackward: */
5746 - (void)insertText: (id)aString
5748   int code;
5749   int len = [(NSString *)aString length];
5750   int i;
5752   NSTRACE ("[EmacsView insertText:]");
5754   if (NS_KEYLOG)
5755     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5756   processingCompose = NO;
5758   if (!emacs_event)
5759     return;
5761   /* first, clear any working text */
5762   if (workingText != nil)
5763     [self deleteWorkingText];
5765   /* now insert the string as keystrokes */
5766   for (i =0; i<len; i++)
5767     {
5768       code = [aString characterAtIndex: i];
5769       /* TODO: still need this? */
5770       if (code == 0x2DC)
5771         code = '~'; /* 0x7E */
5772       if (code != 32) /* Space */
5773         emacs_event->modifiers = 0;
5774       emacs_event->kind
5775         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5776       emacs_event->code = code;
5777       EV_TRAILER ((id)nil);
5778     }
5782 /* <NSTextInput>: inserts display of composing characters */
5783 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5785   NSString *str = [aString respondsToSelector: @selector (string)] ?
5786     [aString string] : aString;
5788   NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
5790   if (NS_KEYLOG)
5791     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5792            str, (unsigned long)[str length],
5793            (unsigned long)selRange.length,
5794            (unsigned long)selRange.location);
5796   if (workingText != nil)
5797     [self deleteWorkingText];
5798   if ([str length] == 0)
5799     return;
5801   if (!emacs_event)
5802     return;
5804   processingCompose = YES;
5805   workingText = [str copy];
5806   ns_working_text = build_string ([workingText UTF8String]);
5808   emacs_event->kind = NS_TEXT_EVENT;
5809   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5810   EV_TRAILER ((id)nil);
5814 /* delete display of composing characters [not in <NSTextInput>] */
5815 - (void)deleteWorkingText
5817   NSTRACE ("[EmacsView deleteWorkingText]");
5819   if (workingText == nil)
5820     return;
5821   if (NS_KEYLOG)
5822     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5823   [workingText release];
5824   workingText = nil;
5825   processingCompose = NO;
5827   if (!emacs_event)
5828     return;
5830   emacs_event->kind = NS_TEXT_EVENT;
5831   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5832   EV_TRAILER ((id)nil);
5836 - (BOOL)hasMarkedText
5838   NSTRACE ("[EmacsView hasMarkedText]");
5840   return workingText != nil;
5844 - (NSRange)markedRange
5846   NSTRACE ("[EmacsView markedRange]");
5848   NSRange rng = workingText != nil
5849     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5850   if (NS_KEYLOG)
5851     NSLog (@"markedRange request");
5852   return rng;
5856 - (void)unmarkText
5858   NSTRACE ("[EmacsView unmarkText]");
5860   if (NS_KEYLOG)
5861     NSLog (@"unmark (accept) text");
5862   [self deleteWorkingText];
5863   processingCompose = NO;
5867 /* used to position char selection windows, etc. */
5868 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5870   NSRect rect;
5871   NSPoint pt;
5872   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5874   NSTRACE ("[EmacsView firstRectForCharacterRange:]");
5876   if (NS_KEYLOG)
5877     NSLog (@"firstRectForCharRange request");
5879   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5880   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5881   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5882   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5883                                        +FRAME_LINE_HEIGHT (emacsframe));
5885   pt = [self convertPoint: pt toView: nil];
5886 #if !defined (NS_IMPL_COCOA) || \
5887   MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
5888   pt = [[self window] convertBaseToScreen: pt];
5889   rect.origin = pt;
5890 #else
5891   rect.origin = pt;
5892   rect = [[self window] convertRectToScreen: rect];
5893 #endif
5894   return rect;
5898 - (NSInteger)conversationIdentifier
5900   return (NSInteger)self;
5904 - (void)doCommandBySelector: (SEL)aSelector
5906   NSTRACE ("[EmacsView doCommandBySelector:]");
5908   if (NS_KEYLOG)
5909     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5911   processingCompose = NO;
5912   if (aSelector == @selector (deleteBackward:))
5913     {
5914       /* happens when user backspaces over an ongoing composition:
5915          throw a 'delete' into the event queue */
5916       if (!emacs_event)
5917         return;
5918       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5919       emacs_event->code = 0xFF08;
5920       EV_TRAILER ((id)nil);
5921     }
5924 - (NSArray *)validAttributesForMarkedText
5926   static NSArray *arr = nil;
5927   if (arr == nil) arr = [NSArray new];
5928  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5929   return arr;
5932 - (NSRange)selectedRange
5934   if (NS_KEYLOG)
5935     NSLog (@"selectedRange request");
5936   return NSMakeRange (NSNotFound, 0);
5939 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5940     GNUSTEP_GUI_MINOR_VERSION > 22
5941 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5942 #else
5943 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5944 #endif
5946   if (NS_KEYLOG)
5947     NSLog (@"characterIndexForPoint request");
5948   return 0;
5951 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5953   static NSAttributedString *str = nil;
5954   if (str == nil) str = [NSAttributedString new];
5955   if (NS_KEYLOG)
5956     NSLog (@"attributedSubstringFromRange request");
5957   return str;
5960 /* End <NSTextInput> impl. */
5961 /*****************************************************************************/
5964 /* This is what happens when the user presses a mouse button.  */
5965 - (void)mouseDown: (NSEvent *)theEvent
5967   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5968   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5970   NSTRACE ("[EmacsView mouseDown:]");
5972   [self deleteWorkingText];
5974   if (!emacs_event)
5975     return;
5977   dpyinfo->last_mouse_frame = emacsframe;
5978   /* appears to be needed to prevent spurious movement events generated on
5979      button clicks */
5980   emacsframe->mouse_moved = 0;
5982   if ([theEvent type] == NSEventTypeScrollWheel)
5983     {
5984       CGFloat delta = [theEvent deltaY];
5985       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5986       if (delta == 0)
5987         {
5988           delta = [theEvent deltaX];
5989           if (delta == 0)
5990             {
5991               NSTRACE_MSG ("deltaIsZero");
5992               return;
5993             }
5994           emacs_event->kind = HORIZ_WHEEL_EVENT;
5995         }
5996       else
5997         emacs_event->kind = WHEEL_EVENT;
5999       emacs_event->code = 0;
6000       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6001         ((delta > 0) ? up_modifier : down_modifier);
6002     }
6003   else
6004     {
6005       emacs_event->kind = MOUSE_CLICK_EVENT;
6006       emacs_event->code = EV_BUTTON (theEvent);
6007       emacs_event->modifiers = EV_MODIFIERS (theEvent)
6008                              | EV_UDMODIFIERS (theEvent);
6009     }
6010   XSETINT (emacs_event->x, lrint (p.x));
6011   XSETINT (emacs_event->y, lrint (p.y));
6012   EV_TRAILER (theEvent);
6016 - (void)rightMouseDown: (NSEvent *)theEvent
6018   NSTRACE ("[EmacsView rightMouseDown:]");
6019   [self mouseDown: theEvent];
6023 - (void)otherMouseDown: (NSEvent *)theEvent
6025   NSTRACE ("[EmacsView otherMouseDown:]");
6026   [self mouseDown: theEvent];
6030 - (void)mouseUp: (NSEvent *)theEvent
6032   NSTRACE ("[EmacsView mouseUp:]");
6033   [self mouseDown: theEvent];
6037 - (void)rightMouseUp: (NSEvent *)theEvent
6039   NSTRACE ("[EmacsView rightMouseUp:]");
6040   [self mouseDown: theEvent];
6044 - (void)otherMouseUp: (NSEvent *)theEvent
6046   NSTRACE ("[EmacsView otherMouseUp:]");
6047   [self mouseDown: theEvent];
6051 - (void) scrollWheel: (NSEvent *)theEvent
6053   NSTRACE ("[EmacsView scrollWheel:]");
6054   [self mouseDown: theEvent];
6058 /* Tell emacs the mouse has moved. */
6059 - (void)mouseMoved: (NSEvent *)e
6061   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6062   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6063   Lisp_Object frame;
6064   NSPoint pt;
6066   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6068   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6069   pt = [self convertPoint: [e locationInWindow] fromView: nil];
6070   dpyinfo->last_mouse_motion_x = pt.x;
6071   dpyinfo->last_mouse_motion_y = pt.y;
6073   /* update any mouse face */
6074   if (hlinfo->mouse_face_hidden)
6075     {
6076       hlinfo->mouse_face_hidden = 0;
6077       clear_mouse_face (hlinfo);
6078     }
6080   /* tooltip handling */
6081   previous_help_echo_string = help_echo_string;
6082   help_echo_string = Qnil;
6084   if (!NILP (Vmouse_autoselect_window))
6085     {
6086       NSTRACE_MSG ("mouse_autoselect_window");
6087       static Lisp_Object last_mouse_window;
6088       Lisp_Object window
6089         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6091       if (WINDOWP (window)
6092           && !EQ (window, last_mouse_window)
6093           && !EQ (window, selected_window)
6094           && (focus_follows_mouse
6095               || (EQ (XWINDOW (window)->frame,
6096                       XWINDOW (selected_window)->frame))))
6097         {
6098           NSTRACE_MSG ("in_window");
6099           emacs_event->kind = SELECT_WINDOW_EVENT;
6100           emacs_event->frame_or_window = window;
6101           EV_TRAILER2 (e);
6102         }
6103       /* Remember the last window where we saw the mouse.  */
6104       last_mouse_window = window;
6105     }
6107   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6108     help_echo_string = previous_help_echo_string;
6110   XSETFRAME (frame, emacsframe);
6111   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6112     {
6113       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6114          (note_mouse_highlight), which is called through the
6115          note_mouse_movement () call above */
6116       any_help_event_p = YES;
6117       gen_help_event (help_echo_string, frame, help_echo_window,
6118                       help_echo_object, help_echo_pos);
6119     }
6121   if (emacsframe->mouse_moved)
6122     ns_send_appdefined (-1);
6126 - (void)mouseDragged: (NSEvent *)e
6128   NSTRACE ("[EmacsView mouseDragged:]");
6129   [self mouseMoved: e];
6133 - (void)rightMouseDragged: (NSEvent *)e
6135   NSTRACE ("[EmacsView rightMouseDragged:]");
6136   [self mouseMoved: e];
6140 - (void)otherMouseDragged: (NSEvent *)e
6142   NSTRACE ("[EmacsView otherMouseDragged:]");
6143   [self mouseMoved: e];
6147 - (BOOL)windowShouldClose: (id)sender
6149   NSEvent *e =[[self window] currentEvent];
6151   NSTRACE ("[EmacsView windowShouldClose:]");
6152   windowClosing = YES;
6153   if (!emacs_event)
6154     return NO;
6155   emacs_event->kind = DELETE_WINDOW_EVENT;
6156   emacs_event->modifiers = 0;
6157   emacs_event->code = 0;
6158   EV_TRAILER (e);
6159   /* Don't close this window, let this be done from lisp code.  */
6160   return NO;
6163 - (void) updateFrameSize: (BOOL) delay;
6165   NSWindow *window = [self window];
6166   NSRect wr = [window frame];
6167   int extra = 0;
6168   int oldc = cols, oldr = rows;
6169   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6170   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6171   int neww, newh;
6173   NSTRACE ("[EmacsView updateFrameSize:]");
6174   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6175   NSTRACE_RECT ("Original frame", wr);
6176   NSTRACE_MSG  ("Original columns: %d", cols);
6177   NSTRACE_MSG  ("Original rows: %d", rows);
6179   if (! [self isFullscreen])
6180     {
6181 #ifdef NS_IMPL_GNUSTEP
6182       // GNUstep does not always update the tool bar height.  Force it.
6183       if (toolbar && [toolbar isVisible])
6184           update_frame_tool_bar (emacsframe);
6185 #endif
6187       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6188         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6189     }
6191   if (wait_for_tool_bar)
6192     {
6193       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
6194         {
6195           NSTRACE_MSG ("Waiting for toolbar");
6196           return;
6197         }
6198       wait_for_tool_bar = NO;
6199     }
6201   neww = (int)wr.size.width - emacsframe->border_width;
6202   newh = (int)wr.size.height - extra;
6204   NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6205   NSTRACE_MSG ("tool_bar_height: %d", emacsframe->tool_bar_height);
6207   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6208   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6210   if (cols < MINWIDTH)
6211     cols = MINWIDTH;
6213   if (rows < MINHEIGHT)
6214     rows = MINHEIGHT;
6216   NSTRACE_MSG ("New columns: %d", cols);
6217   NSTRACE_MSG ("New rows: %d", rows);
6219   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6220     {
6221       NSView *view = FRAME_NS_VIEW (emacsframe);
6223       change_frame_size (emacsframe,
6224                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6225                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6226                          0, delay, 0, 1);
6227       SET_FRAME_GARBAGED (emacsframe);
6228       cancel_mouse_face (emacsframe);
6230       wr = NSMakeRect (0, 0, neww, newh);
6232       [view setFrame: wr];
6234       // to do: consider using [NSNotificationCenter postNotificationName:].
6235       [self windowDidMove: // Update top/left.
6236               [NSNotification notificationWithName:NSWindowDidMoveNotification
6237                                             object:[view window]]];
6238     }
6239   else
6240     {
6241       NSTRACE_MSG ("No change");
6242     }
6245 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6246 /* normalize frame to gridded text size */
6248   int extra = 0;
6250   NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6251            NSTRACE_ARG_SIZE (frameSize));
6252   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6253   NSTRACE_FSTYPE ("fs_state", fs_state);
6255   if (fs_state == FULLSCREEN_MAXIMIZED
6256       && (maximized_width != (int)frameSize.width
6257           || maximized_height != (int)frameSize.height))
6258     [self setFSValue: FULLSCREEN_NONE];
6259   else if (fs_state == FULLSCREEN_WIDTH
6260            && maximized_width != (int)frameSize.width)
6261     [self setFSValue: FULLSCREEN_NONE];
6262   else if (fs_state == FULLSCREEN_HEIGHT
6263            && maximized_height != (int)frameSize.height)
6264     [self setFSValue: FULLSCREEN_NONE];
6266   if (fs_state == FULLSCREEN_NONE)
6267     maximized_width = maximized_height = -1;
6269   if (! [self isFullscreen])
6270     {
6271       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6272         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6273     }
6275   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6276   if (cols < MINWIDTH)
6277     cols = MINWIDTH;
6279   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6280                                            frameSize.height - extra);
6281   if (rows < MINHEIGHT)
6282     rows = MINHEIGHT;
6283 #ifdef NS_IMPL_COCOA
6284   {
6285     /* this sets window title to have size in it; the wm does this under GS */
6286     NSRect r = [[self window] frame];
6287     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6288       {
6289         if (old_title != 0)
6290           {
6291             xfree (old_title);
6292             old_title = 0;
6293           }
6294       }
6295     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
6296       {
6297         char *size_title;
6298         NSWindow *window = [self window];
6299         if (old_title == 0)
6300           {
6301             char *t = strdup ([[[self window] title] UTF8String]);
6302             char *pos = strstr (t, "  â€”  ");
6303             if (pos)
6304               *pos = '\0';
6305             old_title = t;
6306           }
6307         size_title = xmalloc (strlen (old_title) + 40);
6308         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
6309         [window setTitle: [NSString stringWithUTF8String: size_title]];
6310         [window display];
6311         xfree (size_title);
6312       }
6313   }
6314 #endif /* NS_IMPL_COCOA */
6316   NSTRACE_MSG ("cols: %d  rows: %d", cols, rows);
6318   /* Restrict the new size to the text gird.
6320      Don't restrict the width if the user only adjusted the height, and
6321      vice versa.  (Without this, the frame would shrink, and move
6322      slightly, if the window was resized by dragging one of its
6323      borders.) */
6324   if (!frame_resize_pixelwise)
6325     {
6326       NSRect r = [[self window] frame];
6328       if (r.size.width != frameSize.width)
6329         {
6330           frameSize.width =
6331             FRAME_TEXT_COLS_TO_PIXEL_WIDTH  (emacsframe, cols);
6332         }
6334       if (r.size.height != frameSize.height)
6335         {
6336           frameSize.height =
6337             FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6338         }
6339     }
6341   NSTRACE_RETURN_SIZE (frameSize);
6343   return frameSize;
6347 - (void)windowDidResize: (NSNotification *)notification
6349   NSTRACE ("[EmacsView windowDidResize:]");
6350   if (!FRAME_LIVE_P (emacsframe))
6351     {
6352       NSTRACE_MSG ("Ignored (frame dead)");
6353       return;
6354     }
6355   if (emacsframe->output_data.ns->in_animation)
6356     {
6357       NSTRACE_MSG ("Ignored (in animation)");
6358       return;
6359     }
6361   if (! [self fsIsNative])
6362     {
6363       NSWindow *theWindow = [notification object];
6364       /* We can get notification on the non-FS window when in
6365          fullscreen mode.  */
6366       if ([self window] != theWindow) return;
6367     }
6369   NSTRACE_RECT ("frame", [[notification object] frame]);
6371 #ifdef NS_IMPL_GNUSTEP
6372   NSWindow *theWindow = [notification object];
6374    /* In GNUstep, at least currently, it's possible to get a didResize
6375       without getting a willResize.. therefore we need to act as if we got
6376       the willResize now */
6377   NSSize sz = [theWindow frame].size;
6378   sz = [self windowWillResize: theWindow toSize: sz];
6379 #endif /* NS_IMPL_GNUSTEP */
6381   if (cols > 0 && rows > 0)
6382     {
6383       [self updateFrameSize: YES];
6384     }
6386   ns_send_appdefined (-1);
6389 #ifdef NS_IMPL_COCOA
6390 - (void)viewDidEndLiveResize
6392   NSTRACE ("[EmacsView viewDidEndLiveResize]");
6394   [super viewDidEndLiveResize];
6395   if (old_title != 0)
6396     {
6397       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6398       xfree (old_title);
6399       old_title = 0;
6400     }
6401   maximizing_resize = NO;
6403 #endif /* NS_IMPL_COCOA */
6406 - (void)windowDidBecomeKey: (NSNotification *)notification
6407 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6409   [self windowDidBecomeKey];
6413 - (void)windowDidBecomeKey      /* for direct calls */
6415   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6416   struct frame *old_focus = dpyinfo->x_focus_frame;
6418   NSTRACE ("[EmacsView windowDidBecomeKey]");
6420   if (emacsframe != old_focus)
6421     dpyinfo->x_focus_frame = emacsframe;
6423   ns_frame_rehighlight (emacsframe);
6425   if (emacs_event)
6426     {
6427       emacs_event->kind = FOCUS_IN_EVENT;
6428       EV_TRAILER ((id)nil);
6429     }
6433 - (void)windowDidResignKey: (NSNotification *)notification
6434 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6436   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6437   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6438   NSTRACE ("[EmacsView windowDidResignKey:]");
6440   if (is_focus_frame)
6441     dpyinfo->x_focus_frame = 0;
6443   emacsframe->mouse_moved = 0;
6444   ns_frame_rehighlight (emacsframe);
6446   /* FIXME: for some reason needed on second and subsequent clicks away
6447             from sole-frame Emacs to get hollow box to show */
6448   if (!windowClosing && [[self window] isVisible] == YES)
6449     {
6450       x_update_cursor (emacsframe, 1);
6451       x_set_frame_alpha (emacsframe);
6452     }
6454   if (any_help_event_p)
6455     {
6456       Lisp_Object frame;
6457       XSETFRAME (frame, emacsframe);
6458       help_echo_string = Qnil;
6459       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6460     }
6462   if (emacs_event && is_focus_frame)
6463     {
6464       [self deleteWorkingText];
6465       emacs_event->kind = FOCUS_OUT_EVENT;
6466       EV_TRAILER ((id)nil);
6467     }
6471 - (void)windowWillMiniaturize: sender
6473   NSTRACE ("[EmacsView windowWillMiniaturize:]");
6477 - (void)setFrame:(NSRect)frameRect;
6479   NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
6480            NSTRACE_ARG_RECT (frameRect));
6482   [super setFrame:(NSRect)frameRect];
6486 - (BOOL)isFlipped
6488   return YES;
6492 - (BOOL)isOpaque
6494   return NO;
6498 - initFrameFromEmacs: (struct frame *)f
6500   NSRect r, wr;
6501   Lisp_Object tem;
6502   NSWindow *win;
6503   NSColor *col;
6504   NSString *name;
6506   NSTRACE ("[EmacsView initFrameFromEmacs:]");
6507   NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
6509   windowClosing = NO;
6510   processingCompose = NO;
6511   scrollbarsNeedingUpdate = 0;
6512   fs_state = FULLSCREEN_NONE;
6513   fs_before_fs = next_maximized = -1;
6514 #ifdef HAVE_NATIVE_FS
6515   fs_is_native = ns_use_native_fullscreen;
6516 #else
6517   fs_is_native = NO;
6518 #endif
6519   maximized_width = maximized_height = -1;
6520   nonfs_window = nil;
6522   ns_userRect = NSMakeRect (0, 0, 0, 0);
6523   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6524                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6525   [self initWithFrame: r];
6526   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6528   FRAME_NS_VIEW (f) = self;
6529   emacsframe = f;
6530 #ifdef NS_IMPL_COCOA
6531   old_title = 0;
6532   maximizing_resize = NO;
6533 #endif
6535   win = [[EmacsWindow alloc]
6536             initWithContentRect: r
6537                       styleMask: (NSWindowStyleMaskResizable |
6538 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6539                                   NSWindowStyleMaskTitled |
6540 #endif
6541                                   NSWindowStyleMaskMiniaturizable |
6542                                   NSWindowStyleMaskClosable)
6543                         backing: NSBackingStoreBuffered
6544                           defer: YES];
6546 #ifdef HAVE_NATIVE_FS
6547     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6548 #endif
6550   wr = [win frame];
6551   bwidth = f->border_width = wr.size.width - r.size.width;
6552   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6554   [win setAcceptsMouseMovedEvents: YES];
6555   [win setDelegate: self];
6556 #if !defined (NS_IMPL_COCOA) || \
6557   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6558   [win useOptimizedDrawing: YES];
6559 #endif
6561   [[win contentView] addSubview: self];
6563   if (ns_drag_types)
6564     [self registerForDraggedTypes: ns_drag_types];
6566   tem = f->name;
6567   name = [NSString stringWithUTF8String:
6568                    NILP (tem) ? "Emacs" : SSDATA (tem)];
6569   [win setTitle: name];
6571   /* toolbar support */
6572   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6573                          [NSString stringWithFormat: @"Emacs Frame %d",
6574                                    ns_window_num]];
6575   [win setToolbar: toolbar];
6576   [toolbar setVisible: NO];
6578   /* Don't set frame garbaged until tool bar is up to date?
6579      This avoids an extra clear and redraw (flicker) at frame creation.  */
6580   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6581   else wait_for_tool_bar = NO;
6584 #ifdef NS_IMPL_COCOA
6585   {
6586     NSButton *toggleButton;
6587   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6588   [toggleButton setTarget: self];
6589   [toggleButton setAction: @selector (toggleToolbar: )];
6590   }
6591 #endif
6592   FRAME_TOOLBAR_HEIGHT (f) = 0;
6594   tem = f->icon_name;
6595   if (!NILP (tem))
6596     [win setMiniwindowTitle:
6597            [NSString stringWithUTF8String: SSDATA (tem)]];
6599   {
6600     NSScreen *screen = [win screen];
6602     if (screen != 0)
6603       {
6604         NSPoint pt = NSMakePoint
6605           (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6606            IN_BOUND (-SCREENMAX,
6607                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX));
6609         [win setFrameTopLeftPoint: pt];
6611         NSTRACE_RECT ("new frame", [win frame]);
6612       }
6613   }
6615   [win makeFirstResponder: self];
6617   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6618                                  (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
6619                                  emacsframe);
6620   [win setBackgroundColor: col];
6621   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6622     [win setOpaque: NO];
6624 #if !defined (NS_IMPL_COCOA) || \
6625   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6626   [self allocateGState];
6627 #endif
6628   [NSApp registerServicesMenuSendTypes: ns_send_types
6629                            returnTypes: nil];
6631   ns_window_num++;
6632   return self;
6636 - (void)windowDidMove: sender
6638   NSWindow *win = [self window];
6639   NSRect r = [win frame];
6640   NSArray *screens = [NSScreen screens];
6641   NSScreen *screen = [screens objectAtIndex: 0];
6643   NSTRACE ("[EmacsView windowDidMove:]");
6645   if (!emacsframe->output_data.ns)
6646     return;
6647   if (screen != nil)
6648     {
6649       emacsframe->left_pos = r.origin.x;
6650       emacsframe->top_pos =
6651         [screen frame].size.height - (r.origin.y + r.size.height);
6652     }
6656 /* Called AFTER method below, but before our windowWillResize call there leads
6657    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
6658    location so set_window_size moves the frame. */
6659 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6661   NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
6662             NSTRACE_FMT_RETURN "YES"),
6663            NSTRACE_ARG_RECT (newFrame));
6665   emacsframe->output_data.ns->zooming = 1;
6666   return YES;
6670 /* Override to do something slightly nonstandard, but nice.  First click on
6671    zoom button will zoom vertically.  Second will zoom completely.  Third
6672    returns to original. */
6673 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6674                         defaultFrame:(NSRect)defaultFrame
6676   // TODO: Rename to "currentFrame" and assign "result" properly in
6677   // all paths.
6678   NSRect result = [sender frame];
6680   NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
6681             NSTRACE_FMT_RECT "]"),
6682            NSTRACE_ARG_RECT (defaultFrame));
6683   NSTRACE_FSTYPE ("fs_state", fs_state);
6684   NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
6685   NSTRACE_FSTYPE ("next_maximized", next_maximized);
6686   NSTRACE_RECT   ("ns_userRect", ns_userRect);
6687   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6689   if (fs_before_fs != -1) /* Entering fullscreen */
6690     {
6691       NSTRACE_MSG ("Entering fullscreen");
6692       result = defaultFrame;
6693     }
6694   else
6695     {
6696       // Save the window size and position (frame) before the resize.
6697       if (fs_state != FULLSCREEN_MAXIMIZED
6698           && fs_state != FULLSCREEN_WIDTH)
6699         {
6700           ns_userRect.size.width = result.size.width;
6701           ns_userRect.origin.x   = result.origin.x;
6702         }
6704       if (fs_state != FULLSCREEN_MAXIMIZED
6705           && fs_state != FULLSCREEN_HEIGHT)
6706         {
6707           ns_userRect.size.height = result.size.height;
6708           ns_userRect.origin.y    = result.origin.y;
6709         }
6711       NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
6713       if (next_maximized == FULLSCREEN_HEIGHT
6714           || (next_maximized == -1
6715               && abs ((int)(defaultFrame.size.height - result.size.height))
6716               > FRAME_LINE_HEIGHT (emacsframe)))
6717         {
6718           /* first click */
6719           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
6720           maximized_height = result.size.height = defaultFrame.size.height;
6721           maximized_width = -1;
6722           result.origin.y = defaultFrame.origin.y;
6723           if (ns_userRect.size.height != 0)
6724             {
6725               result.origin.x = ns_userRect.origin.x;
6726               result.size.width = ns_userRect.size.width;
6727             }
6728           [self setFSValue: FULLSCREEN_HEIGHT];
6729 #ifdef NS_IMPL_COCOA
6730           maximizing_resize = YES;
6731 #endif
6732         }
6733       else if (next_maximized == FULLSCREEN_WIDTH)
6734         {
6735           NSTRACE_MSG ("FULLSCREEN_WIDTH");
6736           maximized_width = result.size.width = defaultFrame.size.width;
6737           maximized_height = -1;
6738           result.origin.x = defaultFrame.origin.x;
6739           if (ns_userRect.size.width != 0)
6740             {
6741               result.origin.y = ns_userRect.origin.y;
6742               result.size.height = ns_userRect.size.height;
6743             }
6744           [self setFSValue: FULLSCREEN_WIDTH];
6745         }
6746       else if (next_maximized == FULLSCREEN_MAXIMIZED
6747                || (next_maximized == -1
6748                    && abs ((int)(defaultFrame.size.width - result.size.width))
6749                    > FRAME_COLUMN_WIDTH (emacsframe)))
6750         {
6751           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
6753           result = defaultFrame;  /* second click */
6754           maximized_width = result.size.width;
6755           maximized_height = result.size.height;
6756           [self setFSValue: FULLSCREEN_MAXIMIZED];
6757 #ifdef NS_IMPL_COCOA
6758           maximizing_resize = YES;
6759 #endif
6760         }
6761       else
6762         {
6763           /* restore */
6764           NSTRACE_MSG ("Restore");
6765           result = ns_userRect.size.height ? ns_userRect : result;
6766           NSTRACE_RECT ("restore (2)", result);
6767           ns_userRect = NSMakeRect (0, 0, 0, 0);
6768 #ifdef NS_IMPL_COCOA
6769           maximizing_resize = fs_state != FULLSCREEN_NONE;
6770 #endif
6771           [self setFSValue: FULLSCREEN_NONE];
6772           maximized_width = maximized_height = -1;
6773         }
6774     }
6776   if (fs_before_fs == -1) next_maximized = -1;
6778   NSTRACE_RECT   ("Final ns_userRect", ns_userRect);
6779   NSTRACE_MSG    ("Final maximized_width: %d", maximized_width);
6780   NSTRACE_MSG    ("Final maximized_height: %d", maximized_height);
6781   NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
6783   [self windowWillResize: sender toSize: result.size];
6785   NSTRACE_RETURN_RECT (result);
6787   return result;
6791 - (void)windowDidDeminiaturize: sender
6793   NSTRACE ("[EmacsView windowDidDeminiaturize:]");
6794   if (!emacsframe->output_data.ns)
6795     return;
6797   SET_FRAME_ICONIFIED (emacsframe, 0);
6798   SET_FRAME_VISIBLE (emacsframe, 1);
6799   windows_or_buffers_changed = 63;
6801   if (emacs_event)
6802     {
6803       emacs_event->kind = DEICONIFY_EVENT;
6804       EV_TRAILER ((id)nil);
6805     }
6809 - (void)windowDidExpose: sender
6811   NSTRACE ("[EmacsView windowDidExpose:]");
6812   if (!emacsframe->output_data.ns)
6813     return;
6815   SET_FRAME_VISIBLE (emacsframe, 1);
6816   SET_FRAME_GARBAGED (emacsframe);
6818   ns_send_appdefined (-1);
6822 - (void)windowDidMiniaturize: sender
6824   NSTRACE ("[EmacsView windowDidMiniaturize:]");
6825   if (!emacsframe->output_data.ns)
6826     return;
6828   SET_FRAME_ICONIFIED (emacsframe, 1);
6829   SET_FRAME_VISIBLE (emacsframe, 0);
6831   if (emacs_event)
6832     {
6833       emacs_event->kind = ICONIFY_EVENT;
6834       EV_TRAILER ((id)nil);
6835     }
6838 #ifdef HAVE_NATIVE_FS
6839 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6840       willUseFullScreenPresentationOptions:
6841   (NSApplicationPresentationOptions)proposedOptions
6843   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6845 #endif
6847 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6849   NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
6850   [self windowWillEnterFullScreen];
6852 - (void)windowWillEnterFullScreen /* provided for direct calls */
6854   NSTRACE ("[EmacsView windowWillEnterFullScreen]");
6855   fs_before_fs = fs_state;
6858 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6860   NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
6861   [self windowDidEnterFullScreen];
6864 - (void)windowDidEnterFullScreen /* provided for direct calls */
6866   NSTRACE ("[EmacsView windowDidEnterFullScreen]");
6867   [self setFSValue: FULLSCREEN_BOTH];
6868   if (! [self fsIsNative])
6869     {
6870       [self windowDidBecomeKey];
6871       [nonfs_window orderOut:self];
6872     }
6873   else
6874     {
6875       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
6876 #ifdef NS_IMPL_COCOA
6877 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6878       unsigned val = (unsigned)[NSApp presentationOptions];
6880       // Mac OS X 10.7 bug fix, the menu won't appear without this.
6881       // val is non-zero on other macOS versions.
6882       if (val == 0)
6883         {
6884           NSApplicationPresentationOptions options
6885             = NSApplicationPresentationAutoHideDock
6886             | NSApplicationPresentationAutoHideMenuBar
6887             | NSApplicationPresentationFullScreen
6888             | NSApplicationPresentationAutoHideToolbar;
6890           [NSApp setPresentationOptions: options];
6891         }
6892 #endif
6893 #endif
6894       [toolbar setVisible:tbar_visible];
6895     }
6898 - (void)windowWillExitFullScreen:(NSNotification *)notification
6900   NSTRACE ("[EmacsView windowWillExitFullScreen:]");
6901   [self windowWillExitFullScreen];
6904 - (void)windowWillExitFullScreen /* provided for direct calls */
6906   NSTRACE ("[EmacsView windowWillExitFullScreen]");
6907   if (!FRAME_LIVE_P (emacsframe))
6908     {
6909       NSTRACE_MSG ("Ignored (frame dead)");
6910       return;
6911     }
6912   if (next_maximized != -1)
6913     fs_before_fs = next_maximized;
6916 - (void)windowDidExitFullScreen:(NSNotification *)notification
6918   NSTRACE ("[EmacsView windowDidExitFullScreen:]");
6919   [self windowDidExitFullScreen];
6922 - (void)windowDidExitFullScreen /* provided for direct calls */
6924   NSTRACE ("[EmacsView windowDidExitFullScreen]");
6925   if (!FRAME_LIVE_P (emacsframe))
6926     {
6927       NSTRACE_MSG ("Ignored (frame dead)");
6928       return;
6929     }
6930   [self setFSValue: fs_before_fs];
6931   fs_before_fs = -1;
6932 #ifdef HAVE_NATIVE_FS
6933   [self updateCollectionBehavior];
6934 #endif
6935   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6936     {
6937       [toolbar setVisible:YES];
6938       update_frame_tool_bar (emacsframe);
6939       [self updateFrameSize:YES];
6940       [[self window] display];
6941     }
6942   else
6943     [toolbar setVisible:NO];
6945   if (next_maximized != -1)
6946     [[self window] performZoom:self];
6949 - (BOOL)fsIsNative
6951   return fs_is_native;
6954 - (BOOL)isFullscreen
6956   BOOL res;
6958   if (! fs_is_native)
6959     {
6960       res = (nonfs_window != nil);
6961     }
6962   else
6963     {
6964 #ifdef HAVE_NATIVE_FS
6965       res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
6966 #else
6967       res = NO;
6968 #endif
6969     }
6971   NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
6972            (int) res);
6974   return res;
6977 #ifdef HAVE_NATIVE_FS
6978 - (void)updateCollectionBehavior
6980   NSTRACE ("[EmacsView updateCollectionBehavior]");
6982   if (! [self isFullscreen])
6983     {
6984       NSWindow *win = [self window];
6985       NSWindowCollectionBehavior b = [win collectionBehavior];
6986       if (ns_use_native_fullscreen)
6987         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6988       else
6989         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6991       [win setCollectionBehavior: b];
6992       fs_is_native = ns_use_native_fullscreen;
6993     }
6995 #endif
6997 - (void)toggleFullScreen: (id)sender
6999   NSWindow *w, *fw;
7000   BOOL onFirstScreen;
7001   struct frame *f;
7002   NSRect r, wr;
7003   NSColor *col;
7005   NSTRACE ("[EmacsView toggleFullScreen:]");
7007   if (fs_is_native)
7008     {
7009 #ifdef HAVE_NATIVE_FS
7010       [[self window] toggleFullScreen:sender];
7011 #endif
7012       return;
7013     }
7015   w = [self window];
7016   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7017   f = emacsframe;
7018   wr = [w frame];
7019   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7020                                  (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7021                                  f);
7023   if (fs_state != FULLSCREEN_BOTH)
7024     {
7025       NSScreen *screen = [w screen];
7027 #if defined (NS_IMPL_COCOA) && \
7028   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7029       /* Hide ghost menu bar on secondary monitor? */
7030       if (! onFirstScreen)
7031         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7032 #endif
7033       /* Hide dock and menubar if we are on the primary screen.  */
7034       if (onFirstScreen)
7035         {
7036 #ifdef NS_IMPL_COCOA
7037           NSApplicationPresentationOptions options
7038             = NSApplicationPresentationAutoHideDock
7039             | NSApplicationPresentationAutoHideMenuBar;
7041           [NSApp setPresentationOptions: options];
7042 #else
7043           [NSMenu setMenuBarVisible:NO];
7044 #endif
7045         }
7047       fw = [[EmacsFSWindow alloc]
7048                        initWithContentRect:[w contentRectForFrameRect:wr]
7049                                  styleMask:NSWindowStyleMaskBorderless
7050                                    backing:NSBackingStoreBuffered
7051                                      defer:YES
7052                                     screen:screen];
7054       [fw setContentView:[w contentView]];
7055       [fw setTitle:[w title]];
7056       [fw setDelegate:self];
7057       [fw setAcceptsMouseMovedEvents: YES];
7058 #if !defined (NS_IMPL_COCOA) || \
7059   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7060       [fw useOptimizedDrawing: YES];
7061 #endif
7062       [fw setBackgroundColor: col];
7063       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7064         [fw setOpaque: NO];
7066       f->border_width = 0;
7067       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
7068       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
7069       FRAME_TOOLBAR_HEIGHT (f) = 0;
7071       nonfs_window = w;
7073       [self windowWillEnterFullScreen];
7074       [fw makeKeyAndOrderFront:NSApp];
7075       [fw makeFirstResponder:self];
7076       [w orderOut:self];
7077       r = [fw frameRectForContentRect:[screen frame]];
7078       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7079       [self windowDidEnterFullScreen];
7080       [fw display];
7081     }
7082   else
7083     {
7084       fw = w;
7085       w = nonfs_window;
7086       nonfs_window = nil;
7088       if (onFirstScreen)
7089         {
7090 #ifdef NS_IMPL_COCOA
7091           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7092 #else
7093           [NSMenu setMenuBarVisible:YES];
7094 #endif
7095         }
7097       [w setContentView:[fw contentView]];
7098       [w setBackgroundColor: col];
7099       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7100         [w setOpaque: NO];
7102       f->border_width = bwidth;
7103       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
7104       if (FRAME_EXTERNAL_TOOL_BAR (f))
7105         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
7107       // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7109       [self windowWillExitFullScreen];
7110       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7111       [fw close];
7112       [w makeKeyAndOrderFront:NSApp];
7113       [self windowDidExitFullScreen];
7114       [self updateFrameSize:YES];
7115     }
7118 - (void)handleFS
7120   NSTRACE ("[EmacsView handleFS]");
7122   if (fs_state != emacsframe->want_fullscreen)
7123     {
7124       if (fs_state == FULLSCREEN_BOTH)
7125         {
7126           NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7127           [self toggleFullScreen:self];
7128         }
7130       switch (emacsframe->want_fullscreen)
7131         {
7132         case FULLSCREEN_BOTH:
7133           NSTRACE_MSG ("FULLSCREEN_BOTH");
7134           [self toggleFullScreen:self];
7135           break;
7136         case FULLSCREEN_WIDTH:
7137           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7138           next_maximized = FULLSCREEN_WIDTH;
7139           if (fs_state != FULLSCREEN_BOTH)
7140             [[self window] performZoom:self];
7141           break;
7142         case FULLSCREEN_HEIGHT:
7143           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7144           next_maximized = FULLSCREEN_HEIGHT;
7145           if (fs_state != FULLSCREEN_BOTH)
7146             [[self window] performZoom:self];
7147           break;
7148         case FULLSCREEN_MAXIMIZED:
7149           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7150           next_maximized = FULLSCREEN_MAXIMIZED;
7151           if (fs_state != FULLSCREEN_BOTH)
7152             [[self window] performZoom:self];
7153           break;
7154         case FULLSCREEN_NONE:
7155           NSTRACE_MSG ("FULLSCREEN_NONE");
7156           if (fs_state != FULLSCREEN_BOTH)
7157             {
7158               next_maximized = FULLSCREEN_NONE;
7159               [[self window] performZoom:self];
7160             }
7161           break;
7162         }
7164       emacsframe->want_fullscreen = FULLSCREEN_NONE;
7165     }
7169 - (void) setFSValue: (int)value
7171   NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7172            NSTRACE_ARG_FSTYPE(value));
7174   Lisp_Object lval = Qnil;
7175   switch (value)
7176     {
7177     case FULLSCREEN_BOTH:
7178       lval = Qfullboth;
7179       break;
7180     case FULLSCREEN_WIDTH:
7181       lval = Qfullwidth;
7182       break;
7183     case FULLSCREEN_HEIGHT:
7184       lval = Qfullheight;
7185       break;
7186     case FULLSCREEN_MAXIMIZED:
7187       lval = Qmaximized;
7188       break;
7189     }
7190   store_frame_param (emacsframe, Qfullscreen, lval);
7191   fs_state = value;
7194 - (void)mouseEntered: (NSEvent *)theEvent
7196   NSTRACE ("[EmacsView mouseEntered:]");
7197   if (emacsframe)
7198     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7199       = EV_TIMESTAMP (theEvent);
7203 - (void)mouseExited: (NSEvent *)theEvent
7205   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7207   NSTRACE ("[EmacsView mouseExited:]");
7209   if (!hlinfo)
7210     return;
7212   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7213     = EV_TIMESTAMP (theEvent);
7215   if (emacsframe == hlinfo->mouse_face_mouse_frame)
7216     {
7217       clear_mouse_face (hlinfo);
7218       hlinfo->mouse_face_mouse_frame = 0;
7219     }
7223 - menuDown: sender
7225   NSTRACE ("[EmacsView menuDown:]");
7226   if (context_menu_value == -1)
7227     context_menu_value = [sender tag];
7228   else
7229     {
7230       NSInteger tag = [sender tag];
7231       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7232                                     emacsframe->menu_bar_vector,
7233                                     (void *)tag);
7234     }
7236   ns_send_appdefined (-1);
7237   return self;
7241 - (EmacsToolbar *)toolbar
7243   return toolbar;
7247 /* this gets called on toolbar button click */
7248 - toolbarClicked: (id)item
7250   NSEvent *theEvent;
7251   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7253   NSTRACE ("[EmacsView toolbarClicked:]");
7255   if (!emacs_event)
7256     return self;
7258   /* send first event (for some reason two needed) */
7259   theEvent = [[self window] currentEvent];
7260   emacs_event->kind = TOOL_BAR_EVENT;
7261   XSETFRAME (emacs_event->arg, emacsframe);
7262   EV_TRAILER (theEvent);
7264   emacs_event->kind = TOOL_BAR_EVENT;
7265 /*   XSETINT (emacs_event->code, 0); */
7266   emacs_event->arg = AREF (emacsframe->tool_bar_items,
7267                            idx + TOOL_BAR_ITEM_KEY);
7268   emacs_event->modifiers = EV_MODIFIERS (theEvent);
7269   EV_TRAILER (theEvent);
7270   return self;
7274 - toggleToolbar: (id)sender
7276   NSTRACE ("[EmacsView toggleToolbar:]");
7278   if (!emacs_event)
7279     return self;
7281   emacs_event->kind = NS_NONKEY_EVENT;
7282   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7283   EV_TRAILER ((id)nil);
7284   return self;
7288 - (void)drawRect: (NSRect)rect
7290   int x = NSMinX (rect), y = NSMinY (rect);
7291   int width = NSWidth (rect), height = NSHeight (rect);
7293   NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7294            NSTRACE_ARG_RECT(rect));
7296   if (!emacsframe || !emacsframe->output_data.ns)
7297     return;
7299   ns_clear_frame_area (emacsframe, x, y, width, height);
7300   block_input ();
7301   expose_frame (emacsframe, x, y, width, height);
7302   unblock_input ();
7304   /*
7305     drawRect: may be called (at least in Mac OS X 10.5) for invisible
7306     views as well for some reason.  Thus, do not infer visibility
7307     here.
7309     emacsframe->async_visible = 1;
7310     emacsframe->async_iconified = 0;
7311   */
7315 /* NSDraggingDestination protocol methods.  Actually this is not really a
7316    protocol, but a category of Object.  O well...  */
7318 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7320   NSTRACE ("[EmacsView draggingEntered:]");
7321   return NSDragOperationGeneric;
7325 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7327   return YES;
7331 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7333   id pb;
7334   int x, y;
7335   NSString *type;
7336   NSEvent *theEvent = [[self window] currentEvent];
7337   NSPoint position;
7338   NSDragOperation op = [sender draggingSourceOperationMask];
7339   int modifiers = 0;
7341   NSTRACE ("[EmacsView performDragOperation:]");
7343   if (!emacs_event)
7344     return NO;
7346   position = [self convertPoint: [sender draggingLocation] fromView: nil];
7347   x = lrint (position.x);  y = lrint (position.y);
7349   pb = [sender draggingPasteboard];
7350   type = [pb availableTypeFromArray: ns_drag_types];
7352   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7353       // URL drags contain all operations (0xf), don't allow all to be set.
7354       (op & 0xf) != 0xf)
7355     {
7356       if (op & NSDragOperationLink)
7357         modifiers |= NSEventModifierFlagControl;
7358       if (op & NSDragOperationCopy)
7359         modifiers |= NSEventModifierFlagOption;
7360       if (op & NSDragOperationGeneric)
7361         modifiers |= NSEventModifierFlagCommand;
7362     }
7364   modifiers = EV_MODIFIERS2 (modifiers);
7365   if (type == 0)
7366     {
7367       return NO;
7368     }
7369   else if ([type isEqualToString: NSFilenamesPboardType])
7370     {
7371       NSArray *files;
7372       NSEnumerator *fenum;
7373       NSString *file;
7375       if (!(files = [pb propertyListForType: type]))
7376         return NO;
7378       fenum = [files objectEnumerator];
7379       while ( (file = [fenum nextObject]) )
7380         {
7381           emacs_event->kind = DRAG_N_DROP_EVENT;
7382           XSETINT (emacs_event->x, x);
7383           XSETINT (emacs_event->y, y);
7384           ns_input_file = append2 (ns_input_file,
7385                                    build_string ([file UTF8String]));
7386           emacs_event->modifiers = modifiers;
7387           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
7388           EV_TRAILER (theEvent);
7389         }
7390       return YES;
7391     }
7392   else if ([type isEqualToString: NSURLPboardType])
7393     {
7394       NSURL *url = [NSURL URLFromPasteboard: pb];
7395       if (url == nil) return NO;
7397       emacs_event->kind = DRAG_N_DROP_EVENT;
7398       XSETINT (emacs_event->x, x);
7399       XSETINT (emacs_event->y, y);
7400       emacs_event->modifiers = modifiers;
7401       emacs_event->arg =  list2 (Qurl,
7402                                  build_string ([[url absoluteString]
7403                                                  UTF8String]));
7404       EV_TRAILER (theEvent);
7406       if ([url isFileURL] != NO)
7407         {
7408           NSString *file = [url path];
7409           ns_input_file = append2 (ns_input_file,
7410                                    build_string ([file UTF8String]));
7411         }
7412       return YES;
7413     }
7414   else if ([type isEqualToString: NSStringPboardType]
7415            || [type isEqualToString: NSTabularTextPboardType])
7416     {
7417       NSString *data;
7419       if (! (data = [pb stringForType: type]))
7420         return NO;
7422       emacs_event->kind = DRAG_N_DROP_EVENT;
7423       XSETINT (emacs_event->x, x);
7424       XSETINT (emacs_event->y, y);
7425       emacs_event->modifiers = modifiers;
7426       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
7427       EV_TRAILER (theEvent);
7428       return YES;
7429     }
7430   else
7431     {
7432       fprintf (stderr, "Invalid data type in dragging pasteboard");
7433       return NO;
7434     }
7438 - (id) validRequestorForSendType: (NSString *)typeSent
7439                       returnType: (NSString *)typeReturned
7441   NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
7442   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7443       && typeReturned == nil)
7444     {
7445       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7446         return self;
7447     }
7449   return [super validRequestorForSendType: typeSent
7450                                returnType: typeReturned];
7454 /* The next two methods are part of NSServicesRequests informal protocol,
7455    supposedly called when a services menu item is chosen from this app.
7456    But this should not happen because we override the services menu with our
7457    own entries which call ns-perform-service.
7458    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7459    So let's at least stub them out until further investigation can be done. */
7461 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7463   /* we could call ns_string_from_pasteboard(pboard) here but then it should
7464      be written into the buffer in place of the existing selection..
7465      ordinary service calls go through functions defined in ns-win.el */
7466   return NO;
7469 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7471   NSArray *typesDeclared;
7472   Lisp_Object val;
7474   NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
7476   /* We only support NSStringPboardType */
7477   if ([types containsObject:NSStringPboardType] == NO) {
7478     return NO;
7479   }
7481   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7482   if (CONSP (val) && SYMBOLP (XCAR (val)))
7483     {
7484       val = XCDR (val);
7485       if (CONSP (val) && NILP (XCDR (val)))
7486         val = XCAR (val);
7487     }
7488   if (! STRINGP (val))
7489     return NO;
7491   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7492   [pb declareTypes:typesDeclared owner:nil];
7493   ns_string_to_pasteboard (pb, val);
7494   return YES;
7498 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7499    (gives a miniaturized version of the window); currently we use the latter for
7500    frames whose active buffer doesn't correspond to any file
7501    (e.g., '*scratch*') */
7502 - setMiniwindowImage: (BOOL) setMini
7504   id image = [[self window] miniwindowImage];
7505   NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
7507   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7508      about "AppleDockIconEnabled" notwithstanding, however the set message
7509      below has its effect nonetheless. */
7510   if (image != emacsframe->output_data.ns->miniimage)
7511     {
7512       if (image && [image isKindOfClass: [EmacsImage class]])
7513         [image release];
7514       [[self window] setMiniwindowImage:
7515                        setMini ? emacsframe->output_data.ns->miniimage : nil];
7516     }
7518   return self;
7522 - (void) setRows: (int) r andColumns: (int) c
7524   NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
7525   rows = r;
7526   cols = c;
7529 - (int) fullscreenState
7531   return fs_state;
7534 @end  /* EmacsView */
7538 /* ==========================================================================
7540     EmacsWindow implementation
7542    ========================================================================== */
7544 @implementation EmacsWindow
7546 #ifdef NS_IMPL_COCOA
7547 - (id)accessibilityAttributeValue:(NSString *)attribute
7549   Lisp_Object str = Qnil;
7550   struct frame *f = SELECTED_FRAME ();
7551   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7553   NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
7555   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7556     return NSAccessibilityTextFieldRole;
7558   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7559       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7560     {
7561       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7562     }
7563   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7564     {
7565       if (! NILP (BVAR (curbuf, mark_active)))
7566           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7568       if (NILP (str))
7569         {
7570           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7571           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7572           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7574           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7575             str = make_uninit_multibyte_string (range, byte_range);
7576           else
7577             str = make_uninit_string (range);
7578           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7579              Is this a problem?  */
7580           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7581         }
7582     }
7585   if (! NILP (str))
7586     {
7587       if (CONSP (str) && SYMBOLP (XCAR (str)))
7588         {
7589           str = XCDR (str);
7590           if (CONSP (str) && NILP (XCDR (str)))
7591             str = XCAR (str);
7592         }
7593       if (STRINGP (str))
7594         {
7595           const char *utfStr = SSDATA (str);
7596           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7597           return nsStr;
7598         }
7599     }
7601   return [super accessibilityAttributeValue:attribute];
7603 #endif /* NS_IMPL_COCOA */
7605 /* Constrain size and placement of a frame.
7607    By returning the original "frameRect", the frame is not
7608    constrained. This can lead to unwanted situations where, for
7609    example, the menu bar covers the frame.
7611    The default implementation (accessed using "super") constrains the
7612    frame to the visible area of SCREEN, minus the menu bar (if
7613    present) and the Dock.  Note that default implementation also calls
7614    windowWillResize, with the frame it thinks should have.  (This can
7615    make the frame exit maximized mode.)
7617    Note that this should work in situations where multiple monitors
7618    are present.  Common configurations are side-by-side monitors and a
7619    monitor on top of another (e.g. when a laptop is placed under a
7620    large screen). */
7621 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7623   NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
7624              NSTRACE_ARG_RECT (frameRect));
7626 #ifdef NS_IMPL_COCOA
7627 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7628   // If separate spaces is on, it is like each screen is independent.  There is
7629   // no spanning of frames across screens.
7630   if ([NSScreen screensHaveSeparateSpaces])
7631     {
7632       NSTRACE_MSG ("Screens have separate spaces");
7633       frameRect = [super constrainFrameRect:frameRect toScreen:screen];
7634       NSTRACE_RETURN_RECT (frameRect);
7635       return frameRect;
7636     }
7637 #endif
7638 #endif
7640   return constrain_frame_rect(frameRect,
7641                               [(EmacsView *)[self delegate] isFullscreen]);
7645 - (void)performZoom:(id)sender
7647   NSTRACE ("[EmacsWindow performZoom:]");
7649   return [super performZoom:sender];
7652 - (void)zoom:(id)sender
7654   NSTRACE ("[EmacsWindow zoom:]");
7656   ns_update_auto_hide_menu_bar();
7658   // Below are three zoom implementations.  In the final commit, the
7659   // idea is that the last should be included.
7661 #if 0
7662   // Native zoom done using the standard zoom animation.  Size of the
7663   // resulting frame reduced to accommodate the Dock and, if present,
7664   // the menu-bar.
7665   [super zoom:sender];
7667 #elif 0
7668   // Native zoom done using the standard zoom animation, plus an
7669   // explicit resize to cover the full screen, except the menu-bar and
7670   // dock, if present.
7671   [super zoom:sender];
7673   // After the native zoom, resize the resulting frame to fill the
7674   // entire screen, except the menu-bar.
7675   //
7676   // This works for all practical purposes.  (The only minor oddity is
7677   // when transiting from full-height frame to a maximized, the
7678   // animation reduces the height of the frame slightly (to the 4
7679   // pixels needed to accommodate the Doc) before it snaps back into
7680   // full height.  The user would need a very trained eye to spot
7681   // this.)
7682   NSScreen * screen = [self screen];
7683   if (screen != nil)
7684     {
7685       int fs_state = [(EmacsView *)[self delegate] fullscreenState];
7687       NSTRACE_FSTYPE ("fullscreenState", fs_state);
7689       NSRect sr = [screen frame];
7690       struct EmacsMargins margins
7691         = ns_screen_margins_ignoring_hidden_dock(screen);
7693       NSRect wr = [self frame];
7694       NSTRACE_RECT ("Rect after zoom", wr);
7696       NSRect newWr = wr;
7698       if (fs_state == FULLSCREEN_MAXIMIZED
7699           || fs_state == FULLSCREEN_HEIGHT)
7700         {
7701           newWr.origin.y = sr.origin.y + margins.bottom;
7702           newWr.size.height = sr.size.height - margins.top - margins.bottom;
7703         }
7705       if (fs_state == FULLSCREEN_MAXIMIZED
7706           || fs_state == FULLSCREEN_WIDTH)
7707         {
7708           newWr.origin.x = sr.origin.x + margins.left;
7709           newWr.size.width = sr.size.width - margins.right - margins.left;
7710         }
7712       if (newWr.size.width     != wr.size.width
7713           || newWr.size.height != wr.size.height
7714           || newWr.origin.x    != wr.origin.x
7715           || newWr.origin.y    != wr.origin.y)
7716         {
7717           NSTRACE_MSG ("New frame different");
7718           [self setFrame: newWr display: NO];
7719         }
7720     }
7721 #else
7722   // Non-native zoom which is done instantaneously.  The resulting
7723   // frame covers the entire screen, except the menu-bar and dock, if
7724   // present.
7725   NSScreen * screen = [self screen];
7726   if (screen != nil)
7727     {
7728       NSRect sr = [screen frame];
7729       struct EmacsMargins margins
7730         = ns_screen_margins_ignoring_hidden_dock(screen);
7732       sr.size.height -= (margins.top + margins.bottom);
7733       sr.size.width  -= (margins.left + margins.right);
7734       sr.origin.x += margins.left;
7735       sr.origin.y += margins.bottom;
7737       sr = [[self delegate] windowWillUseStandardFrame:self
7738                                           defaultFrame:sr];
7739       [self setFrame: sr display: NO];
7740     }
7741 #endif
7744 - (void)setFrame:(NSRect)windowFrame
7745          display:(BOOL)displayViews
7747   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
7748            NSTRACE_ARG_RECT (windowFrame), displayViews);
7750   [super setFrame:windowFrame display:displayViews];
7753 - (void)setFrame:(NSRect)windowFrame
7754          display:(BOOL)displayViews
7755          animate:(BOOL)performAnimation
7757   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
7758            " display:%d performAnimation:%d]",
7759            NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
7761   [super setFrame:windowFrame display:displayViews animate:performAnimation];
7764 - (void)setFrameTopLeftPoint:(NSPoint)point
7766   NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
7767            NSTRACE_ARG_POINT (point));
7769   [super setFrameTopLeftPoint:point];
7771 @end /* EmacsWindow */
7774 @implementation EmacsFSWindow
7776 - (BOOL)canBecomeKeyWindow
7778   return YES;
7781 - (BOOL)canBecomeMainWindow
7783   return YES;
7786 @end
7788 /* ==========================================================================
7790     EmacsScroller implementation
7792    ========================================================================== */
7795 @implementation EmacsScroller
7797 /* for repeat button push */
7798 #define SCROLL_BAR_FIRST_DELAY 0.5
7799 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
7801 + (CGFloat) scrollerWidth
7803   /* TODO: if we want to allow variable widths, this is the place to do it,
7804            however neither GNUstep nor Cocoa support it very well */
7805   CGFloat r;
7806 #if !defined (NS_IMPL_COCOA) || \
7807   MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
7808   r = [NSScroller scrollerWidth];
7809 #else
7810   r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
7811                                 scrollerStyle: NSScrollerStyleLegacy];
7812 #endif
7813   return r;
7816 - initFrame: (NSRect )r window: (Lisp_Object)nwin
7818   NSTRACE ("[EmacsScroller initFrame: window:]");
7820   if (r.size.width > r.size.height)
7821       horizontal = YES;
7822   else
7823       horizontal = NO;
7825   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
7826   [self setContinuous: YES];
7827   [self setEnabled: YES];
7829   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
7830      locked against the top and bottom edges, and right edge on macOS, where
7831      scrollers are on right. */
7832 #ifdef NS_IMPL_GNUSTEP
7833   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
7834 #else
7835   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
7836 #endif
7838   window = XWINDOW (nwin);
7839   condemned = NO;
7840   if (horizontal)
7841     pixel_length = NSWidth (r);
7842   else
7843     pixel_length = NSHeight (r);
7844   if (pixel_length == 0) pixel_length = 1;
7845   min_portion = 20 / pixel_length;
7847   frame = XFRAME (window->frame);
7848   if (FRAME_LIVE_P (frame))
7849     {
7850       int i;
7851       EmacsView *view = FRAME_NS_VIEW (frame);
7852       NSView *sview = [[view window] contentView];
7853       NSArray *subs = [sview subviews];
7855       /* disable optimization stopping redraw of other scrollbars */
7856       view->scrollbarsNeedingUpdate = 0;
7857       for (i =[subs count]-1; i >= 0; i--)
7858         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
7859           view->scrollbarsNeedingUpdate++;
7860       [sview addSubview: self];
7861     }
7863 /*  [self setFrame: r]; */
7865   return self;
7869 - (void)setFrame: (NSRect)newRect
7871   NSTRACE ("[EmacsScroller setFrame:]");
7873 /*  block_input (); */
7874   if (horizontal)
7875     pixel_length = NSWidth (newRect);
7876   else
7877     pixel_length = NSHeight (newRect);
7878   if (pixel_length == 0) pixel_length = 1;
7879   min_portion = 20 / pixel_length;
7880   [super setFrame: newRect];
7881 /*  unblock_input (); */
7885 - (void)dealloc
7887   NSTRACE ("[EmacsScroller dealloc]");
7888   if (window)
7889     {
7890       if (horizontal)
7891         wset_horizontal_scroll_bar (window, Qnil);
7892       else
7893         wset_vertical_scroll_bar (window, Qnil);
7894     }
7895   window = 0;
7896   [super dealloc];
7900 - condemn
7902   NSTRACE ("[EmacsScroller condemn]");
7903   condemned =YES;
7904   return self;
7908 - reprieve
7910   NSTRACE ("[EmacsScroller reprieve]");
7911   condemned =NO;
7912   return self;
7916 -(bool)judge
7918   NSTRACE ("[EmacsScroller judge]");
7919   bool ret = condemned;
7920   if (condemned)
7921     {
7922       EmacsView *view;
7923       block_input ();
7924       /* ensure other scrollbar updates after deletion */
7925       view = (EmacsView *)FRAME_NS_VIEW (frame);
7926       if (view != nil)
7927         view->scrollbarsNeedingUpdate++;
7928       if (window)
7929         {
7930           if (horizontal)
7931             wset_horizontal_scroll_bar (window, Qnil);
7932           else
7933             wset_vertical_scroll_bar (window, Qnil);
7934         }
7935       window = 0;
7936       [self removeFromSuperview];
7937       [self release];
7938       unblock_input ();
7939     }
7940   return ret;
7944 - (void)resetCursorRects
7946   NSRect visible = [self visibleRect];
7947   NSTRACE ("[EmacsScroller resetCursorRects]");
7949   if (!NSIsEmptyRect (visible))
7950     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
7951   [[NSCursor arrowCursor] setOnMouseEntered: YES];
7955 - (int) checkSamePosition: (int) position portion: (int) portion
7956                     whole: (int) whole
7958   return em_position ==position && em_portion ==portion && em_whole ==whole
7959     && portion != whole; /* needed for resize empty buf */
7963 - setPosition: (int)position portion: (int)portion whole: (int)whole
7965   NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
7967   em_position = position;
7968   em_portion = portion;
7969   em_whole = whole;
7971   if (portion >= whole)
7972     {
7973 #ifdef NS_IMPL_COCOA
7974       [self setKnobProportion: 1.0];
7975       [self setDoubleValue: 1.0];
7976 #else
7977       [self setFloatValue: 0.0 knobProportion: 1.0];
7978 #endif
7979     }
7980   else
7981     {
7982       float pos;
7983       CGFloat por;
7984       portion = max ((float)whole*min_portion/pixel_length, portion);
7985       pos = (float)position / (whole - portion);
7986       por = (CGFloat)portion/whole;
7987 #ifdef NS_IMPL_COCOA
7988       [self setKnobProportion: por];
7989       [self setDoubleValue: pos];
7990 #else
7991       [self setFloatValue: pos knobProportion: por];
7992 #endif
7993     }
7995   return self;
7998 /* set up emacs_event */
7999 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8001   Lisp_Object win;
8003   NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8005   if (!emacs_event)
8006     return;
8008   emacs_event->part = last_hit_part;
8009   emacs_event->code = 0;
8010   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8011   XSETWINDOW (win, window);
8012   emacs_event->frame_or_window = win;
8013   emacs_event->timestamp = EV_TIMESTAMP (e);
8014   emacs_event->arg = Qnil;
8016   if (horizontal)
8017     {
8018       emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8019       XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8020       XSETINT (emacs_event->y, em_whole);
8021     }
8022   else
8023     {
8024       emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8025       XSETINT (emacs_event->x, loc);
8026       XSETINT (emacs_event->y, pixel_length-20);
8027     }
8029   if (q_event_ptr)
8030     {
8031       n_emacs_events_pending++;
8032       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8033     }
8034   else
8035     hold_event (emacs_event);
8036   EVENT_INIT (*emacs_event);
8037   ns_send_appdefined (-1);
8041 /* called manually thru timer to implement repeated button action w/hold-down */
8042 - repeatScroll: (NSTimer *)scrollEntry
8044   NSEvent *e = [[self window] currentEvent];
8045   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
8046   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8048   NSTRACE ("[EmacsScroller repeatScroll:]");
8050   /* clear timer if need be */
8051   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8052     {
8053         [scroll_repeat_entry invalidate];
8054         [scroll_repeat_entry release];
8055         scroll_repeat_entry = nil;
8057         if (inKnob)
8058           return self;
8060         scroll_repeat_entry
8061           = [[NSTimer scheduledTimerWithTimeInterval:
8062                         SCROLL_BAR_CONTINUOUS_DELAY
8063                                             target: self
8064                                           selector: @selector (repeatScroll:)
8065                                           userInfo: 0
8066                                            repeats: YES]
8067               retain];
8068     }
8070   [self sendScrollEventAtLoc: 0 fromEvent: e];
8071   return self;
8075 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
8076    mouseDragged events without going into a modal loop. */
8077 - (void)mouseDown: (NSEvent *)e
8079   NSRect sr, kr;
8080   /* hitPart is only updated AFTER event is passed on */
8081   NSScrollerPart part = [self testPart: [e locationInWindow]];
8082   CGFloat loc, kloc, pos UNINIT;
8083   int edge = 0;
8085   NSTRACE ("[EmacsScroller mouseDown:]");
8087   switch (part)
8088     {
8089     case NSScrollerDecrementPage:
8090       last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
8091     case NSScrollerIncrementPage:
8092       last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
8093     case NSScrollerDecrementLine:
8094       last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
8095     case NSScrollerIncrementLine:
8096       last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
8097     case NSScrollerKnob:
8098       last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
8099     case NSScrollerKnobSlot:  /* GNUstep-only */
8100       last_hit_part = scroll_bar_move_ratio; break;
8101     default:  /* NSScrollerNoPart? */
8102       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
8103                (long) part);
8104       return;
8105     }
8107   if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
8108     {
8109       /* handle, or on GNUstep possibly slot */
8110       NSEvent *fake_event;
8111       int length;
8113       /* compute float loc in slot and mouse offset on knob */
8114       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8115                       toView: nil];
8116       if (horizontal)
8117         {
8118           length = NSWidth (sr);
8119           loc = ([e locationInWindow].x - NSMinX (sr));
8120         }
8121       else
8122         {
8123           length = NSHeight (sr);
8124           loc = length - ([e locationInWindow].y - NSMinY (sr));
8125         }
8127       if (loc <= 0.0)
8128         {
8129           loc = 0.0;
8130           edge = -1;
8131         }
8132       else if (loc >= length)
8133         {
8134           loc = length;
8135           edge = 1;
8136         }
8138       if (edge)
8139         kloc = 0.5 * edge;
8140       else
8141         {
8142           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8143                           toView: nil];
8144           if (horizontal)
8145             kloc = ([e locationInWindow].x - NSMinX (kr));
8146           else
8147             kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8148         }
8149       last_mouse_offset = kloc;
8151       if (part != NSScrollerKnob)
8152         /* this is a slot click on GNUstep: go straight there */
8153         pos = loc;
8155       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8156       fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
8157                                       location: [e locationInWindow]
8158                                  modifierFlags: [e modifierFlags]
8159                                      timestamp: [e timestamp]
8160                                   windowNumber: [e windowNumber]
8161                                        context: [e context]
8162                                    eventNumber: [e eventNumber]
8163                                     clickCount: [e clickCount]
8164                                       pressure: [e pressure]];
8165       [super mouseUp: fake_event];
8166     }
8167   else
8168     {
8169       pos = 0;      /* ignored */
8171       /* set a timer to repeat, as we can't let superclass do this modally */
8172       scroll_repeat_entry
8173         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8174                                             target: self
8175                                           selector: @selector (repeatScroll:)
8176                                           userInfo: 0
8177                                            repeats: YES]
8178             retain];
8179     }
8181   if (part != NSScrollerKnob)
8182     [self sendScrollEventAtLoc: pos fromEvent: e];
8186 /* Called as we manually track scroller drags, rather than superclass. */
8187 - (void)mouseDragged: (NSEvent *)e
8189     NSRect sr;
8190     double loc, pos;
8191     int length;
8193     NSTRACE ("[EmacsScroller mouseDragged:]");
8195       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8196                       toView: nil];
8198       if (horizontal)
8199         {
8200           length = NSWidth (sr);
8201           loc = ([e locationInWindow].x - NSMinX (sr));
8202         }
8203       else
8204         {
8205           length = NSHeight (sr);
8206           loc = length - ([e locationInWindow].y - NSMinY (sr));
8207         }
8209       if (loc <= 0.0)
8210         {
8211           loc = 0.0;
8212         }
8213       else if (loc >= length + last_mouse_offset)
8214         {
8215           loc = length + last_mouse_offset;
8216         }
8218       pos = (loc - last_mouse_offset);
8219       [self sendScrollEventAtLoc: pos fromEvent: e];
8223 - (void)mouseUp: (NSEvent *)e
8225   NSTRACE ("[EmacsScroller mouseUp:]");
8227   if (scroll_repeat_entry)
8228     {
8229       [scroll_repeat_entry invalidate];
8230       [scroll_repeat_entry release];
8231       scroll_repeat_entry = nil;
8232     }
8233   last_hit_part = scroll_bar_above_handle;
8237 /* treat scrollwheel events in the bar as though they were in the main window */
8238 - (void) scrollWheel: (NSEvent *)theEvent
8240   NSTRACE ("[EmacsScroller scrollWheel:]");
8242   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8243   [view mouseDown: theEvent];
8246 @end  /* EmacsScroller */
8249 #ifdef NS_IMPL_GNUSTEP
8250 /* Dummy class to get rid of startup warnings.  */
8251 @implementation EmacsDocument
8253 @end
8254 #endif
8257 /* ==========================================================================
8259    Font-related functions; these used to be in nsfaces.m
8261    ========================================================================== */
8264 Lisp_Object
8265 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8267   struct font *font = XFONT_OBJECT (font_object);
8268   EmacsView *view = FRAME_NS_VIEW (f);
8269   int font_ascent, font_descent;
8271   if (fontset < 0)
8272     fontset = fontset_from_font (font_object);
8273   FRAME_FONTSET (f) = fontset;
8275   if (FRAME_FONT (f) == font)
8276     /* This font is already set in frame F.  There's nothing more to
8277        do.  */
8278     return font_object;
8280   FRAME_FONT (f) = font;
8282   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8283   FRAME_COLUMN_WIDTH (f) = font->average_width;
8284   get_font_ascent_descent (font, &font_ascent, &font_descent);
8285   FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8287   /* Compute the scroll bar width in character columns.  */
8288   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8289     {
8290       int wid = FRAME_COLUMN_WIDTH (f);
8291       FRAME_CONFIG_SCROLL_BAR_COLS (f)
8292         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8293     }
8294   else
8295     {
8296       int wid = FRAME_COLUMN_WIDTH (f);
8297       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8298     }
8300   /* Compute the scroll bar height in character lines.  */
8301   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8302     {
8303       int height = FRAME_LINE_HEIGHT (f);
8304       FRAME_CONFIG_SCROLL_BAR_LINES (f)
8305         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8306     }
8307   else
8308     {
8309       int height = FRAME_LINE_HEIGHT (f);
8310       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8311     }
8313   /* Now make the frame display the given font.  */
8314   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8315     adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8316                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8317                        false, Qfont);
8319   return font_object;
8323 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8324 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8325          in 1.43. */
8327 const char *
8328 ns_xlfd_to_fontname (const char *xlfd)
8329 /* --------------------------------------------------------------------------
8330     Convert an X font name (XLFD) to an NS font name.
8331     Only family is used.
8332     The string returned is temporarily allocated.
8333    -------------------------------------------------------------------------- */
8335   char *name = xmalloc (180);
8336   int i, len;
8337   const char *ret;
8339   if (!strncmp (xlfd, "--", 2))
8340     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8341   else
8342     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8344   /* stopgap for malformed XLFD input */
8345   if (strlen (name) == 0)
8346     strcpy (name, "Monaco");
8348   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8349      also uppercase after '-' or ' ' */
8350   name[0] = c_toupper (name[0]);
8351   for (len =strlen (name), i =0; i<len; i++)
8352     {
8353       if (name[i] == '$')
8354         {
8355           name[i] = '-';
8356           if (i+1<len)
8357             name[i+1] = c_toupper (name[i+1]);
8358         }
8359       else if (name[i] == '_')
8360         {
8361           name[i] = ' ';
8362           if (i+1<len)
8363             name[i+1] = c_toupper (name[i+1]);
8364         }
8365     }
8366 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
8367   ret = [[NSString stringWithUTF8String: name] UTF8String];
8368   xfree (name);
8369   return ret;
8373 void
8374 syms_of_nsterm (void)
8376   NSTRACE ("syms_of_nsterm");
8378   ns_antialias_threshold = 10.0;
8380   /* from 23+ we need to tell emacs what modifiers there are.. */
8381   DEFSYM (Qmodifier_value, "modifier-value");
8382   DEFSYM (Qalt, "alt");
8383   DEFSYM (Qhyper, "hyper");
8384   DEFSYM (Qmeta, "meta");
8385   DEFSYM (Qsuper, "super");
8386   DEFSYM (Qcontrol, "control");
8387   DEFSYM (QUTF8_STRING, "UTF8_STRING");
8389   DEFSYM (Qfile, "file");
8390   DEFSYM (Qurl, "url");
8392   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8393   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8394   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8395   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8396   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8398   DEFVAR_LISP ("ns-input-file", ns_input_file,
8399               "The file specified in the last NS event.");
8400   ns_input_file =Qnil;
8402   DEFVAR_LISP ("ns-working-text", ns_working_text,
8403               "String for visualizing working composition sequence.");
8404   ns_working_text =Qnil;
8406   DEFVAR_LISP ("ns-input-font", ns_input_font,
8407               "The font specified in the last NS event.");
8408   ns_input_font =Qnil;
8410   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8411               "The fontsize specified in the last NS event.");
8412   ns_input_fontsize =Qnil;
8414   DEFVAR_LISP ("ns-input-line", ns_input_line,
8415                "The line specified in the last NS event.");
8416   ns_input_line =Qnil;
8418   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
8419                "The service name specified in the last NS event.");
8420   ns_input_spi_name =Qnil;
8422   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
8423                "The service argument specified in the last NS event.");
8424   ns_input_spi_arg =Qnil;
8426   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
8427                "This variable describes the behavior of the alternate or option key.\n\
8428 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8429 that key.\n\
8430 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8431 at all, allowing it to be used at a lower level for accented character entry.");
8432   ns_alternate_modifier = Qmeta;
8434   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
8435                "This variable describes the behavior of the right alternate or option key.\n\
8436 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8437 that key.\n\
8438 Set to left means be the same key as `ns-alternate-modifier'.\n\
8439 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8440 at all, allowing it to be used at a lower level for accented character entry.");
8441   ns_right_alternate_modifier = Qleft;
8443   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
8444                "This variable describes the behavior of the command key.\n\
8445 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8446 that key.");
8447   ns_command_modifier = Qsuper;
8449   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
8450                "This variable describes the behavior of the right command key.\n\
8451 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8452 that key.\n\
8453 Set to left means be the same key as `ns-command-modifier'.\n\
8454 Set to none means that the command / option key is not interpreted by Emacs\n\
8455 at all, allowing it to be used at a lower level for accented character entry.");
8456   ns_right_command_modifier = Qleft;
8458   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
8459                "This variable describes the behavior of the control key.\n\
8460 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8461 that key.");
8462   ns_control_modifier = Qcontrol;
8464   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
8465                "This variable describes the behavior of the right control key.\n\
8466 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8467 that key.\n\
8468 Set to left means be the same key as `ns-control-modifier'.\n\
8469 Set to none means that the control / option key is not interpreted by Emacs\n\
8470 at all, allowing it to be used at a lower level for accented character entry.");
8471   ns_right_control_modifier = Qleft;
8473   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
8474                "This variable describes the behavior of the function key (on laptops).\n\
8475 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8476 that key.\n\
8477 Set to none means that the function key is not interpreted by Emacs at all,\n\
8478 allowing it to be used at a lower level for accented character entry.");
8479   ns_function_modifier = Qnone;
8481   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
8482                "Non-nil (the default) means to render text antialiased.");
8483   ns_antialias_text = Qt;
8485   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
8486                "Whether to confirm application quit using dialog.");
8487   ns_confirm_quit = Qnil;
8489   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
8490                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
8491 Only works on Mac OS X 10.6 or later.  */);
8492   ns_auto_hide_menu_bar = Qnil;
8494   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
8495      doc: /*Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
8496 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
8497 multiple monitors, but lacks tool bar.  This variable is ignored on
8498 Mac OS X < 10.7.  Default is t for 10.7 and later, nil otherwise.  */);
8499 #ifdef HAVE_NATIVE_FS
8500   ns_use_native_fullscreen = YES;
8501 #else
8502   ns_use_native_fullscreen = NO;
8503 #endif
8504   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
8506   DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
8507      doc: /*Non-nil means use animation on non-native fullscreen.
8508 For native fullscreen, this does nothing.
8509 Default is nil.  */);
8510   ns_use_fullscreen_animation = NO;
8512   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
8513      doc: /*Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
8514 Note that this does not apply to images.
8515 This variable is ignored on Mac OS X < 10.7 and GNUstep.  */);
8516   ns_use_srgb_colorspace = YES;
8518   /* TODO: move to common code */
8519   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
8520                doc: /* Which toolkit scroll bars Emacs uses, if any.
8521 A value of nil means Emacs doesn't use toolkit scroll bars.
8522 With the X Window system, the value is a symbol describing the
8523 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
8524 With MS Windows or Nextstep, the value is t.  */);
8525   Vx_toolkit_scroll_bars = Qt;
8527   DEFVAR_BOOL ("x-use-underline-position-properties",
8528                x_use_underline_position_properties,
8529      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
8530 A value of nil means ignore them.  If you encounter fonts with bogus
8531 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
8532 to 4.1, set this to nil. */);
8533   x_use_underline_position_properties = 0;
8535   DEFVAR_BOOL ("x-underline-at-descent-line",
8536                x_underline_at_descent_line,
8537      doc: /* Non-nil means to draw the underline at the same place as the descent line.
8538 A value of nil means to draw the underline according to the value of the
8539 variable `x-use-underline-position-properties', which is usually at the
8540 baseline level.  The default value is nil.  */);
8541   x_underline_at_descent_line = 0;
8543   /* Tell Emacs about this window system.  */
8544   Fprovide (Qns, Qnil);
8546   DEFSYM (Qcocoa, "cocoa");
8547   DEFSYM (Qgnustep, "gnustep");
8549 #ifdef NS_IMPL_COCOA
8550   Fprovide (Qcocoa, Qnil);
8551   syms_of_macfont ();
8552 #else
8553   Fprovide (Qgnustep, Qnil);
8554   syms_of_nsfont ();
8555 #endif