; * etc/NEWS: Use double spaces to end a sentence.
[emacs.git] / src / nsterm.m
blob43d1377f8a717cf6b9be8661fb2acb5d4cbb693a
1 /* NeXT/Open/GNUstep / MacOSX communication module.      -*- coding: utf-8 -*-
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2016 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
11 (at 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 MacOSX/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
72 extern NSString *NSMenuDidBeginTrackingNotification;
75 /* ==========================================================================
77    NSTRACE, Trace support.
79    ========================================================================== */
81 #if NSTRACE_ENABLED
83 /* The following use "volatile" since they can be accessed from
84    parallel threads. */
85 volatile int nstrace_num = 0;
86 volatile int nstrace_depth = 0;
88 /* When 0, no trace is emitted.  This is used by NSTRACE_WHEN and
89    NSTRACE_UNLESS to silence functions called.
91    TODO: This should really be a thread-local variable, to avoid that
92    a function with disabled trace thread silence trace output in
93    another.  However, in practice this seldom is a problem. */
94 volatile int nstrace_enabled_global = 1;
96 /* Called when nstrace_enabled goes out of scope. */
97 void nstrace_leave(int * pointer_to_nstrace_enabled)
99   if (*pointer_to_nstrace_enabled)
100     {
101       --nstrace_depth;
102     }
106 /* Called when nstrace_saved_enabled_global goes out of scope. */
107 void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
109   nstrace_enabled_global = *pointer_to_saved_enabled_global;
113 char const * nstrace_fullscreen_type_name (int fs_type)
115   switch (fs_type)
116     {
117     case -1:                   return "-1";
118     case FULLSCREEN_NONE:      return "FULLSCREEN_NONE";
119     case FULLSCREEN_WIDTH:     return "FULLSCREEN_WIDTH";
120     case FULLSCREEN_HEIGHT:    return "FULLSCREEN_HEIGHT";
121     case FULLSCREEN_BOTH:      return "FULLSCREEN_BOTH";
122     case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
123     default:                   return "FULLSCREEN_?????";
124     }
126 #endif
129 /* ==========================================================================
131    NSColor, EmacsColor category.
133    ========================================================================== */
134 @implementation NSColor (EmacsColor)
135 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
136                          blue:(CGFloat)blue alpha:(CGFloat)alpha
138 #ifdef NS_IMPL_COCOA
139 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
140   if (ns_use_srgb_colorspace)
141       return [NSColor colorWithSRGBRed: red
142                                  green: green
143                                   blue: blue
144                                  alpha: alpha];
145 #endif
146 #endif
147   return [NSColor colorWithCalibratedRed: red
148                                    green: green
149                                     blue: blue
150                                    alpha: alpha];
153 - (NSColor *)colorUsingDefaultColorSpace
155 #ifdef NS_IMPL_COCOA
156 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
157   if (ns_use_srgb_colorspace)
158     return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
159 #endif
160 #endif
161   return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
164 @end
166 /* ==========================================================================
168     Local declarations
170    ========================================================================== */
172 /* Convert a symbol indexed with an NSxxx value to a value as defined
173    in keyboard.c (lispy_function_key). I hope this is a correct way
174    of doing things... */
175 static unsigned convert_ns_to_X_keysym[] =
177   NSHomeFunctionKey,            0x50,
178   NSLeftArrowFunctionKey,       0x51,
179   NSUpArrowFunctionKey,         0x52,
180   NSRightArrowFunctionKey,      0x53,
181   NSDownArrowFunctionKey,       0x54,
182   NSPageUpFunctionKey,          0x55,
183   NSPageDownFunctionKey,        0x56,
184   NSEndFunctionKey,             0x57,
185   NSBeginFunctionKey,           0x58,
186   NSSelectFunctionKey,          0x60,
187   NSPrintFunctionKey,           0x61,
188   NSClearLineFunctionKey,       0x0B,
189   NSExecuteFunctionKey,         0x62,
190   NSInsertFunctionKey,          0x63,
191   NSUndoFunctionKey,            0x65,
192   NSRedoFunctionKey,            0x66,
193   NSMenuFunctionKey,            0x67,
194   NSFindFunctionKey,            0x68,
195   NSHelpFunctionKey,            0x6A,
196   NSBreakFunctionKey,           0x6B,
198   NSF1FunctionKey,              0xBE,
199   NSF2FunctionKey,              0xBF,
200   NSF3FunctionKey,              0xC0,
201   NSF4FunctionKey,              0xC1,
202   NSF5FunctionKey,              0xC2,
203   NSF6FunctionKey,              0xC3,
204   NSF7FunctionKey,              0xC4,
205   NSF8FunctionKey,              0xC5,
206   NSF9FunctionKey,              0xC6,
207   NSF10FunctionKey,             0xC7,
208   NSF11FunctionKey,             0xC8,
209   NSF12FunctionKey,             0xC9,
210   NSF13FunctionKey,             0xCA,
211   NSF14FunctionKey,             0xCB,
212   NSF15FunctionKey,             0xCC,
213   NSF16FunctionKey,             0xCD,
214   NSF17FunctionKey,             0xCE,
215   NSF18FunctionKey,             0xCF,
216   NSF19FunctionKey,             0xD0,
217   NSF20FunctionKey,             0xD1,
218   NSF21FunctionKey,             0xD2,
219   NSF22FunctionKey,             0xD3,
220   NSF23FunctionKey,             0xD4,
221   NSF24FunctionKey,             0xD5,
223   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
224   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
225   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
227   NSTabCharacter,               0x09,
228   0x19,                         0x09,  /* left tab->regular since pass shift */
229   NSCarriageReturnCharacter,    0x0D,
230   NSNewlineCharacter,           0x0D,
231   NSEnterCharacter,             0x8D,
233   0x41|NSNumericPadKeyMask,     0xAE,  /* KP_Decimal */
234   0x43|NSNumericPadKeyMask,     0xAA,  /* KP_Multiply */
235   0x45|NSNumericPadKeyMask,     0xAB,  /* KP_Add */
236   0x4B|NSNumericPadKeyMask,     0xAF,  /* KP_Divide */
237   0x4E|NSNumericPadKeyMask,     0xAD,  /* KP_Subtract */
238   0x51|NSNumericPadKeyMask,     0xBD,  /* KP_Equal */
239   0x52|NSNumericPadKeyMask,     0xB0,  /* KP_0 */
240   0x53|NSNumericPadKeyMask,     0xB1,  /* KP_1 */
241   0x54|NSNumericPadKeyMask,     0xB2,  /* KP_2 */
242   0x55|NSNumericPadKeyMask,     0xB3,  /* KP_3 */
243   0x56|NSNumericPadKeyMask,     0xB4,  /* KP_4 */
244   0x57|NSNumericPadKeyMask,     0xB5,  /* KP_5 */
245   0x58|NSNumericPadKeyMask,     0xB6,  /* KP_6 */
246   0x59|NSNumericPadKeyMask,     0xB7,  /* KP_7 */
247   0x5B|NSNumericPadKeyMask,     0xB8,  /* KP_8 */
248   0x5C|NSNumericPadKeyMask,     0xB9,  /* KP_9 */
250   0x1B,                         0x1B   /* escape */
253 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
254    the maximum font size to NOT antialias.  On GNUstep there is currently
255    no way to control this behavior. */
256 float ns_antialias_threshold;
258 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
259 NSString *ns_app_name = @"Emacs";  /* default changed later */
261 /* Display variables */
262 struct ns_display_info *x_display_list; /* Chain of existing displays */
263 long context_menu_value = 0;
265 /* display update */
266 static struct frame *ns_updating_frame;
267 static NSView *focus_view = NULL;
268 static int ns_window_num = 0;
269 #ifdef NS_IMPL_GNUSTEP
270 static NSRect uRect;            // TODO: This is dead, remove it?
271 #endif
272 static BOOL gsaved = NO;
273 static BOOL ns_fake_keydown = NO;
274 #ifdef NS_IMPL_COCOA
275 static BOOL ns_menu_bar_is_hidden = NO;
276 #endif
277 /*static int debug_lock = 0; */
279 /* event loop */
280 static BOOL send_appdefined = YES;
281 #define NO_APPDEFINED_DATA (-8)
282 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
283 static NSTimer *timed_entry = 0;
284 static NSTimer *scroll_repeat_entry = nil;
285 static fd_set select_readfds, select_writefds;
286 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
287 static int select_nfds = 0, select_valid = 0;
288 static struct timespec select_timeout = { 0, 0 };
289 static int selfds[2] = { -1, -1 };
290 static pthread_mutex_t select_mutex;
291 static int apploopnr = 0;
292 static NSAutoreleasePool *outerpool;
293 static struct input_event *emacs_event = NULL;
294 static struct input_event *q_event_ptr = NULL;
295 static int n_emacs_events_pending = 0;
296 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
297   *ns_pending_service_args;
298 static BOOL ns_do_open_file = NO;
299 static BOOL ns_last_use_native_fullscreen;
301 /* Non-zero means that a HELP_EVENT has been generated since Emacs
302    start.  */
304 static BOOL any_help_event_p = NO;
306 static struct {
307   struct input_event *q;
308   int nr, cap;
309 } hold_event_q = {
310   NULL, 0, 0
313 static NSString *represented_filename = nil;
314 static struct frame *represented_frame = 0;
316 #ifdef NS_IMPL_COCOA
318  * State for pending menu activation:
319  * MENU_NONE     Normal state
320  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
321  *               run lisp to update the menu.
322  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
323  *               will open.
324  */
325 #define MENU_NONE 0
326 #define MENU_PENDING 1
327 #define MENU_OPENING 2
328 static int menu_will_open_state = MENU_NONE;
330 /* Saved position for menu click.  */
331 static CGPoint menu_mouse_point;
332 #endif
334 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
335 #define NS_FUNCTION_KEY_MASK 0x800000
336 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
337 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
338 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
339 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
340 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
341 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
342 #define EV_MODIFIERS2(flags)                          \
343     (((flags & NSHelpKeyMask) ?           \
344            hyper_modifier : 0)                        \
345      | (!EQ (ns_right_alternate_modifier, Qleft) && \
346         ((flags & NSRightAlternateKeyMask) \
347          == NSRightAlternateKeyMask) ? \
348            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
349      | ((flags & NSAlternateKeyMask) ?                 \
350            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
351      | ((flags & NSShiftKeyMask) ?     \
352            shift_modifier : 0)                        \
353      | (!EQ (ns_right_control_modifier, Qleft) && \
354         ((flags & NSRightControlKeyMask) \
355          == NSRightControlKeyMask) ? \
356            parse_solitary_modifier (ns_right_control_modifier) : 0) \
357      | ((flags & NSControlKeyMask) ?      \
358            parse_solitary_modifier (ns_control_modifier) : 0)     \
359      | ((flags & NS_FUNCTION_KEY_MASK) ?  \
360            parse_solitary_modifier (ns_function_modifier) : 0)    \
361      | (!EQ (ns_right_command_modifier, Qleft) && \
362         ((flags & NSRightCommandKeyMask) \
363          == NSRightCommandKeyMask) ? \
364            parse_solitary_modifier (ns_right_command_modifier) : 0) \
365      | ((flags & NSCommandKeyMask) ?      \
366            parse_solitary_modifier (ns_command_modifier):0))
367 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
369 #define EV_UDMODIFIERS(e)                                      \
370     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
371      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
372      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
373      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
374      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
375      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
376      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
377      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
378      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
380 #define EV_BUTTON(e)                                                         \
381     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
382       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
383      [e buttonNumber] - 1)
385 /* Convert the time field to a timestamp in milliseconds. */
386 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
388 /* This is a piece of code which is common to all the event handling
389    methods.  Maybe it should even be a function.  */
390 #define EV_TRAILER(e)                                                   \
391   {                                                                     \
392     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
393     EV_TRAILER2 (e);                                                    \
394   }
396 #define EV_TRAILER2(e)                                                  \
397   {                                                                     \
398       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
399       if (q_event_ptr)                                                  \
400         {                                                               \
401           Lisp_Object tem = Vinhibit_quit;                              \
402           Vinhibit_quit = Qt;                                           \
403           n_emacs_events_pending++;                                     \
404           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
405           Vinhibit_quit = tem;                                          \
406         }                                                               \
407       else                                                              \
408         hold_event (emacs_event);                                       \
409       EVENT_INIT (*emacs_event);                                        \
410       ns_send_appdefined (-1);                                          \
411     }
413 /* TODO: get rid of need for these forward declarations */
414 static void ns_condemn_scroll_bars (struct frame *f);
415 static void ns_judge_scroll_bars (struct frame *f);
416 void x_set_frame_alpha (struct frame *f);
419 /* ==========================================================================
421     Utilities
423    ========================================================================== */
425 void
426 ns_set_represented_filename (NSString* fstr, struct frame *f)
428   represented_filename = [fstr retain];
429   represented_frame = f;
432 void
433 ns_init_events (struct input_event* ev)
435   EVENT_INIT (*ev);
436   emacs_event = ev;
439 void
440 ns_finish_events ()
442   emacs_event = NULL;
445 static void
446 hold_event (struct input_event *event)
448   if (hold_event_q.nr == hold_event_q.cap)
449     {
450       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
451       else hold_event_q.cap *= 2;
452       hold_event_q.q =
453         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
454     }
456   hold_event_q.q[hold_event_q.nr++] = *event;
457   /* Make sure ns_read_socket is called, i.e. we have input.  */
458   raise (SIGIO);
459   send_appdefined = YES;
462 static Lisp_Object
463 append2 (Lisp_Object list, Lisp_Object item)
464 /* --------------------------------------------------------------------------
465    Utility to append to a list
466    -------------------------------------------------------------------------- */
468   return CALLN (Fnconc, list, list1 (item));
472 const char *
473 ns_etc_directory (void)
474 /* If running as a self-contained app bundle, return as a string the
475    filename of the etc directory, if present; else nil.  */
477   NSBundle *bundle = [NSBundle mainBundle];
478   NSString *resourceDir = [bundle resourcePath];
479   NSString *resourcePath;
480   NSFileManager *fileManager = [NSFileManager defaultManager];
481   BOOL isDir;
483   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
484   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
485     {
486       if (isDir) return [resourcePath UTF8String];
487     }
488   return NULL;
492 const char *
493 ns_exec_path (void)
494 /* If running as a self-contained app bundle, return as a path string
495    the filenames of the libexec and bin directories, ie libexec:bin.
496    Otherwise, return nil.
497    Normally, Emacs does not add its own bin/ directory to the PATH.
498    However, a self-contained NS build has a different layout, with
499    bin/ and libexec/ subdirectories in the directory that contains
500    Emacs.app itself.
501    We put libexec first, because init_callproc_1 uses the first
502    element to initialize exec-directory.  An alternative would be
503    for init_callproc to check for invocation-directory/libexec.
506   NSBundle *bundle = [NSBundle mainBundle];
507   NSString *resourceDir = [bundle resourcePath];
508   NSString *binDir = [bundle bundlePath];
509   NSString *resourcePath, *resourcePaths;
510   NSRange range;
511   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
512   NSFileManager *fileManager = [NSFileManager defaultManager];
513   NSArray *paths;
514   NSEnumerator *pathEnum;
515   BOOL isDir;
517   range = [resourceDir rangeOfString: @"Contents"];
518   if (range.location != NSNotFound)
519     {
520       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
521 #ifdef NS_IMPL_COCOA
522       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
523 #endif
524     }
526   paths = [binDir stringsByAppendingPaths:
527                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
528   pathEnum = [paths objectEnumerator];
529   resourcePaths = @"";
531   while ((resourcePath = [pathEnum nextObject]))
532     {
533       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
534         if (isDir)
535           {
536             if ([resourcePaths length] > 0)
537               resourcePaths
538                 = [resourcePaths stringByAppendingString: pathSeparator];
539             resourcePaths
540               = [resourcePaths stringByAppendingString: resourcePath];
541           }
542     }
543   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
545   return NULL;
549 const char *
550 ns_load_path (void)
551 /* If running as a self-contained app bundle, return as a path string
552    the filenames of the site-lisp and lisp directories.
553    Ie, site-lisp:lisp.  Otherwise, return nil.  */
555   NSBundle *bundle = [NSBundle mainBundle];
556   NSString *resourceDir = [bundle resourcePath];
557   NSString *resourcePath, *resourcePaths;
558   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
559   NSFileManager *fileManager = [NSFileManager defaultManager];
560   BOOL isDir;
561   NSArray *paths = [resourceDir stringsByAppendingPaths:
562                               [NSArray arrayWithObjects:
563                                          @"site-lisp", @"lisp", nil]];
564   NSEnumerator *pathEnum = [paths objectEnumerator];
565   resourcePaths = @"";
567   /* Hack to skip site-lisp.  */
568   if (no_site_lisp) resourcePath = [pathEnum nextObject];
570   while ((resourcePath = [pathEnum nextObject]))
571     {
572       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
573         if (isDir)
574           {
575             if ([resourcePaths length] > 0)
576               resourcePaths
577                 = [resourcePaths stringByAppendingString: pathSeparator];
578             resourcePaths
579               = [resourcePaths stringByAppendingString: resourcePath];
580           }
581     }
582   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
584   return NULL;
588 void
589 ns_init_locale (void)
590 /* OS X doesn't set any environment variables for the locale when run
591    from the GUI. Get the locale from the OS and set LANG. */
593   NSLocale *locale = [NSLocale currentLocale];
595   NSTRACE ("ns_init_locale");
597   @try
598     {
599       /* Set LANG to locale, but not if LANG is already set. */
600       setenv("LANG", [[locale localeIdentifier] UTF8String], 0);
601     }
602   @catch (NSException *e)
603     {
604       NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
605     }
609 void
610 ns_release_object (void *obj)
611 /* --------------------------------------------------------------------------
612     Release an object (callable from C)
613    -------------------------------------------------------------------------- */
615     [(id)obj release];
619 void
620 ns_retain_object (void *obj)
621 /* --------------------------------------------------------------------------
622     Retain an object (callable from C)
623    -------------------------------------------------------------------------- */
625     [(id)obj retain];
629 void *
630 ns_alloc_autorelease_pool (void)
631 /* --------------------------------------------------------------------------
632      Allocate a pool for temporary objects (callable from C)
633    -------------------------------------------------------------------------- */
635   return [[NSAutoreleasePool alloc] init];
639 void
640 ns_release_autorelease_pool (void *pool)
641 /* --------------------------------------------------------------------------
642      Free a pool and temporary objects it refers to (callable from C)
643    -------------------------------------------------------------------------- */
645   ns_release_object (pool);
649 /* True, if the menu bar should be hidden.  */
651 static BOOL
652 ns_menu_bar_should_be_hidden (void)
654   return !NILP (ns_auto_hide_menu_bar)
655     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
659 static CGFloat
660 ns_menu_bar_height (NSScreen *screen)
661 /* The height of the menu bar, if visible.
663    Note: Don't use this when fullscreen is enabled -- the screen
664    sometimes includes, sometimes excludes the menu bar area. */
666   CGFloat res;
668   if (ns_menu_bar_should_be_hidden())
669     {
670       res = 0;
671     }
672   else
673     {
674       NSRect screenFrame = [screen frame];
675       NSRect screenVisibleFrame = [screen visibleFrame];
677       CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
678       CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
679                                  + screenVisibleFrame.size.height);
681       res = frameTop - visibleFrameTop;
683     }
685   NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
687   return res;
691 /* ==========================================================================
693     Focus (clipping) and screen update
695    ========================================================================== */
698 // Window constraining
699 // -------------------
701 // To ensure that the windows are not placed under the menu bar, they
702 // are typically moved by the call-back constrainFrameRect. However,
703 // by overriding it, it's possible to inhibit this, leaving the window
704 // in it's original position.
706 // It's possible to hide the menu bar. However, technically, it's only
707 // possible to hide it when the application is active. To ensure that
708 // this work properly, the menu bar and window constraining are
709 // deferred until the application becomes active.
711 // Even though it's not possible to manually move a window above the
712 // top of the screen, it is allowed if it's done programmatically,
713 // when the menu is hidden. This allows the editable area to cover the
714 // full screen height.
716 // Test cases
717 // ----------
719 // Use the following extra files:
721 //    init.el:
722 //       ;; Hide menu and place frame slightly above the top of the screen.
723 //       (setq ns-auto-hide-menu-bar t)
724 //       (set-frame-position (selected-frame) 0 -20)
726 // Test 1:
728 //    emacs -Q -l init.el
730 //    Result: No menu bar, and the title bar should be above the screen.
732 // Test 2:
734 //    emacs -Q
736 //    Result: Menu bar visible, frame placed immediately below the menu.
739 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
741   NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
742              NSTRACE_ARG_RECT (frameRect));
744   // --------------------
745   // Collect information about the screen the frame is covering.
746   //
748   NSArray *screens = [NSScreen screens];
749   NSUInteger nr_screens = [screens count];
751   int i;
753   // The height of the menu bar, if present in any screen the frame is
754   // displayed in.
755   int menu_bar_height = 0;
757   // A rectangle covering all the screen the frame is displayed in.
758   NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
759   for (i = 0; i < nr_screens; ++i )
760     {
761       NSScreen *s = [screens objectAtIndex: i];
762       NSRect scrRect = [s frame];
764       NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
765                    i, NSTRACE_ARG_RECT (scrRect));
767       if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
768         {
769           multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
771           if (!isFullscreen)
772             {
773               CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
774               menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
775             }
776         }
777     }
779   NSTRACE_RECT ("multiscreenRect", multiscreenRect);
781   NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
783   if (multiscreenRect.size.width == 0
784       || multiscreenRect.size.height == 0)
785     {
786       // Failed to find any monitor, give up.
787       NSTRACE_MSG ("multiscreenRect empty");
788       NSTRACE_RETURN_RECT (frameRect);
789       return frameRect;
790     }
793   // --------------------
794   // Find a suitable placement.
795   //
797   if (ns_menu_bar_should_be_hidden())
798     {
799       // When the menu bar is hidden, the user may place part of the
800       // frame above the top of the screen, for example to hide the
801       // title bar.
802       //
803       // Hence, keep the original position.
804     }
805   else
806     {
807       // Ensure that the frame is below the menu bar, or below the top
808       // of the screen.
809       //
810       // This assume that the menu bar is placed at the top in the
811       // rectangle that covers the monitors.  (It doesn't have to be,
812       // but if it's not it's hard to do anything useful.)
813       CGFloat topOfWorkArea = (multiscreenRect.origin.y
814                                + multiscreenRect.size.height
815                                - menu_bar_height);
817       CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
818       if (topOfFrame > topOfWorkArea)
819         {
820           frameRect.origin.y -= topOfFrame - topOfWorkArea;
821           NSTRACE_RECT ("After placement adjust", frameRect);
822         }
823     }
825   // Include the following section to restrict frame to the screens.
826   // (If so, update it to allow the frame to stretch down below the
827   // screen.)
828 #if 0
829   // --------------------
830   // Ensure frame doesn't stretch below the screens.
831   //
833   CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
835   if (diff > 0)
836     {
837       frameRect.origin.y = multiscreenRect.origin.y;
838       frameRect.size.height -= diff;
839     }
840 #endif
842   NSTRACE_RETURN_RECT (frameRect);
843   return frameRect;
847 static void
848 ns_constrain_all_frames (void)
849 /* --------------------------------------------------------------------------
850      Ensure that the menu bar doesn't cover any frames.
851    -------------------------------------------------------------------------- */
853   Lisp_Object tail, frame;
855   NSTRACE ("ns_constrain_all_frames");
857   block_input ();
859   FOR_EACH_FRAME (tail, frame)
860     {
861       struct frame *f = XFRAME (frame);
862       if (FRAME_NS_P (f))
863         {
864           EmacsView *view = FRAME_NS_VIEW (f);
866           if (![view isFullscreen])
867             {
868               [[view window]
869                 setFrame:constrain_frame_rect([[view window] frame], false)
870                  display:NO];
871             }
872         }
873     }
875   unblock_input ();
879 static void
880 ns_update_auto_hide_menu_bar (void)
881 /* --------------------------------------------------------------------------
882      Show or hide the menu bar, based on user setting.
883    -------------------------------------------------------------------------- */
885 #ifdef NS_IMPL_COCOA
886   NSTRACE ("ns_update_auto_hide_menu_bar");
888   block_input ();
890   if (NSApp != nil && [NSApp isActive])
891     {
892       // Note, "setPresentationOptions" triggers an error unless the
893       // application is active.
894       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
896       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
897         {
898           NSApplicationPresentationOptions options
899             = NSApplicationPresentationDefault;
901           if (menu_bar_should_be_hidden)
902             options |= NSApplicationPresentationAutoHideMenuBar
903               | NSApplicationPresentationAutoHideDock;
905           [NSApp setPresentationOptions: options];
907           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
909           if (!ns_menu_bar_is_hidden)
910             {
911               ns_constrain_all_frames ();
912             }
913         }
914     }
916   unblock_input ();
917 #endif
921 static void
922 ns_update_begin (struct frame *f)
923 /* --------------------------------------------------------------------------
924    Prepare for a grouped sequence of drawing calls
925    external (RIF) call; whole frame, called before update_window_begin
926    -------------------------------------------------------------------------- */
928   EmacsView *view = FRAME_NS_VIEW (f);
929   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
931   ns_update_auto_hide_menu_bar ();
933 #ifdef NS_IMPL_COCOA
934   if ([view isFullscreen] && [view fsIsNative])
935   {
936     // Fix reappearing tool bar in fullscreen for OSX 10.7
937     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
938     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
939     if (! tbar_visible != ! [toolbar isVisible])
940       [toolbar setVisible: tbar_visible];
941   }
942 #endif
944   ns_updating_frame = f;
945   [view lockFocus];
947   /* drawRect may have been called for say the minibuffer, and then clip path
948      is for the minibuffer.  But the display engine may draw more because
949      we have set the frame as garbaged.  So reset clip path to the whole
950      view.  */
951 #ifdef NS_IMPL_COCOA
952   {
953     NSBezierPath *bp;
954     NSRect r = [view frame];
955     NSRect cr = [[view window] frame];
956     /* If a large frame size is set, r may be larger than the window frame
957        before constrained.  In that case don't change the clip path, as we
958        will clear in to the tool bar and title bar.  */
959     if (r.size.height
960         + FRAME_NS_TITLEBAR_HEIGHT (f)
961         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
962       {
963         bp = [[NSBezierPath bezierPathWithRect: r] retain];
964         [bp setClip];
965         [bp release];
966       }
967   }
968 #endif
970 #ifdef NS_IMPL_GNUSTEP
971   uRect = NSMakeRect (0, 0, 0, 0);
972 #endif
976 static void
977 ns_update_window_begin (struct window *w)
978 /* --------------------------------------------------------------------------
979    Prepare for a grouped sequence of drawing calls
980    external (RIF) call; for one window, called after update_begin
981    -------------------------------------------------------------------------- */
983   struct frame *f = XFRAME (WINDOW_FRAME (w));
984   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
986   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
987   w->output_cursor = w->cursor;
989   block_input ();
991   if (f == hlinfo->mouse_face_mouse_frame)
992     {
993       /* Don't do highlighting for mouse motion during the update.  */
994       hlinfo->mouse_face_defer = 1;
996         /* If the frame needs to be redrawn,
997            simply forget about any prior mouse highlighting.  */
998       if (FRAME_GARBAGED_P (f))
999         hlinfo->mouse_face_window = Qnil;
1001       /* (further code for mouse faces ifdef'd out in other terms elided) */
1002     }
1004   unblock_input ();
1008 static void
1009 ns_update_window_end (struct window *w, bool cursor_on_p,
1010                       bool mouse_face_overwritten_p)
1011 /* --------------------------------------------------------------------------
1012    Finished a grouped sequence of drawing calls
1013    external (RIF) call; for one window called before update_end
1014    -------------------------------------------------------------------------- */
1016   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1018   /* note: this fn is nearly identical in all terms */
1019   if (!w->pseudo_window_p)
1020     {
1021       block_input ();
1023       if (cursor_on_p)
1024         display_and_set_cursor (w, 1,
1025                                 w->output_cursor.hpos, w->output_cursor.vpos,
1026                                 w->output_cursor.x, w->output_cursor.y);
1028       if (draw_window_fringes (w, 1))
1029         {
1030           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1031             x_draw_right_divider (w);
1032           else
1033             x_draw_vertical_border (w);
1034         }
1036       unblock_input ();
1037     }
1039   /* If a row with mouse-face was overwritten, arrange for
1040      frame_up_to_date to redisplay the mouse highlight.  */
1041   if (mouse_face_overwritten_p)
1042     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1046 static void
1047 ns_update_end (struct frame *f)
1048 /* --------------------------------------------------------------------------
1049    Finished a grouped sequence of drawing calls
1050    external (RIF) call; for whole frame, called after update_window_end
1051    -------------------------------------------------------------------------- */
1053   EmacsView *view = FRAME_NS_VIEW (f);
1055   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1057 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1058   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1060   block_input ();
1062   [view unlockFocus];
1063   [[view window] flushWindow];
1065   unblock_input ();
1066   ns_updating_frame = NULL;
1069 static void
1070 ns_focus (struct frame *f, NSRect *r, int n)
1071 /* --------------------------------------------------------------------------
1072    Internal: Focus on given frame.  During small local updates this is used to
1073      draw, however during large updates, ns_update_begin and ns_update_end are
1074      called to wrap the whole thing, in which case these calls are stubbed out.
1075      Except, on GNUstep, we accumulate the rectangle being drawn into, because
1076      the back end won't do this automatically, and will just end up flushing
1077      the entire window.
1078    -------------------------------------------------------------------------- */
1080   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1081   if (r != NULL)
1082     {
1083       NSTRACE_RECT ("r", *r);
1084     }
1086   if (f != ns_updating_frame)
1087     {
1088       NSView *view = FRAME_NS_VIEW (f);
1089       if (view != focus_view)
1090         {
1091           if (focus_view != NULL)
1092             {
1093               [focus_view unlockFocus];
1094               [[focus_view window] flushWindow];
1095 /*debug_lock--; */
1096             }
1098           if (view)
1099             [view lockFocus];
1100           focus_view = view;
1101 /*if (view) debug_lock++; */
1102         }
1103     }
1105   /* clipping */
1106   if (r)
1107     {
1108       [[NSGraphicsContext currentContext] saveGraphicsState];
1109       if (n == 2)
1110         NSRectClipList (r, 2);
1111       else
1112         NSRectClip (*r);
1113       gsaved = YES;
1114     }
1118 static void
1119 ns_unfocus (struct frame *f)
1120 /* --------------------------------------------------------------------------
1121      Internal: Remove focus on given frame
1122    -------------------------------------------------------------------------- */
1124   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1126   if (gsaved)
1127     {
1128       [[NSGraphicsContext currentContext] restoreGraphicsState];
1129       gsaved = NO;
1130     }
1132   if (f != ns_updating_frame)
1133     {
1134       if (focus_view != NULL)
1135         {
1136           [focus_view unlockFocus];
1137           [[focus_view window] flushWindow];
1138           focus_view = NULL;
1139 /*debug_lock--; */
1140         }
1141     }
1145 static void
1146 ns_clip_to_row (struct window *w, struct glyph_row *row,
1147                 enum glyph_row_area area, BOOL gc)
1148 /* --------------------------------------------------------------------------
1149      Internal (but parallels other terms): Focus drawing on given row
1150    -------------------------------------------------------------------------- */
1152   struct frame *f = XFRAME (WINDOW_FRAME (w));
1153   NSRect clip_rect;
1154   int window_x, window_y, window_width;
1156   window_box (w, area, &window_x, &window_y, &window_width, 0);
1158   clip_rect.origin.x = window_x;
1159   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1160   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1161   clip_rect.size.width = window_width;
1162   clip_rect.size.height = row->visible_height;
1164   ns_focus (f, &clip_rect, 1);
1168 /* ==========================================================================
1170     Visible bell and beep.
1172    ========================================================================== */
1175 @interface EmacsBell : NSImageView
1177   // Number of currently active bell:s.
1178   unsigned int nestCount;
1179   bool isAttached;
1181 - (void)show:(NSView *)view;
1182 - (void)hide;
1183 - (void)remove;
1184 @end
1186 @implementation EmacsBell
1188 - (id)init;
1190   NSTRACE ("[EmacsBell init]");
1191   if ((self = [super init]))
1192     {
1193       nestCount = 0;
1194       isAttached = false;
1195 #ifdef NS_IMPL_GNUSTEP
1196       // GNUstep doesn't provide named images.  This was reported in
1197       // 2011, see https://savannah.gnu.org/bugs/?33396
1198       //
1199       // As a drop in replacement, a semitransparent gray square is used.
1200       self.image = [[NSImage alloc] initWithSize:NSMakeSize(32, 32)];
1201       [self.image lockFocus];
1202       [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1203       NSRectFill(NSMakeRect(0, 0, 32, 32));
1204       [self.image unlockFocus];
1205 #else
1206       self.image = [NSImage imageNamed:NSImageNameCaution];
1207 #endif
1208     }
1209   return self;
1212 - (void)show:(NSView *)view
1214   NSTRACE ("[EmacsBell show:]");
1215   NSTRACE_MSG ("nestCount: %u", nestCount);
1217   // Show the image, unless it's already shown.
1218   if (nestCount == 0)
1219     {
1220       NSRect rect = [view bounds];
1221       NSPoint pos;
1222       pos.x = rect.origin.x + (rect.size.width  - self.image.size.width )/2;
1223       pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1225       [self setFrameOrigin:pos];
1226       [self setFrameSize:self.image.size];
1228       isAttached = true;
1229       [[[view window] contentView] addSubview:self
1230                                    positioned:NSWindowAbove
1231                                    relativeTo:nil];
1232     }
1234   ++nestCount;
1236   [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1240 - (void)hide
1242   // Note: Trace output from this method isn't shown, reason unknown.
1243   // NSTRACE ("[EmacsBell hide]");
1245   if (nestCount > 0)
1246     --nestCount;
1248   // Remove the image once the last bell became inactive.
1249   if (nestCount == 0)
1250     {
1251       [self remove];
1252     }
1256 -(void)remove
1258   if (isAttached)
1259     {
1260       [self removeFromSuperview];
1261       isAttached = false;
1262     }
1265 @end
1268 static EmacsBell * bell_view = nil;
1270 static void
1271 ns_ring_bell (struct frame *f)
1272 /* --------------------------------------------------------------------------
1273      "Beep" routine
1274    -------------------------------------------------------------------------- */
1276   NSTRACE ("ns_ring_bell");
1277   if (visible_bell)
1278     {
1279       struct frame *frame = SELECTED_FRAME ();
1280       NSView *view;
1282       if (bell_view == nil)
1283         {
1284           bell_view = [[EmacsBell alloc] init];
1285           [bell_view retain];
1286         }
1288       block_input ();
1290       view = FRAME_NS_VIEW (frame);
1291       if (view != nil)
1292         {
1293           [bell_view show:view];
1294         }
1296       unblock_input ();
1297     }
1298   else
1299     {
1300       NSBeep ();
1301     }
1305 static void hide_bell ()
1306 /* --------------------------------------------------------------------------
1307      Ensure the bell is hidden.
1308    -------------------------------------------------------------------------- */
1310   if (bell_view != nil)
1311     {
1312       [bell_view remove];
1313     }
1317 /* ==========================================================================
1319     Frame / window manager related functions
1321    ========================================================================== */
1324 static void
1325 ns_raise_frame (struct frame *f)
1326 /* --------------------------------------------------------------------------
1327      Bring window to foreground and make it active
1328    -------------------------------------------------------------------------- */
1330   NSView *view;
1332   check_window_system (f);
1333   view = FRAME_NS_VIEW (f);
1334   block_input ();
1335   if (FRAME_VISIBLE_P (f))
1336     [[view window] makeKeyAndOrderFront: NSApp];
1337   unblock_input ();
1341 static void
1342 ns_lower_frame (struct frame *f)
1343 /* --------------------------------------------------------------------------
1344      Send window to back
1345    -------------------------------------------------------------------------- */
1347   NSView *view;
1349   check_window_system (f);
1350   view = FRAME_NS_VIEW (f);
1351   block_input ();
1352   [[view window] orderBack: NSApp];
1353   unblock_input ();
1357 static void
1358 ns_frame_raise_lower (struct frame *f, bool raise)
1359 /* --------------------------------------------------------------------------
1360      External (hook)
1361    -------------------------------------------------------------------------- */
1363   NSTRACE ("ns_frame_raise_lower");
1365   if (raise)
1366     ns_raise_frame (f);
1367   else
1368     ns_lower_frame (f);
1372 static void
1373 ns_frame_rehighlight (struct frame *frame)
1374 /* --------------------------------------------------------------------------
1375      External (hook): called on things like window switching within frame
1376    -------------------------------------------------------------------------- */
1378   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1379   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1381   NSTRACE ("ns_frame_rehighlight");
1382   if (dpyinfo->x_focus_frame)
1383     {
1384       dpyinfo->x_highlight_frame
1385         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1386            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1387            : dpyinfo->x_focus_frame);
1388       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1389         {
1390           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1391           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1392         }
1393     }
1394   else
1395       dpyinfo->x_highlight_frame = 0;
1397   if (dpyinfo->x_highlight_frame &&
1398          dpyinfo->x_highlight_frame != old_highlight)
1399     {
1400       if (old_highlight)
1401         {
1402           x_update_cursor (old_highlight, 1);
1403           x_set_frame_alpha (old_highlight);
1404         }
1405       if (dpyinfo->x_highlight_frame)
1406         {
1407           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1408           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1409         }
1410     }
1414 void
1415 x_make_frame_visible (struct frame *f)
1416 /* --------------------------------------------------------------------------
1417      External: Show the window (X11 semantics)
1418    -------------------------------------------------------------------------- */
1420   NSTRACE ("x_make_frame_visible");
1421   /* XXX: at some points in past this was not needed, as the only place that
1422      called this (frame.c:Fraise_frame ()) also called raise_lower;
1423      if this ends up the case again, comment this out again. */
1424   if (!FRAME_VISIBLE_P (f))
1425     {
1426       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1428       SET_FRAME_VISIBLE (f, 1);
1429       ns_raise_frame (f);
1431       /* Making a new frame from a fullscreen frame will make the new frame
1432          fullscreen also.  So skip handleFS as this will print an error.  */
1433       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1434           && [view isFullscreen])
1435         return;
1437       if (f->want_fullscreen != FULLSCREEN_NONE)
1438         {
1439           block_input ();
1440           [view handleFS];
1441           unblock_input ();
1442         }
1443     }
1447 void
1448 x_make_frame_invisible (struct frame *f)
1449 /* --------------------------------------------------------------------------
1450      External: Hide the window (X11 semantics)
1451    -------------------------------------------------------------------------- */
1453   NSView *view;
1454   NSTRACE ("x_make_frame_invisible");
1455   check_window_system (f);
1456   view = FRAME_NS_VIEW (f);
1457   [[view window] orderOut: NSApp];
1458   SET_FRAME_VISIBLE (f, 0);
1459   SET_FRAME_ICONIFIED (f, 0);
1463 void
1464 x_iconify_frame (struct frame *f)
1465 /* --------------------------------------------------------------------------
1466      External: Iconify window
1467    -------------------------------------------------------------------------- */
1469   NSView *view;
1470   struct ns_display_info *dpyinfo;
1472   NSTRACE ("x_iconify_frame");
1473   check_window_system (f);
1474   view = FRAME_NS_VIEW (f);
1475   dpyinfo = FRAME_DISPLAY_INFO (f);
1477   if (dpyinfo->x_highlight_frame == f)
1478     dpyinfo->x_highlight_frame = 0;
1480   if ([[view window] windowNumber] <= 0)
1481     {
1482       /* the window is still deferred.  Make it very small, bring it
1483          on screen and order it out. */
1484       NSRect s = { { 100, 100}, {0, 0} };
1485       NSRect t;
1486       t = [[view window] frame];
1487       [[view window] setFrame: s display: NO];
1488       [[view window] orderBack: NSApp];
1489       [[view window] orderOut: NSApp];
1490       [[view window] setFrame: t display: NO];
1491     }
1492   [[view window] miniaturize: NSApp];
1495 /* Free X resources of frame F.  */
1497 void
1498 x_free_frame_resources (struct frame *f)
1500   NSView *view;
1501   struct ns_display_info *dpyinfo;
1502   Mouse_HLInfo *hlinfo;
1504   NSTRACE ("x_free_frame_resources");
1505   check_window_system (f);
1506   view = FRAME_NS_VIEW (f);
1507   dpyinfo = FRAME_DISPLAY_INFO (f);
1508   hlinfo = MOUSE_HL_INFO (f);
1510   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1512   block_input ();
1514   free_frame_menubar (f);
1515   free_frame_faces (f);
1517   if (f == dpyinfo->x_focus_frame)
1518     dpyinfo->x_focus_frame = 0;
1519   if (f == dpyinfo->x_highlight_frame)
1520     dpyinfo->x_highlight_frame = 0;
1521   if (f == hlinfo->mouse_face_mouse_frame)
1522     reset_mouse_highlight (hlinfo);
1524   if (f->output_data.ns->miniimage != nil)
1525     [f->output_data.ns->miniimage release];
1527   [[view window] close];
1528   [view release];
1530   xfree (f->output_data.ns);
1532   unblock_input ();
1535 void
1536 x_destroy_window (struct frame *f)
1537 /* --------------------------------------------------------------------------
1538      External: Delete the window
1539    -------------------------------------------------------------------------- */
1541   NSTRACE ("x_destroy_window");
1542   check_window_system (f);
1543   x_free_frame_resources (f);
1544   ns_window_num--;
1548 void
1549 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1550 /* --------------------------------------------------------------------------
1551      External: Position the window
1552    -------------------------------------------------------------------------- */
1554   NSView *view = FRAME_NS_VIEW (f);
1555   NSArray *screens = [NSScreen screens];
1556   NSScreen *fscreen = [screens objectAtIndex: 0];
1557   NSScreen *screen = [[view window] screen];
1559   NSTRACE ("x_set_offset");
1561   block_input ();
1563   f->left_pos = xoff;
1564   f->top_pos = yoff;
1566   if (view != nil && screen && fscreen)
1567     {
1568       f->left_pos = f->size_hint_flags & XNegative
1569         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1570         : f->left_pos;
1571       /* We use visibleFrame here to take menu bar into account.
1572          Ideally we should also adjust left/top with visibleFrame.origin.  */
1574       f->top_pos = f->size_hint_flags & YNegative
1575         ? ([screen visibleFrame].size.height + f->top_pos
1576            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1577            - FRAME_TOOLBAR_HEIGHT (f))
1578         : f->top_pos;
1579 #ifdef NS_IMPL_GNUSTEP
1580       if (f->left_pos < 100)
1581         f->left_pos = 100;  /* don't overlap menu */
1582 #endif
1583       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1584          menu bar.  */
1585       NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos),
1586                                 SCREENMAXBOUND ([fscreen frame].size.height
1587                                                 - NS_TOP_POS (f)));
1588       NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1589       [[view window] setFrameTopLeftPoint: pt];
1590       f->size_hint_flags &= ~(XNegative|YNegative);
1591     }
1593   unblock_input ();
1597 void
1598 x_set_window_size (struct frame *f,
1599                    bool change_gravity,
1600                    int width,
1601                    int height,
1602                    bool pixelwise)
1603 /* --------------------------------------------------------------------------
1604      Adjust window pixel size based on given character grid size
1605      Impl is a bit more complex than other terms, need to do some
1606      internal clipping.
1607    -------------------------------------------------------------------------- */
1609   EmacsView *view = FRAME_NS_VIEW (f);
1610   NSWindow *window = [view window];
1611   NSRect wr = [window frame];
1612   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1613   int pixelwidth, pixelheight;
1614   int orig_height = wr.size.height;
1616   NSTRACE ("x_set_window_size");
1618   if (view == nil)
1619     return;
1621   NSTRACE_RECT ("current", wr);
1622   NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1623   NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1625   block_input ();
1627   if (pixelwise)
1628     {
1629       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1630       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1631     }
1632   else
1633     {
1634       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1635       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1636     }
1638   /* If we have a toolbar, take its height into account. */
1639   if (tb && ! [view isFullscreen])
1640     {
1641     /* NOTE: previously this would generate wrong result if toolbar not
1642              yet displayed and fixing toolbar_height=32 helped, but
1643              now (200903) seems no longer needed */
1644     FRAME_TOOLBAR_HEIGHT (f) =
1645       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1646         - FRAME_NS_TITLEBAR_HEIGHT (f);
1647 #if 0
1648       /* Only breaks things here, removed by martin 2015-09-30.  */
1649 #ifdef NS_IMPL_GNUSTEP
1650       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1651 #endif
1652 #endif
1653     }
1654   else
1655     FRAME_TOOLBAR_HEIGHT (f) = 0;
1657   wr.size.width = pixelwidth + f->border_width;
1658   wr.size.height = pixelheight;
1659   if (! [view isFullscreen])
1660     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1661       + FRAME_TOOLBAR_HEIGHT (f);
1663   /* Do not try to constrain to this screen.  We may have multiple
1664      screens, and want Emacs to span those.  Constraining to screen
1665      prevents that, and that is not nice to the user.  */
1666  if (f->output_data.ns->zooming)
1667    f->output_data.ns->zooming = 0;
1668  else
1669    wr.origin.y += orig_height - wr.size.height;
1671  frame_size_history_add
1672    (f, Qx_set_window_size_1, width, height,
1673     list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1674            Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1675            make_number (f->border_width),
1676            make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1677            make_number (FRAME_TOOLBAR_HEIGHT (f))));
1679   [window setFrame: wr display: YES];
1681   /* This is a trick to compensate for Emacs' managing the scrollbar area
1682      as a fixed number of standard character columns.  Instead of leaving
1683      blank space for the extra, we chopped it off above.  Now for
1684      left-hand scrollbars, we shift all rendering to the left by the
1685      difference between the real width and Emacs' imagined one.  For
1686      right-hand bars, don't worry about it since the extra is never used.
1687      (Obviously doesn't work for vertically split windows tho..) */
1688   {
1689     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1690       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1691                      - NS_SCROLL_BAR_WIDTH (f), 0)
1692       : NSMakePoint (0, 0);
1694     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1695     [view setBoundsOrigin: origin];
1696   }
1698   [view updateFrameSize: NO];
1699   unblock_input ();
1703 static void
1704 ns_fullscreen_hook (struct frame *f)
1706   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1708   NSTRACE ("ns_fullscreen_hook");
1710   if (!FRAME_VISIBLE_P (f))
1711     return;
1713    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1714     {
1715       /* Old style fs don't initiate correctly if created from
1716          init/default-frame alist, so use a timer (not nice...).
1717       */
1718       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1719                                      selector: @selector (handleFS)
1720                                      userInfo: nil repeats: NO];
1721       return;
1722     }
1724   block_input ();
1725   [view handleFS];
1726   unblock_input ();
1729 /* ==========================================================================
1731     Color management
1733    ========================================================================== */
1736 NSColor *
1737 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1739   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1740   if (idx < 1 || idx >= color_table->avail)
1741     return nil;
1742   return color_table->colors[idx];
1746 unsigned long
1747 ns_index_color (NSColor *color, struct frame *f)
1749   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1750   ptrdiff_t idx;
1751   ptrdiff_t i;
1753   if (!color_table->colors)
1754     {
1755       color_table->size = NS_COLOR_CAPACITY;
1756       color_table->avail = 1; /* skip idx=0 as marker */
1757       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1758       color_table->colors[0] = nil;
1759       color_table->empty_indices = [[NSMutableSet alloc] init];
1760     }
1762   /* Do we already have this color?  */
1763   for (i = 1; i < color_table->avail; i++)
1764     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1765       return i;
1767   if ([color_table->empty_indices count] > 0)
1768     {
1769       NSNumber *index = [color_table->empty_indices anyObject];
1770       [color_table->empty_indices removeObject: index];
1771       idx = [index unsignedLongValue];
1772     }
1773   else
1774     {
1775       if (color_table->avail == color_table->size)
1776         color_table->colors =
1777           xpalloc (color_table->colors, &color_table->size, 1,
1778                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1779       idx = color_table->avail++;
1780     }
1782   color_table->colors[idx] = color;
1783   [color retain];
1784 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1785   return idx;
1789 void
1790 ns_free_indexed_color (unsigned long idx, struct frame *f)
1792   struct ns_color_table *color_table;
1793   NSColor *color;
1794   NSNumber *index;
1796   if (!f)
1797     return;
1799   color_table = FRAME_DISPLAY_INFO (f)->color_table;
1801   if (idx <= 0 || idx >= color_table->size) {
1802     message1 ("ns_free_indexed_color: Color index out of range.\n");
1803     return;
1804   }
1806   index = [NSNumber numberWithUnsignedInt: idx];
1807   if ([color_table->empty_indices containsObject: index]) {
1808     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1809     return;
1810   }
1812   color = color_table->colors[idx];
1813   [color release];
1814   color_table->colors[idx] = nil;
1815   [color_table->empty_indices addObject: index];
1816 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1820 static int
1821 ns_get_color (const char *name, NSColor **col)
1822 /* --------------------------------------------------------------------------
1823      Parse a color name
1824    -------------------------------------------------------------------------- */
1825 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1826    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1827    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1829   NSColor *new = nil;
1830   static char hex[20];
1831   int scaling = 0;
1832   float r = -1.0, g, b;
1833   NSString *nsname = [NSString stringWithUTF8String: name];
1835   NSTRACE ("ns_get_color(%s, **)", name);
1837   block_input ();
1839   if ([nsname isEqualToString: @"ns_selection_bg_color"])
1840     {
1841 #ifdef NS_IMPL_COCOA
1842       NSString *defname = [[NSUserDefaults standardUserDefaults]
1843                             stringForKey: @"AppleHighlightColor"];
1844       if (defname != nil)
1845         nsname = defname;
1846       else
1847 #endif
1848       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1849         {
1850           *col = [new colorUsingDefaultColorSpace];
1851           unblock_input ();
1852           return 0;
1853         }
1854       else
1855         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1857       name = [nsname UTF8String];
1858     }
1859   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1860     {
1861       /* NOTE: OSX applications normally don't set foreground selection, but
1862          text may be unreadable if we don't.
1863       */
1864       if ((new = [NSColor selectedTextColor]) != nil)
1865         {
1866           *col = [new colorUsingDefaultColorSpace];
1867           unblock_input ();
1868           return 0;
1869         }
1871       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1872       name = [nsname UTF8String];
1873     }
1875   /* First, check for some sort of numeric specification. */
1876   hex[0] = '\0';
1878   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1879     {
1880       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1881       [scanner scanFloat: &r];
1882       [scanner scanFloat: &g];
1883       [scanner scanFloat: &b];
1884     }
1885   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1886     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1887   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1888     {
1889       int len = (strlen(name) - 1);
1890       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1891       int i;
1892       scaling = strlen(name+start) / 3;
1893       for (i = 0; i < 3; i++)
1894         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1895                  name + start + i * scaling);
1896       hex[3 * (scaling + 1) - 1] = '\0';
1897     }
1899   if (hex[0])
1900     {
1901       int rr, gg, bb;
1902       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1903       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1904         {
1905           r = rr / fscale;
1906           g = gg / fscale;
1907           b = bb / fscale;
1908         }
1909     }
1911   if (r >= 0.0F)
1912     {
1913       *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
1914       unblock_input ();
1915       return 0;
1916     }
1918   /* Otherwise, color is expected to be from a list */
1919   {
1920     NSEnumerator *lenum, *cenum;
1921     NSString *name;
1922     NSColorList *clist;
1924 #ifdef NS_IMPL_GNUSTEP
1925     /* XXX: who is wrong, the requestor or the implementation? */
1926     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1927         == NSOrderedSame)
1928       nsname = @"highlightColor";
1929 #endif
1931     lenum = [[NSColorList availableColorLists] objectEnumerator];
1932     while ( (clist = [lenum nextObject]) && new == nil)
1933       {
1934         cenum = [[clist allKeys] objectEnumerator];
1935         while ( (name = [cenum nextObject]) && new == nil )
1936           {
1937             if ([name compare: nsname
1938                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1939               new = [clist colorWithKey: name];
1940           }
1941       }
1942   }
1944   if (new)
1945     *col = [new colorUsingDefaultColorSpace];
1946   unblock_input ();
1947   return new ? 0 : 1;
1952 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1953 /* --------------------------------------------------------------------------
1954      Convert a Lisp string object to a NS color
1955    -------------------------------------------------------------------------- */
1957   NSTRACE ("ns_lisp_to_color");
1958   if (STRINGP (color))
1959     return ns_get_color (SSDATA (color), col);
1960   else if (SYMBOLP (color))
1961     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1962   return 1;
1966 Lisp_Object
1967 ns_color_to_lisp (NSColor *col)
1968 /* --------------------------------------------------------------------------
1969      Convert a color to a lisp string with the RGB equivalent
1970    -------------------------------------------------------------------------- */
1972   EmacsCGFloat red, green, blue, alpha, gray;
1973   char buf[1024];
1974   const char *str;
1975   NSTRACE ("ns_color_to_lisp");
1977   block_input ();
1978   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1980       if ((str =[[col colorNameComponent] UTF8String]))
1981         {
1982           unblock_input ();
1983           return build_string ((char *)str);
1984         }
1986     [[col colorUsingDefaultColorSpace]
1987         getRed: &red green: &green blue: &blue alpha: &alpha];
1988   if (red == green && red == blue)
1989     {
1990       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1991             getWhite: &gray alpha: &alpha];
1992       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1993                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1994       unblock_input ();
1995       return build_string (buf);
1996     }
1998   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1999             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
2001   unblock_input ();
2002   return build_string (buf);
2006 void
2007 ns_query_color(void *col, XColor *color_def, int setPixel)
2008 /* --------------------------------------------------------------------------
2009          Get ARGB values out of NSColor col and put them into color_def.
2010          If setPixel, set the pixel to a concatenated version.
2011          and set color_def pixel to the resulting index.
2012    -------------------------------------------------------------------------- */
2014   EmacsCGFloat r, g, b, a;
2016   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2017   color_def->red   = r * 65535;
2018   color_def->green = g * 65535;
2019   color_def->blue  = b * 65535;
2021   if (setPixel == YES)
2022     color_def->pixel
2023       = ARGB_TO_ULONG((int)(a*255),
2024                       (int)(r*255), (int)(g*255), (int)(b*255));
2028 bool
2029 ns_defined_color (struct frame *f,
2030                   const char *name,
2031                   XColor *color_def,
2032                   bool alloc,
2033                   bool makeIndex)
2034 /* --------------------------------------------------------------------------
2035          Return true if named color found, and set color_def rgb accordingly.
2036          If makeIndex and alloc are nonzero put the color in the color_table,
2037          and set color_def pixel to the resulting index.
2038          If makeIndex is zero, set color_def pixel to ARGB.
2039          Return false if not found
2040    -------------------------------------------------------------------------- */
2042   NSColor *col;
2043   NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2045   block_input ();
2046   if (ns_get_color (name, &col) != 0) /* Color not found  */
2047     {
2048       unblock_input ();
2049       return 0;
2050     }
2051   if (makeIndex && alloc)
2052     color_def->pixel = ns_index_color (col, f);
2053   ns_query_color (col, color_def, !makeIndex);
2054   unblock_input ();
2055   return 1;
2059 void
2060 x_set_frame_alpha (struct frame *f)
2061 /* --------------------------------------------------------------------------
2062      change the entire-frame transparency
2063    -------------------------------------------------------------------------- */
2065   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2066   double alpha = 1.0;
2067   double alpha_min = 1.0;
2069   NSTRACE ("x_set_frame_alpha");
2071   if (dpyinfo->x_highlight_frame == f)
2072     alpha = f->alpha[0];
2073   else
2074     alpha = f->alpha[1];
2076   if (FLOATP (Vframe_alpha_lower_limit))
2077     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2078   else if (INTEGERP (Vframe_alpha_lower_limit))
2079     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2081   if (alpha < 0.0)
2082     return;
2083   else if (1.0 < alpha)
2084     alpha = 1.0;
2085   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2086     alpha = alpha_min;
2088 #ifdef NS_IMPL_COCOA
2089   {
2090     EmacsView *view = FRAME_NS_VIEW (f);
2091   [[view window] setAlphaValue: alpha];
2092   }
2093 #endif
2097 /* ==========================================================================
2099     Mouse handling
2101    ========================================================================== */
2104 void
2105 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2106 /* --------------------------------------------------------------------------
2107      Programmatically reposition mouse pointer in pixel coordinates
2108    -------------------------------------------------------------------------- */
2110   NSTRACE ("frame_set_mouse_pixel_position");
2111   ns_raise_frame (f);
2112 #if 0
2113   /* FIXME: this does not work, and what about GNUstep? */
2114 #ifdef NS_IMPL_COCOA
2115   [FRAME_NS_VIEW (f) lockFocus];
2116   PSsetmouse ((float)pix_x, (float)pix_y);
2117   [FRAME_NS_VIEW (f) unlockFocus];
2118 #endif
2119 #endif
2122 static int
2123 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2124 /*   ------------------------------------------------------------------------
2125      Called by EmacsView on mouseMovement events.  Passes on
2126      to emacs mainstream code if we moved off of a rect of interest
2127      known as last_mouse_glyph.
2128      ------------------------------------------------------------------------ */
2130   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2131   NSRect *r;
2133 //  NSTRACE ("note_mouse_movement");
2135   dpyinfo->last_mouse_motion_frame = frame;
2136   r = &dpyinfo->last_mouse_glyph;
2138   /* Note, this doesn't get called for enter/leave, since we don't have a
2139      position.  Those are taken care of in the corresponding NSView methods. */
2141   /* has movement gone beyond last rect we were tracking? */
2142   if (x < r->origin.x || x >= r->origin.x + r->size.width
2143       || y < r->origin.y || y >= r->origin.y + r->size.height)
2144     {
2145       ns_update_begin (frame);
2146       frame->mouse_moved = 1;
2147       note_mouse_highlight (frame, x, y);
2148       remember_mouse_glyph (frame, x, y, r);
2149       ns_update_end (frame);
2150       return 1;
2151     }
2153   return 0;
2157 static void
2158 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2159                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2160                    Time *time)
2161 /* --------------------------------------------------------------------------
2162     External (hook): inform emacs about mouse position and hit parts.
2163     If a scrollbar is being dragged, set bar_window, part, x, y, time.
2164     x & y should be position in the scrollbar (the whole bar, not the handle)
2165     and length of scrollbar respectively
2166    -------------------------------------------------------------------------- */
2168   id view;
2169   NSPoint position;
2170   Lisp_Object frame, tail;
2171   struct frame *f;
2172   struct ns_display_info *dpyinfo;
2174   NSTRACE ("ns_mouse_position");
2176   if (*fp == NULL)
2177     {
2178       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2179       return;
2180     }
2182   dpyinfo = FRAME_DISPLAY_INFO (*fp);
2184   block_input ();
2186   /* Clear the mouse-moved flag for every frame on this display.  */
2187   FOR_EACH_FRAME (tail, frame)
2188     if (FRAME_NS_P (XFRAME (frame))
2189         && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2190       XFRAME (frame)->mouse_moved = 0;
2192   dpyinfo->last_mouse_scroll_bar = nil;
2193   if (dpyinfo->last_mouse_frame
2194       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2195     f = dpyinfo->last_mouse_frame;
2196   else
2197     f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2199   if (f && FRAME_NS_P (f))
2200     {
2201       view = FRAME_NS_VIEW (*fp);
2203       position = [[view window] mouseLocationOutsideOfEventStream];
2204       position = [view convertPoint: position fromView: nil];
2205       remember_mouse_glyph (f, position.x, position.y,
2206                             &dpyinfo->last_mouse_glyph);
2207       NSTRACE_POINT ("position", position);
2209       if (bar_window) *bar_window = Qnil;
2210       if (part) *part = scroll_bar_above_handle;
2212       if (x) XSETINT (*x, lrint (position.x));
2213       if (y) XSETINT (*y, lrint (position.y));
2214       if (time)
2215         *time = dpyinfo->last_mouse_movement_time;
2216       *fp = f;
2217     }
2219   unblock_input ();
2223 static void
2224 ns_frame_up_to_date (struct frame *f)
2225 /* --------------------------------------------------------------------------
2226     External (hook): Fix up mouse highlighting right after a full update.
2227     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2228    -------------------------------------------------------------------------- */
2230   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2232   if (FRAME_NS_P (f))
2233     {
2234       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2235       if (f == hlinfo->mouse_face_mouse_frame)
2236         {
2237           block_input ();
2238           ns_update_begin(f);
2239           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2240                                 hlinfo->mouse_face_mouse_x,
2241                                 hlinfo->mouse_face_mouse_y);
2242           ns_update_end(f);
2243           unblock_input ();
2244         }
2245     }
2249 static void
2250 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2251 /* --------------------------------------------------------------------------
2252     External (RIF): set frame mouse pointer type.
2253    -------------------------------------------------------------------------- */
2255   NSTRACE ("ns_define_frame_cursor");
2256   if (FRAME_POINTER_TYPE (f) != cursor)
2257     {
2258       EmacsView *view = FRAME_NS_VIEW (f);
2259       FRAME_POINTER_TYPE (f) = cursor;
2260       [[view window] invalidateCursorRectsForView: view];
2261       /* Redisplay assumes this function also draws the changed frame
2262          cursor, but this function doesn't, so do it explicitly.  */
2263       x_update_cursor (f, 1);
2264     }
2269 /* ==========================================================================
2271     Keyboard handling
2273    ========================================================================== */
2276 static unsigned
2277 ns_convert_key (unsigned code)
2278 /* --------------------------------------------------------------------------
2279     Internal call used by NSView-keyDown.
2280    -------------------------------------------------------------------------- */
2282   const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2283   unsigned keysym;
2284   /* An array would be faster, but less easy to read. */
2285   for (keysym = 0; keysym < last_keysym; keysym += 2)
2286     if (code == convert_ns_to_X_keysym[keysym])
2287       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2288   return 0;
2289 /* if decide to use keyCode and Carbon table, use this line:
2290      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2294 char *
2295 x_get_keysym_name (int keysym)
2296 /* --------------------------------------------------------------------------
2297     Called by keyboard.c.  Not sure if the return val is important, except
2298     that it be unique.
2299    -------------------------------------------------------------------------- */
2301   static char value[16];
2302   NSTRACE ("x_get_keysym_name");
2303   sprintf (value, "%d", keysym);
2304   return value;
2309 /* ==========================================================================
2311     Block drawing operations
2313    ========================================================================== */
2316 static void
2317 ns_redraw_scroll_bars (struct frame *f)
2319   int i;
2320   id view;
2321   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2322   NSTRACE ("ns_redraw_scroll_bars");
2323   for (i =[subviews count]-1; i >= 0; i--)
2324     {
2325       view = [subviews objectAtIndex: i];
2326       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2327       [view display];
2328     }
2332 void
2333 ns_clear_frame (struct frame *f)
2334 /* --------------------------------------------------------------------------
2335       External (hook): Erase the entire frame
2336    -------------------------------------------------------------------------- */
2338   NSView *view = FRAME_NS_VIEW (f);
2339   NSRect r;
2341   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2343  /* comes on initial frame because we have
2344     after-make-frame-functions = select-frame */
2345  if (!FRAME_DEFAULT_FACE (f))
2346    return;
2348   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2350   r = [view bounds];
2352   block_input ();
2353   ns_focus (f, &r, 1);
2354   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2355   NSRectFill (r);
2356   ns_unfocus (f);
2358   /* as of 2006/11 or so this is now needed */
2359   ns_redraw_scroll_bars (f);
2360   unblock_input ();
2364 static void
2365 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2366 /* --------------------------------------------------------------------------
2367     External (RIF):  Clear section of frame
2368    -------------------------------------------------------------------------- */
2370   NSRect r = NSMakeRect (x, y, width, height);
2371   NSView *view = FRAME_NS_VIEW (f);
2372   struct face *face = FRAME_DEFAULT_FACE (f);
2374   if (!view || !face)
2375     return;
2377   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2379   r = NSIntersectionRect (r, [view frame]);
2380   ns_focus (f, &r, 1);
2381   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2383   NSRectFill (r);
2385   ns_unfocus (f);
2386   return;
2389 static void
2390 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2392   if (FRAME_NS_VIEW (f))
2393     {
2394       hide_bell();              // Ensure the bell image isn't scrolled.
2396       ns_focus (f, &dest, 1);
2397       [FRAME_NS_VIEW (f) scrollRect: src
2398                                  by: NSMakeSize (dest.origin.x - src.origin.x,
2399                                                  dest.origin.y - src.origin.y)];
2400       ns_unfocus (f);
2401     }
2404 static void
2405 ns_scroll_run (struct window *w, struct run *run)
2406 /* --------------------------------------------------------------------------
2407     External (RIF):  Insert or delete n lines at line vpos
2408    -------------------------------------------------------------------------- */
2410   struct frame *f = XFRAME (w->frame);
2411   int x, y, width, height, from_y, to_y, bottom_y;
2413   NSTRACE ("ns_scroll_run");
2415   /* begin copy from other terms */
2416   /* Get frame-relative bounding box of the text display area of W,
2417      without mode lines.  Include in this box the left and right
2418      fringe of W.  */
2419   window_box (w, ANY_AREA, &x, &y, &width, &height);
2421   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2422   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2423   bottom_y = y + height;
2425   if (to_y < from_y)
2426     {
2427       /* Scrolling up.  Make sure we don't copy part of the mode
2428          line at the bottom.  */
2429       if (from_y + run->height > bottom_y)
2430         height = bottom_y - from_y;
2431       else
2432         height = run->height;
2433     }
2434   else
2435     {
2436       /* Scrolling down.  Make sure we don't copy over the mode line.
2437          at the bottom.  */
2438       if (to_y + run->height > bottom_y)
2439         height = bottom_y - to_y;
2440       else
2441         height = run->height;
2442     }
2443   /* end copy from other terms */
2445   if (height == 0)
2446       return;
2448   block_input ();
2450   x_clear_cursor (w);
2452   {
2453     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2454     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2456     ns_copy_bits (f, srcRect , dstRect);
2457   }
2459   unblock_input ();
2463 static void
2464 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2465 /* --------------------------------------------------------------------------
2466     External (RIF): preparatory to fringe update after text was updated
2467    -------------------------------------------------------------------------- */
2469   struct frame *f;
2470   int width, height;
2472   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2474   /* begin copy from other terms */
2475   eassert (w);
2477   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2478     desired_row->redraw_fringe_bitmaps_p = 1;
2480   /* When a window has disappeared, make sure that no rest of
2481      full-width rows stays visible in the internal border.  */
2482   if (windows_or_buffers_changed
2483       && desired_row->full_width_p
2484       && (f = XFRAME (w->frame),
2485           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2486           width != 0)
2487       && (height = desired_row->visible_height,
2488           height > 0))
2489     {
2490       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2492       block_input ();
2493       ns_clear_frame_area (f, 0, y, width, height);
2494       ns_clear_frame_area (f,
2495                            FRAME_PIXEL_WIDTH (f) - width,
2496                            y, width, height);
2497       unblock_input ();
2498     }
2502 static void
2503 ns_shift_glyphs_for_insert (struct frame *f,
2504                            int x, int y, int width, int height,
2505                            int shift_by)
2506 /* --------------------------------------------------------------------------
2507     External (RIF): copy an area horizontally, don't worry about clearing src
2508    -------------------------------------------------------------------------- */
2510   NSRect srcRect = NSMakeRect (x, y, width, height);
2511   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2513   NSTRACE ("ns_shift_glyphs_for_insert");
2515   ns_copy_bits (f, srcRect, dstRect);
2520 /* ==========================================================================
2522     Character encoding and metrics
2524    ========================================================================== */
2527 static void
2528 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2529 /* --------------------------------------------------------------------------
2530      External (RIF); compute left/right overhang of whole string and set in s
2531    -------------------------------------------------------------------------- */
2533   struct font *font = s->font;
2535   if (s->char2b)
2536     {
2537       struct font_metrics metrics;
2538       unsigned int codes[2];
2539       codes[0] = *(s->char2b);
2540       codes[1] = *(s->char2b + s->nchars - 1);
2542       font->driver->text_extents (font, codes, 2, &metrics);
2543       s->left_overhang = -metrics.lbearing;
2544       s->right_overhang
2545         = metrics.rbearing > metrics.width
2546         ? metrics.rbearing - metrics.width : 0;
2547     }
2548   else
2549     {
2550       s->left_overhang = 0;
2551       if (EQ (font->driver->type, Qns))
2552         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2553           FONT_HEIGHT (font) * 0.2 : 0;
2554       else
2555         s->right_overhang = 0;
2556     }
2561 /* ==========================================================================
2563     Fringe and cursor drawing
2565    ========================================================================== */
2568 extern int max_used_fringe_bitmap;
2569 static void
2570 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2571                       struct draw_fringe_bitmap_params *p)
2572 /* --------------------------------------------------------------------------
2573     External (RIF); fringe-related
2574    -------------------------------------------------------------------------- */
2576   /* Fringe bitmaps comes in two variants, normal and periodic.  A
2577      periodic bitmap is used to create a continuous pattern.  Since a
2578      bitmap is rendered one text line at a time, the start offset (dh)
2579      of the bitmap varies.  Concretely, this is used for the empty
2580      line indicator.
2582      For a bitmap, "h + dh" is the full height and is always
2583      invariant.  For a normal bitmap "dh" is zero.
2585      For example, when the period is three and the full height is 72
2586      the following combinations exists:
2588        h=72 dh=0
2589        h=71 dh=1
2590        h=70 dh=2 */
2592   struct frame *f = XFRAME (WINDOW_FRAME (w));
2593   struct face *face = p->face;
2594   static EmacsImage **bimgs = NULL;
2595   static int nBimgs = 0;
2597   NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2598   NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2599                p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2601   /* grow bimgs if needed */
2602   if (nBimgs < max_used_fringe_bitmap)
2603     {
2604       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2605       memset (bimgs + nBimgs, 0,
2606               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2607       nBimgs = max_used_fringe_bitmap;
2608     }
2610   /* Must clip because of partially visible lines.  */
2611   ns_clip_to_row (w, row, ANY_AREA, YES);
2613   if (!p->overlay_p)
2614     {
2615       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2617       if (bx >= 0 && nx > 0)
2618         {
2619           NSRect r = NSMakeRect (bx, by, nx, ny);
2620           NSRectClip (r);
2621           [ns_lookup_indexed_color (face->background, f) set];
2622           NSRectFill (r);
2623         }
2624     }
2626   if (p->which)
2627     {
2628       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2629       EmacsImage *img = bimgs[p->which - 1];
2631       if (!img)
2632         {
2633           // Note: For "periodic" images, allocate one EmacsImage for
2634           // the base image, and use it for all dh:s.
2635           unsigned short *bits = p->bits;
2636           int full_height = p->h + p->dh;
2637           int i;
2638           unsigned char *cbits = xmalloc (full_height);
2640           for (i = 0; i < full_height; i++)
2641             cbits[i] = bits[i];
2642           img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2643                                          height: full_height
2644                                              fg: 0 bg: 0];
2645           bimgs[p->which - 1] = img;
2646           xfree (cbits);
2647         }
2649       NSTRACE_RECT ("r", r);
2651       NSRectClip (r);
2652       /* Since we composite the bitmap instead of just blitting it, we need
2653          to erase the whole background. */
2654       [ns_lookup_indexed_color(face->background, f) set];
2655       NSRectFill (r);
2657       {
2658         NSColor *bm_color;
2659         if (!p->cursor_p)
2660           bm_color = ns_lookup_indexed_color(face->foreground, f);
2661         else if (p->overlay_p)
2662           bm_color = ns_lookup_indexed_color(face->background, f);
2663         else
2664           bm_color = f->output_data.ns->cursor_color;
2665         [img setXBMColor: bm_color];
2666       }
2668 #ifdef NS_IMPL_COCOA
2669       // Note: For periodic images, the full image height is "h + hd".
2670       // By using the height h, a suitable part of the image is used.
2671       NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2673       NSTRACE_RECT ("fromRect", fromRect);
2675       [img drawInRect: r
2676               fromRect: fromRect
2677              operation: NSCompositeSourceOver
2678               fraction: 1.0
2679            respectFlipped: YES
2680                 hints: nil];
2681 #else
2682       {
2683         NSPoint pt = r.origin;
2684         pt.y += p->h;
2685         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2686       }
2687 #endif
2688     }
2689   ns_unfocus (f);
2693 static void
2694 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2695                        int x, int y, enum text_cursor_kinds cursor_type,
2696                        int cursor_width, bool on_p, bool active_p)
2697 /* --------------------------------------------------------------------------
2698      External call (RIF): draw cursor.
2699      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2700    -------------------------------------------------------------------------- */
2702   NSRect r, s;
2703   int fx, fy, h, cursor_height;
2704   struct frame *f = WINDOW_XFRAME (w);
2705   struct glyph *phys_cursor_glyph;
2706   struct glyph *cursor_glyph;
2707   struct face *face;
2708   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2710   /* If cursor is out of bounds, don't draw garbage.  This can happen
2711      in mini-buffer windows when switching between echo area glyphs
2712      and mini-buffer.  */
2714   NSTRACE ("ns_draw_window_cursor");
2716   if (!on_p)
2717     return;
2719   w->phys_cursor_type = cursor_type;
2720   w->phys_cursor_on_p = on_p;
2722   if (cursor_type == NO_CURSOR)
2723     {
2724       w->phys_cursor_width = 0;
2725       return;
2726     }
2728   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2729     {
2730       if (glyph_row->exact_window_width_line_p
2731           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2732         {
2733           glyph_row->cursor_in_fringe_p = 1;
2734           draw_fringe_bitmap (w, glyph_row, 0);
2735         }
2736       return;
2737     }
2739   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2740      (other terminals do it the other way round).  We must set
2741      w->phys_cursor_width to the cursor width.  For bar cursors, that
2742      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2743   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2745   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2746      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2747   if (cursor_type == BAR_CURSOR)
2748     {
2749       if (cursor_width < 1)
2750         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2751       w->phys_cursor_width = cursor_width;
2752     }
2753   /* If we have an HBAR, "cursor_width" MAY specify height. */
2754   else if (cursor_type == HBAR_CURSOR)
2755     {
2756       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2757       if (cursor_height > glyph_row->height)
2758         cursor_height = glyph_row->height;
2759       if (h > cursor_height) // Cursor smaller than line height, move down
2760         fy += h - cursor_height;
2761       h = cursor_height;
2762     }
2764   r.origin.x = fx, r.origin.y = fy;
2765   r.size.height = h;
2766   r.size.width = w->phys_cursor_width;
2768   /* TODO: only needed in rare cases with last-resort font in HELLO..
2769      should we do this more efficiently? */
2770   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2773   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2774   if (face && NS_FACE_BACKGROUND (face)
2775       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2776     {
2777       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2778       hollow_color = FRAME_CURSOR_COLOR (f);
2779     }
2780   else
2781     [FRAME_CURSOR_COLOR (f) set];
2783 #ifdef NS_IMPL_COCOA
2784   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2785            atomic.  Cleaner ways of doing this should be investigated.
2786            One way would be to set a global variable DRAWING_CURSOR
2787            when making the call to draw_phys..(), don't focus in that
2788            case, then move the ns_unfocus() here after that call. */
2789   NSDisableScreenUpdates ();
2790 #endif
2792   switch (cursor_type)
2793     {
2794     case DEFAULT_CURSOR:
2795     case NO_CURSOR:
2796       break;
2797     case FILLED_BOX_CURSOR:
2798       NSRectFill (r);
2799       break;
2800     case HOLLOW_BOX_CURSOR:
2801       NSRectFill (r);
2802       [hollow_color set];
2803       NSRectFill (NSInsetRect (r, 1, 1));
2804       [FRAME_CURSOR_COLOR (f) set];
2805       break;
2806     case HBAR_CURSOR:
2807       NSRectFill (r);
2808       break;
2809     case BAR_CURSOR:
2810       s = r;
2811       /* If the character under cursor is R2L, draw the bar cursor
2812          on the right of its glyph, rather than on the left.  */
2813       cursor_glyph = get_phys_cursor_glyph (w);
2814       if ((cursor_glyph->resolved_level & 1) != 0)
2815         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2817       NSRectFill (s);
2818       break;
2819     }
2820   ns_unfocus (f);
2822   /* draw the character under the cursor */
2823   if (cursor_type != NO_CURSOR)
2824     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2826 #ifdef NS_IMPL_COCOA
2827   NSEnableScreenUpdates ();
2828 #endif
2833 static void
2834 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2835 /* --------------------------------------------------------------------------
2836      External (RIF): Draw a vertical line.
2837    -------------------------------------------------------------------------- */
2839   struct frame *f = XFRAME (WINDOW_FRAME (w));
2840   struct face *face;
2841   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2843   NSTRACE ("ns_draw_vertical_window_border");
2845   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2846   if (face)
2847       [ns_lookup_indexed_color(face->foreground, f) set];
2849   ns_focus (f, &r, 1);
2850   NSRectFill(r);
2851   ns_unfocus (f);
2855 static void
2856 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2857 /* --------------------------------------------------------------------------
2858      External (RIF): Draw a window divider.
2859    -------------------------------------------------------------------------- */
2861   struct frame *f = XFRAME (WINDOW_FRAME (w));
2862   struct face *face;
2863   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2865   NSTRACE ("ns_draw_window_divider");
2867   face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2868   if (face)
2869       [ns_lookup_indexed_color(face->foreground, f) set];
2871   ns_focus (f, &r, 1);
2872   NSRectFill(r);
2873   ns_unfocus (f);
2876 static void
2877 ns_show_hourglass (struct frame *f)
2879   /* TODO: add NSProgressIndicator to all frames.  */
2882 static void
2883 ns_hide_hourglass (struct frame *f)
2885   /* TODO: remove NSProgressIndicator from all frames.  */
2888 /* ==========================================================================
2890     Glyph drawing operations
2892    ========================================================================== */
2894 static int
2895 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2896 /* --------------------------------------------------------------------------
2897     Wrapper utility to account for internal border width on full-width lines,
2898     and allow top full-width rows to hit the frame top.  nr should be pointer
2899     to two successive NSRects.  Number of rects actually used is returned.
2900    -------------------------------------------------------------------------- */
2902   int n = get_glyph_string_clip_rects (s, nr, 2);
2903   return n;
2906 /* --------------------------------------------------------------------
2907    Draw a wavy line under glyph string s. The wave fills wave_height
2908    pixels from y.
2910                     x          wave_length = 2
2911                                  --
2912                 y    *   *   *   *   *
2913                      |* * * * * * * * *
2914     wave_height = 3  | *   *   *   *
2915   --------------------------------------------------------------------- */
2917 static void
2918 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2920   int wave_height = 3, wave_length = 2;
2921   int y, dx, dy, odd, xmax;
2922   NSPoint a, b;
2923   NSRect waveClip;
2925   dx = wave_length;
2926   dy = wave_height - 1;
2927   y =  s->ybase - wave_height + 3;
2928   xmax = x + width;
2930   /* Find and set clipping rectangle */
2931   waveClip = NSMakeRect (x, y, width, wave_height);
2932   [[NSGraphicsContext currentContext] saveGraphicsState];
2933   NSRectClip (waveClip);
2935   /* Draw the waves */
2936   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2937   b.x = a.x + dx;
2938   odd = (int)(a.x/dx) % 2;
2939   a.y = b.y = y + 0.5;
2941   if (odd)
2942     a.y += dy;
2943   else
2944     b.y += dy;
2946   while (a.x <= xmax)
2947     {
2948       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2949       a.x = b.x, a.y = b.y;
2950       b.x += dx, b.y = y + 0.5 + odd*dy;
2951       odd = !odd;
2952     }
2954   /* Restore previous clipping rectangle(s) */
2955   [[NSGraphicsContext currentContext] restoreGraphicsState];
2960 void
2961 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2962                          NSColor *defaultCol, CGFloat width, CGFloat x)
2963 /* --------------------------------------------------------------------------
2964    Draw underline, overline, and strike-through on glyph string s.
2965    -------------------------------------------------------------------------- */
2967   if (s->for_overlaps)
2968     return;
2970   /* Do underline. */
2971   if (face->underline_p)
2972     {
2973       if (s->face->underline_type == FACE_UNDER_WAVE)
2974         {
2975           if (face->underline_defaulted_p)
2976             [defaultCol set];
2977           else
2978             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2980           ns_draw_underwave (s, width, x);
2981         }
2982       else if (s->face->underline_type == FACE_UNDER_LINE)
2983         {
2985           NSRect r;
2986           unsigned long thickness, position;
2988           /* If the prev was underlined, match its appearance. */
2989           if (s->prev && s->prev->face->underline_p
2990               && s->prev->face->underline_type == FACE_UNDER_LINE
2991               && s->prev->underline_thickness > 0)
2992             {
2993               thickness = s->prev->underline_thickness;
2994               position = s->prev->underline_position;
2995             }
2996           else
2997             {
2998               struct font *font;
2999               unsigned long descent;
3001               font=s->font;
3002               descent = s->y + s->height - s->ybase;
3004               /* Use underline thickness of font, defaulting to 1. */
3005               thickness = (font && font->underline_thickness > 0)
3006                 ? font->underline_thickness : 1;
3008               /* Determine the offset of underlining from the baseline. */
3009               if (x_underline_at_descent_line)
3010                 position = descent - thickness;
3011               else if (x_use_underline_position_properties
3012                        && font && font->underline_position >= 0)
3013                 position = font->underline_position;
3014               else if (font)
3015                 position = lround (font->descent / 2);
3016               else
3017                 position = underline_minimum_offset;
3019               position = max (position, underline_minimum_offset);
3021               /* Ensure underlining is not cropped. */
3022               if (descent <= position)
3023                 {
3024                   position = descent - 1;
3025                   thickness = 1;
3026                 }
3027               else if (descent < position + thickness)
3028                 thickness = 1;
3029             }
3031           s->underline_thickness = thickness;
3032           s->underline_position = position;
3034           r = NSMakeRect (x, s->ybase + position, width, thickness);
3036           if (face->underline_defaulted_p)
3037             [defaultCol set];
3038           else
3039             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3040           NSRectFill (r);
3041         }
3042     }
3043   /* Do overline. We follow other terms in using a thickness of 1
3044      and ignoring overline_margin. */
3045   if (face->overline_p)
3046     {
3047       NSRect r;
3048       r = NSMakeRect (x, s->y, width, 1);
3050       if (face->overline_color_defaulted_p)
3051         [defaultCol set];
3052       else
3053         [ns_lookup_indexed_color (face->overline_color, s->f) set];
3054       NSRectFill (r);
3055     }
3057   /* Do strike-through.  We follow other terms for thickness and
3058      vertical position.*/
3059   if (face->strike_through_p)
3060     {
3061       NSRect r;
3062       unsigned long dy;
3064       dy = lrint ((s->height - 1) / 2);
3065       r = NSMakeRect (x, s->y + dy, width, 1);
3067       if (face->strike_through_color_defaulted_p)
3068         [defaultCol set];
3069       else
3070         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3071       NSRectFill (r);
3072     }
3075 static void
3076 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3077              char left_p, char right_p)
3078 /* --------------------------------------------------------------------------
3079     Draw an unfilled rect inside r, optionally leaving left and/or right open.
3080     Note we can't just use an NSDrawRect command, because of the possibility
3081     of some sides not being drawn, and because the rect will be filled.
3082    -------------------------------------------------------------------------- */
3084   NSRect s = r;
3085   [col set];
3087   /* top, bottom */
3088   s.size.height = thickness;
3089   NSRectFill (s);
3090   s.origin.y += r.size.height - thickness;
3091   NSRectFill (s);
3093   s.size.height = r.size.height;
3094   s.origin.y = r.origin.y;
3096   /* left, right (optional) */
3097   s.size.width = thickness;
3098   if (left_p)
3099     NSRectFill (s);
3100   if (right_p)
3101     {
3102       s.origin.x += r.size.width - thickness;
3103       NSRectFill (s);
3104     }
3108 static void
3109 ns_draw_relief (NSRect r, int thickness, char raised_p,
3110                char top_p, char bottom_p, char left_p, char right_p,
3111                struct glyph_string *s)
3112 /* --------------------------------------------------------------------------
3113     Draw a relief rect inside r, optionally leaving some sides open.
3114     Note we can't just use an NSDrawBezel command, because of the possibility
3115     of some sides not being drawn, and because the rect will be filled.
3116    -------------------------------------------------------------------------- */
3118   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3119   NSColor *newBaseCol = nil;
3120   NSRect sr = r;
3122   NSTRACE ("ns_draw_relief");
3124   /* set up colors */
3126   if (s->face->use_box_color_for_shadows_p)
3127     {
3128       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3129     }
3130 /*     else if (s->first_glyph->type == IMAGE_GLYPH
3131            && s->img->pixmap
3132            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3133        {
3134          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
3135        } */
3136   else
3137     {
3138       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3139     }
3141   if (newBaseCol == nil)
3142     newBaseCol = [NSColor grayColor];
3144   if (newBaseCol != baseCol)  /* TODO: better check */
3145     {
3146       [baseCol release];
3147       baseCol = [newBaseCol retain];
3148       [lightCol release];
3149       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3150       [darkCol release];
3151       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3152     }
3154   [(raised_p ? lightCol : darkCol) set];
3156   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3158   /* top */
3159   sr.size.height = thickness;
3160   if (top_p) NSRectFill (sr);
3162   /* left */
3163   sr.size.height = r.size.height;
3164   sr.size.width = thickness;
3165   if (left_p) NSRectFill (sr);
3167   [(raised_p ? darkCol : lightCol) set];
3169   /* bottom */
3170   sr.size.width = r.size.width;
3171   sr.size.height = thickness;
3172   sr.origin.y += r.size.height - thickness;
3173   if (bottom_p) NSRectFill (sr);
3175   /* right */
3176   sr.size.height = r.size.height;
3177   sr.origin.y = r.origin.y;
3178   sr.size.width = thickness;
3179   sr.origin.x += r.size.width - thickness;
3180   if (right_p) NSRectFill (sr);
3184 static void
3185 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3186 /* --------------------------------------------------------------------------
3187       Function modeled after x_draw_glyph_string_box ().
3188       Sets up parameters for drawing.
3189    -------------------------------------------------------------------------- */
3191   int right_x, last_x;
3192   char left_p, right_p;
3193   struct glyph *last_glyph;
3194   NSRect r;
3195   int thickness;
3196   struct face *face;
3198   if (s->hl == DRAW_MOUSE_FACE)
3199     {
3200       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3201       if (!face)
3202         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3203     }
3204   else
3205     face = s->face;
3207   thickness = face->box_line_width;
3209   NSTRACE ("ns_dumpglyphs_box_or_relief");
3211   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3212             ? WINDOW_RIGHT_EDGE_X (s->w)
3213             : window_box_right (s->w, s->area));
3214   last_glyph = (s->cmp || s->img
3215                 ? s->first_glyph : s->first_glyph + s->nchars-1);
3217   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3218               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3220   left_p = (s->first_glyph->left_box_line_p
3221             || (s->hl == DRAW_MOUSE_FACE
3222                 && (s->prev == NULL || s->prev->hl != s->hl)));
3223   right_p = (last_glyph->right_box_line_p
3224              || (s->hl == DRAW_MOUSE_FACE
3225                  && (s->next == NULL || s->next->hl != s->hl)));
3227   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3229   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3230   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3231     {
3232       ns_draw_box (r, abs (thickness),
3233                    ns_lookup_indexed_color (face->box_color, s->f),
3234                   left_p, right_p);
3235     }
3236   else
3237     {
3238       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3239                      1, 1, left_p, right_p, s);
3240     }
3244 static void
3245 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3246 /* --------------------------------------------------------------------------
3247       Modeled after x_draw_glyph_string_background, which draws BG in
3248       certain cases.  Others are left to the text rendering routine.
3249    -------------------------------------------------------------------------- */
3251   NSTRACE ("ns_maybe_dumpglyphs_background");
3253   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3254     {
3255       int box_line_width = max (s->face->box_line_width, 0);
3256       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3257           /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3258              dimensions, since the actual glyphs might be much
3259              smaller.  So in that case we always clear the rectangle
3260              with background color.  */
3261           || FONT_TOO_HIGH (s->font)
3262           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3263         {
3264           struct face *face;
3265           if (s->hl == DRAW_MOUSE_FACE)
3266             {
3267               face = FACE_FROM_ID (s->f,
3268                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3269               if (!face)
3270                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3271             }
3272           else
3273             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3274           if (!face->stipple)
3275             [(NS_FACE_BACKGROUND (face) != 0
3276               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3277               : FRAME_BACKGROUND_COLOR (s->f)) set];
3278           else
3279             {
3280               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3281               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3282             }
3284           if (s->hl != DRAW_CURSOR)
3285             {
3286               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3287                                     s->background_width,
3288                                     s->height-2*box_line_width);
3289               NSRectFill (r);
3290             }
3292           s->background_filled_p = 1;
3293         }
3294     }
3298 static void
3299 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3300 /* --------------------------------------------------------------------------
3301       Renders an image and associated borders.
3302    -------------------------------------------------------------------------- */
3304   EmacsImage *img = s->img->pixmap;
3305   int box_line_vwidth = max (s->face->box_line_width, 0);
3306   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3307   int bg_x, bg_y, bg_height;
3308   int th;
3309   char raised_p;
3310   NSRect br;
3311   struct face *face;
3312   NSColor *tdCol;
3314   NSTRACE ("ns_dumpglyphs_image");
3316   if (s->face->box != FACE_NO_BOX
3317       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3318     x += abs (s->face->box_line_width);
3320   bg_x = x;
3321   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3322   bg_height = s->height;
3323   /* other terms have this, but was causing problems w/tabbar mode */
3324   /* - 2 * box_line_vwidth; */
3326   if (s->slice.x == 0) x += s->img->hmargin;
3327   if (s->slice.y == 0) y += s->img->vmargin;
3329   /* Draw BG: if we need larger area than image itself cleared, do that,
3330      otherwise, since we composite the image under NS (instead of mucking
3331      with its background color), we must clear just the image area. */
3332   if (s->hl == DRAW_MOUSE_FACE)
3333     {
3334       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3335       if (!face)
3336        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3337     }
3338   else
3339     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3341   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3343   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3344       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3345     {
3346       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3347       s->background_filled_p = 1;
3348     }
3349   else
3350     {
3351       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3352     }
3354   NSRectFill (br);
3356   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3357   if (img != nil)
3358     {
3359 #ifdef NS_IMPL_COCOA
3360       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3361       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3362                               s->slice.width, s->slice.height);
3363       [img drawInRect: dr
3364              fromRect: ir
3365              operation: NSCompositeSourceOver
3366               fraction: 1.0
3367            respectFlipped: YES
3368                 hints: nil];
3369 #else
3370       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3371                   operation: NSCompositeSourceOver];
3372 #endif
3373     }
3375   if (s->hl == DRAW_CURSOR)
3376     {
3377     [FRAME_CURSOR_COLOR (s->f) set];
3378     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3379       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3380     else
3381       /* Currently on NS img->mask is always 0. Since
3382          get_window_cursor_type specifies a hollow box cursor when on
3383          a non-masked image we never reach this clause. But we put it
3384          in in anticipation of better support for image masks on
3385          NS. */
3386       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3387     }
3388   else
3389     {
3390       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3391     }
3393   /* Draw underline, overline, strike-through. */
3394   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3396   /* Draw relief, if requested */
3397   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3398     {
3399       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3400         {
3401           th = tool_bar_button_relief >= 0 ?
3402             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3403           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3404         }
3405       else
3406         {
3407           th = abs (s->img->relief);
3408           raised_p = (s->img->relief > 0);
3409         }
3411       r.origin.x = x - th;
3412       r.origin.y = y - th;
3413       r.size.width = s->slice.width + 2*th-1;
3414       r.size.height = s->slice.height + 2*th-1;
3415       ns_draw_relief (r, th, raised_p,
3416                       s->slice.y == 0,
3417                       s->slice.y + s->slice.height == s->img->height,
3418                       s->slice.x == 0,
3419                       s->slice.x + s->slice.width == s->img->width, s);
3420     }
3422   /* If there is no mask, the background won't be seen,
3423      so draw a rectangle on the image for the cursor.
3424      Do this for all images, getting transparency right is not reliable.  */
3425   if (s->hl == DRAW_CURSOR)
3426     {
3427       int thickness = abs (s->img->relief);
3428       if (thickness == 0) thickness = 1;
3429       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3430     }
3434 static void
3435 ns_dumpglyphs_stretch (struct glyph_string *s)
3437   NSRect r[2];
3438   int n, i;
3439   struct face *face;
3440   NSColor *fgCol, *bgCol;
3442   if (!s->background_filled_p)
3443     {
3444       n = ns_get_glyph_string_clip_rect (s, r);
3445       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3447       ns_focus (s->f, r, n);
3449       if (s->hl == DRAW_MOUSE_FACE)
3450        {
3451          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3452          if (!face)
3453            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3454        }
3455       else
3456        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3458       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3459       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3461       for (i = 0; i < n; ++i)
3462         {
3463           if (!s->row->full_width_p)
3464             {
3465               int overrun, leftoverrun;
3467               /* truncate to avoid overwriting fringe and/or scrollbar */
3468               overrun = max (0, (s->x + s->background_width)
3469                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3470                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3471               r[i].size.width -= overrun;
3473               /* truncate to avoid overwriting to left of the window box */
3474               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3475                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3477               if (leftoverrun > 0)
3478                 {
3479                   r[i].origin.x += leftoverrun;
3480                   r[i].size.width -= leftoverrun;
3481                 }
3483               /* XXX: Try to work between problem where a stretch glyph on
3484                  a partially-visible bottom row will clear part of the
3485                  modeline, and another where list-buffers headers and similar
3486                  rows erroneously have visible_height set to 0.  Not sure
3487                  where this is coming from as other terms seem not to show. */
3488               r[i].size.height = min (s->height, s->row->visible_height);
3489             }
3491           [bgCol set];
3493           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3494              overwriting cursor (usually when cursor on a tab) */
3495           if (s->hl == DRAW_CURSOR)
3496             {
3497               CGFloat x, width;
3499               x = r[i].origin.x;
3500               width = s->w->phys_cursor_width;
3501               r[i].size.width -= width;
3502               r[i].origin.x += width;
3504               NSRectFill (r[i]);
3506               /* Draw overlining, etc. on the cursor. */
3507               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3508                 ns_draw_text_decoration (s, face, bgCol, width, x);
3509               else
3510                 ns_draw_text_decoration (s, face, fgCol, width, x);
3511             }
3512           else
3513             {
3514               NSRectFill (r[i]);
3515             }
3517           /* Draw overlining, etc. on the stretch glyph (or the part
3518              of the stretch glyph after the cursor). */
3519           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3520                                    r[i].origin.x);
3521         }
3522       ns_unfocus (s->f);
3523       s->background_filled_p = 1;
3524     }
3528 static void
3529 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3531   int i, j, x;
3532   struct font *font = s->font;
3534   /* If first glyph of S has a left box line, start drawing the text
3535      of S to the right of that box line.  */
3536   if (s->face && s->face->box != FACE_NO_BOX
3537       && s->first_glyph->left_box_line_p)
3538     x = s->x + eabs (s->face->box_line_width);
3539   else
3540     x = s->x;
3542   /* S is a glyph string for a composition.  S->cmp_from is the index
3543      of the first character drawn for glyphs of this composition.
3544      S->cmp_from == 0 means we are drawing the very first character of
3545      this composition.  */
3547   /* Draw a rectangle for the composition if the font for the very
3548      first character of the composition could not be loaded.  */
3549   if (s->font_not_found_p)
3550     {
3551       if (s->cmp_from == 0)
3552         {
3553           NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3554           ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3555         }
3556     }
3557   else if (! s->first_glyph->u.cmp.automatic)
3558     {
3559       int y = s->ybase;
3561       for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3562         /* TAB in a composition means display glyphs with padding
3563            space on the left or right.  */
3564         if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3565           {
3566             int xx = x + s->cmp->offsets[j * 2];
3567             int yy = y - s->cmp->offsets[j * 2 + 1];
3569             font->driver->draw (s, j, j + 1, xx, yy, false);
3570             if (s->face->overstrike)
3571               font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3572           }
3573     }
3574   else
3575     {
3576       Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3577       Lisp_Object glyph;
3578       int y = s->ybase;
3579       int width = 0;
3581       for (i = j = s->cmp_from; i < s->cmp_to; i++)
3582         {
3583           glyph = LGSTRING_GLYPH (gstring, i);
3584           if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3585             width += LGLYPH_WIDTH (glyph);
3586           else
3587             {
3588               int xoff, yoff, wadjust;
3590               if (j < i)
3591                 {
3592                   font->driver->draw (s, j, i, x, y, false);
3593                   if (s->face->overstrike)
3594                     font->driver->draw (s, j, i, x + 1, y, false);
3595                   x += width;
3596                 }
3597               xoff = LGLYPH_XOFF (glyph);
3598               yoff = LGLYPH_YOFF (glyph);
3599               wadjust = LGLYPH_WADJUST (glyph);
3600               font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3601               if (s->face->overstrike)
3602                 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3603                                     false);
3604               x += wadjust;
3605               j = i + 1;
3606               width = 0;
3607             }
3608         }
3609       if (j < i)
3610         {
3611           font->driver->draw (s, j, i, x, y, false);
3612           if (s->face->overstrike)
3613             font->driver->draw (s, j, i, x + 1, y, false);
3614         }
3615     }
3618 static void
3619 ns_draw_glyph_string (struct glyph_string *s)
3620 /* --------------------------------------------------------------------------
3621       External (RIF): Main draw-text call.
3622    -------------------------------------------------------------------------- */
3624   /* TODO (optimize): focus for box and contents draw */
3625   NSRect r[2];
3626   int n, flags;
3627   char box_drawn_p = 0;
3628   struct font *font = s->face->font;
3629   if (! font) font = FRAME_FONT (s->f);
3631   NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3633   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3634     {
3635       int width;
3636       struct glyph_string *next;
3638       for (width = 0, next = s->next;
3639            next && width < s->right_overhang;
3640            width += next->width, next = next->next)
3641         if (next->first_glyph->type != IMAGE_GLYPH)
3642           {
3643             if (next->first_glyph->type != STRETCH_GLYPH)
3644               {
3645                 n = ns_get_glyph_string_clip_rect (s->next, r);
3646                 ns_focus (s->f, r, n);
3647                 ns_maybe_dumpglyphs_background (s->next, 1);
3648                 ns_unfocus (s->f);
3649               }
3650             else
3651               {
3652                 ns_dumpglyphs_stretch (s->next);
3653               }
3654             next->num_clips = 0;
3655           }
3656     }
3658   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3659         && (s->first_glyph->type == CHAR_GLYPH
3660             || s->first_glyph->type == COMPOSITE_GLYPH))
3661     {
3662       n = ns_get_glyph_string_clip_rect (s, r);
3663       ns_focus (s->f, r, n);
3664       ns_maybe_dumpglyphs_background (s, 1);
3665       ns_dumpglyphs_box_or_relief (s);
3666       ns_unfocus (s->f);
3667       box_drawn_p = 1;
3668     }
3670   switch (s->first_glyph->type)
3671     {
3673     case IMAGE_GLYPH:
3674       n = ns_get_glyph_string_clip_rect (s, r);
3675       ns_focus (s->f, r, n);
3676       ns_dumpglyphs_image (s, r[0]);
3677       ns_unfocus (s->f);
3678       break;
3680     case STRETCH_GLYPH:
3681       ns_dumpglyphs_stretch (s);
3682       break;
3684     case CHAR_GLYPH:
3685     case COMPOSITE_GLYPH:
3686       n = ns_get_glyph_string_clip_rect (s, r);
3687       ns_focus (s->f, r, n);
3689       if (s->for_overlaps || (s->cmp_from > 0
3690                               && ! s->first_glyph->u.cmp.automatic))
3691         s->background_filled_p = 1;
3692       else
3693         ns_maybe_dumpglyphs_background
3694           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3696       flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3697         (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3698          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3699           NS_DUMPGLYPH_NORMAL));
3701       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3702         {
3703           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3704           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3705           NS_FACE_FOREGROUND (s->face) = tmp;
3706         }
3708       {
3709         BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3711         if (isComposite)
3712           ns_draw_composite_glyph_string_foreground (s);
3713         else
3714           font->driver->draw
3715             (s, s->cmp_from, s->nchars, s->x, s->ybase,
3716              (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3717              || flags == NS_DUMPGLYPH_MOUSEFACE);
3718       }
3720       {
3721         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3722                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3723                                                    s->f)
3724                         : FRAME_FOREGROUND_COLOR (s->f));
3725         [col set];
3727         /* Draw underline, overline, strike-through. */
3728         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3729       }
3731       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3732         {
3733           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3734           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3735           NS_FACE_FOREGROUND (s->face) = tmp;
3736         }
3738       ns_unfocus (s->f);
3739       break;
3741     case GLYPHLESS_GLYPH:
3742       n = ns_get_glyph_string_clip_rect (s, r);
3743       ns_focus (s->f, r, n);
3745       if (s->for_overlaps || (s->cmp_from > 0
3746                               && ! s->first_glyph->u.cmp.automatic))
3747         s->background_filled_p = 1;
3748       else
3749         ns_maybe_dumpglyphs_background
3750           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3751       /* ... */
3752       /* Not yet implemented.  */
3753       /* ... */
3754       ns_unfocus (s->f);
3755       break;
3757     default:
3758       emacs_abort ();
3759     }
3761   /* Draw box if not done already. */
3762   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3763     {
3764       n = ns_get_glyph_string_clip_rect (s, r);
3765       ns_focus (s->f, r, n);
3766       ns_dumpglyphs_box_or_relief (s);
3767       ns_unfocus (s->f);
3768     }
3770   s->num_clips = 0;
3775 /* ==========================================================================
3777     Event loop
3779    ========================================================================== */
3782 static void
3783 ns_send_appdefined (int value)
3784 /* --------------------------------------------------------------------------
3785     Internal: post an appdefined event which EmacsApp-sendEvent will
3786               recognize and take as a command to halt the event loop.
3787    -------------------------------------------------------------------------- */
3789   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
3791 #ifdef NS_IMPL_GNUSTEP
3792   // GNUstep needs postEvent to happen on the main thread.
3793   if (! [[NSThread currentThread] isMainThread])
3794     {
3795       EmacsApp *app = (EmacsApp *)NSApp;
3796       app->nextappdefined = value;
3797       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3798                             withObject:nil
3799                          waitUntilDone:YES];
3800       return;
3801     }
3802 #endif
3804   /* Only post this event if we haven't already posted one.  This will end
3805        the [NXApp run] main loop after having processed all events queued at
3806        this moment.  */
3808 #ifdef NS_IMPL_COCOA
3809   if (! send_appdefined)
3810     {
3811       /* OSX 10.10.1 swallows the AppDefined event we are sending ourselves
3812          in certain situations (rapid incoming events).
3813          So check if we have one, if not add one.  */
3814       NSEvent *appev = [NSApp nextEventMatchingMask:NSApplicationDefinedMask
3815                                           untilDate:[NSDate distantPast]
3816                                              inMode:NSDefaultRunLoopMode
3817                                             dequeue:NO];
3818       if (! appev) send_appdefined = YES;
3819     }
3820 #endif
3822   if (send_appdefined)
3823     {
3824       NSEvent *nxev;
3826       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3827       send_appdefined = NO;
3829       /* Don't need wakeup timer any more */
3830       if (timed_entry)
3831         {
3832           [timed_entry invalidate];
3833           [timed_entry release];
3834           timed_entry = nil;
3835         }
3837       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3838                                 location: NSMakePoint (0, 0)
3839                            modifierFlags: 0
3840                                timestamp: 0
3841                             windowNumber: [[NSApp mainWindow] windowNumber]
3842                                  context: [NSApp context]
3843                                  subtype: 0
3844                                    data1: value
3845                                    data2: 0];
3847       /* Post an application defined event on the event queue.  When this is
3848          received the [NXApp run] will return, thus having processed all
3849          events which are currently queued.  */
3850       [NSApp postEvent: nxev atStart: NO];
3851     }
3854 #ifdef HAVE_NATIVE_FS
3855 static void
3856 check_native_fs ()
3858   Lisp_Object frame, tail;
3860   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3861     return;
3863   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3865   FOR_EACH_FRAME (tail, frame)
3866     {
3867       struct frame *f = XFRAME (frame);
3868       if (FRAME_NS_P (f))
3869         {
3870           EmacsView *view = FRAME_NS_VIEW (f);
3871           [view updateCollectionBehavior];
3872         }
3873     }
3875 #endif
3877 /* GNUstep does not have cancelTracking.  */
3878 #ifdef NS_IMPL_COCOA
3879 /* Check if menu open should be canceled or continued as normal.  */
3880 void
3881 ns_check_menu_open (NSMenu *menu)
3883   /* Click in menu bar? */
3884   NSArray *a = [[NSApp mainMenu] itemArray];
3885   int i;
3886   BOOL found = NO;
3888   if (menu == nil) // Menu tracking ended.
3889     {
3890       if (menu_will_open_state == MENU_OPENING)
3891         menu_will_open_state = MENU_NONE;
3892       return;
3893     }
3895   for (i = 0; ! found && i < [a count]; i++)
3896     found = menu == [[a objectAtIndex:i] submenu];
3897   if (found)
3898     {
3899       if (menu_will_open_state == MENU_NONE && emacs_event)
3900         {
3901           NSEvent *theEvent = [NSApp currentEvent];
3902           struct frame *emacsframe = SELECTED_FRAME ();
3904           [menu cancelTracking];
3905           menu_will_open_state = MENU_PENDING;
3906           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3907           EV_TRAILER (theEvent);
3909           CGEventRef ourEvent = CGEventCreate (NULL);
3910           menu_mouse_point = CGEventGetLocation (ourEvent);
3911           CFRelease (ourEvent);
3912         }
3913       else if (menu_will_open_state == MENU_OPENING)
3914         {
3915           menu_will_open_state = MENU_NONE;
3916         }
3917     }
3920 /* Redo saved menu click if state is MENU_PENDING.  */
3921 void
3922 ns_check_pending_open_menu ()
3924   if (menu_will_open_state == MENU_PENDING)
3925     {
3926       CGEventSourceRef source
3927         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3929       CGEventRef event = CGEventCreateMouseEvent (source,
3930                                                   kCGEventLeftMouseDown,
3931                                                   menu_mouse_point,
3932                                                   kCGMouseButtonLeft);
3933       CGEventSetType (event, kCGEventLeftMouseDown);
3934       CGEventPost (kCGHIDEventTap, event);
3935       CFRelease (event);
3936       CFRelease (source);
3938       menu_will_open_state = MENU_OPENING;
3939     }
3941 #endif /* NS_IMPL_COCOA */
3943 static void
3944 unwind_apploopnr (Lisp_Object not_used)
3946   --apploopnr;
3947   n_emacs_events_pending = 0;
3948   ns_finish_events ();
3949   q_event_ptr = NULL;
3952 static int
3953 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3954 /* --------------------------------------------------------------------------
3955      External (hook): Post an event to ourself and keep reading events until
3956      we read it back again.  In effect process all events which were waiting.
3957      From 21+ we have to manage the event buffer ourselves.
3958    -------------------------------------------------------------------------- */
3960   struct input_event ev;
3961   int nevents;
3963   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
3965 #ifdef HAVE_NATIVE_FS
3966   check_native_fs ();
3967 #endif
3969   if ([NSApp modalWindow] != nil)
3970     return -1;
3972   if (hold_event_q.nr > 0)
3973     {
3974       int i;
3975       for (i = 0; i < hold_event_q.nr; ++i)
3976         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3977       hold_event_q.nr = 0;
3978       return i;
3979     }
3981   block_input ();
3982   n_emacs_events_pending = 0;
3983   ns_init_events (&ev);
3984   q_event_ptr = hold_quit;
3986   /* we manage autorelease pools by allocate/reallocate each time around
3987      the loop; strict nesting is occasionally violated but seems not to
3988      matter.. earlier methods using full nesting caused major memory leaks */
3989   [outerpool release];
3990   outerpool = [[NSAutoreleasePool alloc] init];
3992   /* If have pending open-file requests, attend to the next one of those. */
3993   if (ns_pending_files && [ns_pending_files count] != 0
3994       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3995     {
3996       [ns_pending_files removeObjectAtIndex: 0];
3997     }
3998   /* Deal with pending service requests. */
3999   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4000     && [(EmacsApp *)
4001          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4002                       withArg: [ns_pending_service_args objectAtIndex: 0]])
4003     {
4004       [ns_pending_service_names removeObjectAtIndex: 0];
4005       [ns_pending_service_args removeObjectAtIndex: 0];
4006     }
4007   else
4008     {
4009       ptrdiff_t specpdl_count = SPECPDL_INDEX ();
4010       /* Run and wait for events.  We must always send one NX_APPDEFINED event
4011          to ourself, otherwise [NXApp run] will never exit.  */
4012       send_appdefined = YES;
4013       ns_send_appdefined (-1);
4015       if (++apploopnr != 1)
4016         {
4017           emacs_abort ();
4018         }
4019       record_unwind_protect (unwind_apploopnr, Qt);
4020       [NSApp run];
4021       unbind_to (specpdl_count, Qnil);  /* calls unwind_apploopnr */
4022     }
4024   nevents = n_emacs_events_pending;
4025   n_emacs_events_pending = 0;
4026   ns_finish_events ();
4027   q_event_ptr = NULL;
4028   unblock_input ();
4030   return nevents;
4035 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4036            fd_set *exceptfds, struct timespec const *timeout,
4037            sigset_t const *sigmask)
4038 /* --------------------------------------------------------------------------
4039      Replacement for select, checking for events
4040    -------------------------------------------------------------------------- */
4042   int result;
4043   int t, k, nr = 0;
4044   struct input_event event;
4045   char c;
4047   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4049 #ifdef HAVE_NATIVE_FS
4050   check_native_fs ();
4051 #endif
4053   if (hold_event_q.nr > 0)
4054     {
4055       /* We already have events pending. */
4056       raise (SIGIO);
4057       errno = EINTR;
4058       return -1;
4059     }
4061   for (k = 0; k < nfds+1; k++)
4062     {
4063       if (readfds && FD_ISSET(k, readfds)) ++nr;
4064       if (writefds && FD_ISSET(k, writefds)) ++nr;
4065     }
4067   if (NSApp == nil
4068       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4069     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
4071   [outerpool release];
4072   outerpool = [[NSAutoreleasePool alloc] init];
4075   send_appdefined = YES;
4076   if (nr > 0)
4077     {
4078       pthread_mutex_lock (&select_mutex);
4079       select_nfds = nfds;
4080       select_valid = 0;
4081       if (readfds)
4082         {
4083           select_readfds = *readfds;
4084           select_valid += SELECT_HAVE_READ;
4085         }
4086       if (writefds)
4087         {
4088           select_writefds = *writefds;
4089           select_valid += SELECT_HAVE_WRITE;
4090         }
4092       if (timeout)
4093         {
4094           select_timeout = *timeout;
4095           select_valid += SELECT_HAVE_TMO;
4096         }
4098       pthread_mutex_unlock (&select_mutex);
4100       /* Inform fd_handler that select should be called */
4101       c = 'g';
4102       emacs_write_sig (selfds[1], &c, 1);
4103     }
4104   else if (nr == 0 && timeout)
4105     {
4106       /* No file descriptor, just a timeout, no need to wake fd_handler  */
4107       double time = timespectod (*timeout);
4108       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4109                                                       target: NSApp
4110                                                     selector:
4111                                   @selector (timeout_handler:)
4112                                                     userInfo: 0
4113                                                      repeats: NO]
4114                       retain];
4115     }
4116   else /* No timeout and no file descriptors, can this happen?  */
4117     {
4118       /* Send appdefined so we exit from the loop */
4119       ns_send_appdefined (-1);
4120     }
4122   block_input ();
4123   ns_init_events (&event);
4124   if (++apploopnr != 1)
4125     {
4126       emacs_abort ();
4127     }
4129   {
4130     ptrdiff_t specpdl_count = SPECPDL_INDEX ();
4131     record_unwind_protect (unwind_apploopnr, Qt);
4132     [NSApp run];
4133     unbind_to (specpdl_count, Qnil);  /* calls unwind_apploopnr */
4134   }
4136   ns_finish_events ();
4137   if (nr > 0 && readfds)
4138     {
4139       c = 's';
4140       emacs_write_sig (selfds[1], &c, 1);
4141     }
4142   unblock_input ();
4144   t = last_appdefined_event_data;
4146   if (t != NO_APPDEFINED_DATA)
4147     {
4148       last_appdefined_event_data = NO_APPDEFINED_DATA;
4150       if (t == -2)
4151         {
4152           /* The NX_APPDEFINED event we received was a timeout. */
4153           result = 0;
4154         }
4155       else if (t == -1)
4156         {
4157           /* The NX_APPDEFINED event we received was the result of
4158              at least one real input event arriving.  */
4159           errno = EINTR;
4160           result = -1;
4161         }
4162       else
4163         {
4164           /* Received back from select () in fd_handler; copy the results */
4165           pthread_mutex_lock (&select_mutex);
4166           if (readfds) *readfds = select_readfds;
4167           if (writefds) *writefds = select_writefds;
4168           pthread_mutex_unlock (&select_mutex);
4169           result = t;
4170         }
4171     }
4172   else
4173     {
4174       errno = EINTR;
4175       result = -1;
4176     }
4178   return result;
4183 /* ==========================================================================
4185     Scrollbar handling
4187    ========================================================================== */
4190 static void
4191 ns_set_vertical_scroll_bar (struct window *window,
4192                            int portion, int whole, int position)
4193 /* --------------------------------------------------------------------------
4194       External (hook): Update or add scrollbar
4195    -------------------------------------------------------------------------- */
4197   Lisp_Object win;
4198   NSRect r, v;
4199   struct frame *f = XFRAME (WINDOW_FRAME (window));
4200   EmacsView *view = FRAME_NS_VIEW (f);
4201   EmacsScroller *bar;
4202   int window_y, window_height;
4203   int top, left, height, width;
4204   BOOL update_p = YES;
4206   /* optimization; display engine sends WAY too many of these.. */
4207   if (!NILP (window->vertical_scroll_bar))
4208     {
4209       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4210       if ([bar checkSamePosition: position portion: portion whole: whole])
4211         {
4212           if (view->scrollbarsNeedingUpdate == 0)
4213             {
4214               if (!windows_or_buffers_changed)
4215                   return;
4216             }
4217           else
4218             view->scrollbarsNeedingUpdate--;
4219           update_p = NO;
4220         }
4221     }
4223   NSTRACE ("ns_set_vertical_scroll_bar");
4225   /* Get dimensions.  */
4226   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4227   top = window_y;
4228   height = window_height;
4229   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
4230   left = WINDOW_SCROLL_BAR_AREA_X (window);
4232   r = NSMakeRect (left, top, width, height);
4233   /* the parent view is flipped, so we need to flip y value */
4234   v = [view frame];
4235   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4237   XSETWINDOW (win, window);
4238   block_input ();
4240   /* we want at least 5 lines to display a scrollbar */
4241   if (WINDOW_TOTAL_LINES (window) < 5)
4242     {
4243       if (!NILP (window->vertical_scroll_bar))
4244         {
4245           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4246           [bar removeFromSuperview];
4247           wset_vertical_scroll_bar (window, Qnil);
4248           [bar release];
4249         }
4250       ns_clear_frame_area (f, left, top, width, height);
4251       unblock_input ();
4252       return;
4253     }
4255   if (NILP (window->vertical_scroll_bar))
4256     {
4257       if (width > 0 && height > 0)
4258         ns_clear_frame_area (f, left, top, width, height);
4260       bar = [[EmacsScroller alloc] initFrame: r window: win];
4261       wset_vertical_scroll_bar (window, make_save_ptr (bar));
4262       update_p = YES;
4263     }
4264   else
4265     {
4266       NSRect oldRect;
4267       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4268       oldRect = [bar frame];
4269       r.size.width = oldRect.size.width;
4270       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4271         {
4272           if (oldRect.origin.x != r.origin.x)
4273               ns_clear_frame_area (f, left, top, width, height);
4274           [bar setFrame: r];
4275         }
4276     }
4278   if (update_p)
4279     [bar setPosition: position portion: portion whole: whole];
4280   unblock_input ();
4284 static void
4285 ns_set_horizontal_scroll_bar (struct window *window,
4286                               int portion, int whole, int position)
4287 /* --------------------------------------------------------------------------
4288       External (hook): Update or add scrollbar
4289    -------------------------------------------------------------------------- */
4291   Lisp_Object win;
4292   NSRect r, v;
4293   struct frame *f = XFRAME (WINDOW_FRAME (window));
4294   EmacsView *view = FRAME_NS_VIEW (f);
4295   EmacsScroller *bar;
4296   int top, height, left, width;
4297   int window_x, window_width;
4298   BOOL update_p = YES;
4300   /* optimization; display engine sends WAY too many of these.. */
4301   if (!NILP (window->horizontal_scroll_bar))
4302     {
4303       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4304       if ([bar checkSamePosition: position portion: portion whole: whole])
4305         {
4306           if (view->scrollbarsNeedingUpdate == 0)
4307             {
4308               if (!windows_or_buffers_changed)
4309                   return;
4310             }
4311           else
4312             view->scrollbarsNeedingUpdate--;
4313           update_p = NO;
4314         }
4315     }
4317   NSTRACE ("ns_set_horizontal_scroll_bar");
4319   /* Get dimensions.  */
4320   window_box (window, ANY_AREA, 0, &window_x, &window_width, 0);
4321   left = window_x;
4322   width = window_width;
4323   height = WINDOW_CONFIG_SCROLL_BAR_LINES (window) * FRAME_LINE_HEIGHT (f);
4324   top = WINDOW_SCROLL_BAR_AREA_Y (window);
4326   r = NSMakeRect (left, top, width, height);
4327   /* the parent view is flipped, so we need to flip y value */
4328   v = [view frame];
4329   /* ??????? PXW/scrollbars !!!!!!!!!!!!!!!!!!!! */
4330   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4332   XSETWINDOW (win, window);
4333   block_input ();
4335   if (WINDOW_TOTAL_COLS (window) < 5)
4336     {
4337       if (!NILP (window->horizontal_scroll_bar))
4338         {
4339           bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4340           [bar removeFromSuperview];
4341           wset_horizontal_scroll_bar (window, Qnil);
4342         }
4343       ns_clear_frame_area (f, left, top, width, height);
4344       unblock_input ();
4345       return;
4346     }
4348   if (NILP (window->horizontal_scroll_bar))
4349     {
4350       if (width > 0 && height > 0)
4351         ns_clear_frame_area (f, left, top, width, height);
4353       bar = [[EmacsScroller alloc] initFrame: r window: win];
4354       wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4355       update_p = YES;
4356     }
4357   else
4358     {
4359       NSRect oldRect;
4360       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4361       oldRect = [bar frame];
4362       r.size.width = oldRect.size.width;
4363       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4364         {
4365           if (oldRect.origin.x != r.origin.x)
4366               ns_clear_frame_area (f, left, top, width, height);
4367           [bar setFrame: r];
4368           update_p = YES;
4369         }
4370     }
4372   if (update_p)
4373     [bar setPosition: position portion: portion whole: whole];
4374   unblock_input ();
4378 static void
4379 ns_condemn_scroll_bars (struct frame *f)
4380 /* --------------------------------------------------------------------------
4381      External (hook): arrange for all frame's scrollbars to be removed
4382      at next call to judge_scroll_bars, except for those redeemed.
4383    -------------------------------------------------------------------------- */
4385   int i;
4386   id view;
4387   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4389   NSTRACE ("ns_condemn_scroll_bars");
4391   for (i =[subviews count]-1; i >= 0; i--)
4392     {
4393       view = [subviews objectAtIndex: i];
4394       if ([view isKindOfClass: [EmacsScroller class]])
4395         [view condemn];
4396     }
4400 static void
4401 ns_redeem_scroll_bar (struct window *window)
4402 /* --------------------------------------------------------------------------
4403      External (hook): arrange to spare this window's scrollbar
4404      at next call to judge_scroll_bars.
4405    -------------------------------------------------------------------------- */
4407   id bar;
4408   NSTRACE ("ns_redeem_scroll_bar");
4409   if (!NILP (window->vertical_scroll_bar))
4410     {
4411       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4412       [bar reprieve];
4413     }
4415   if (!NILP (window->horizontal_scroll_bar))
4416     {
4417       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4418       [bar reprieve];
4419     }
4423 static void
4424 ns_judge_scroll_bars (struct frame *f)
4425 /* --------------------------------------------------------------------------
4426      External (hook): destroy all scrollbars on frame that weren't
4427      redeemed after call to condemn_scroll_bars.
4428    -------------------------------------------------------------------------- */
4430   int i;
4431   id view;
4432   EmacsView *eview = FRAME_NS_VIEW (f);
4433   NSArray *subviews = [[eview superview] subviews];
4434   BOOL removed = NO;
4436   NSTRACE ("ns_judge_scroll_bars");
4437   for (i = [subviews count]-1; i >= 0; --i)
4438     {
4439       view = [subviews objectAtIndex: i];
4440       if (![view isKindOfClass: [EmacsScroller class]]) continue;
4441       if ([view judge])
4442         removed = YES;
4443     }
4445   if (removed)
4446     [eview updateFrameSize: NO];
4449 /* ==========================================================================
4451     Initialization
4453    ========================================================================== */
4456 x_display_pixel_height (struct ns_display_info *dpyinfo)
4458   NSArray *screens = [NSScreen screens];
4459   NSEnumerator *enumerator = [screens objectEnumerator];
4460   NSScreen *screen;
4461   NSRect frame;
4463   frame = NSZeroRect;
4464   while ((screen = [enumerator nextObject]) != nil)
4465     frame = NSUnionRect (frame, [screen frame]);
4467   return NSHeight (frame);
4471 x_display_pixel_width (struct ns_display_info *dpyinfo)
4473   NSArray *screens = [NSScreen screens];
4474   NSEnumerator *enumerator = [screens objectEnumerator];
4475   NSScreen *screen;
4476   NSRect frame;
4478   frame = NSZeroRect;
4479   while ((screen = [enumerator nextObject]) != nil)
4480     frame = NSUnionRect (frame, [screen frame]);
4482   return NSWidth (frame);
4486 static Lisp_Object ns_string_to_lispmod (const char *s)
4487 /* --------------------------------------------------------------------------
4488      Convert modifier name to lisp symbol
4489    -------------------------------------------------------------------------- */
4491   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4492     return Qmeta;
4493   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4494     return Qsuper;
4495   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4496     return Qcontrol;
4497   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4498     return Qalt;
4499   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4500     return Qhyper;
4501   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4502     return Qnone;
4503   else
4504     return Qnil;
4508 static void
4509 ns_default (const char *parameter, Lisp_Object *result,
4510            Lisp_Object yesval, Lisp_Object noval,
4511            BOOL is_float, BOOL is_modstring)
4512 /* --------------------------------------------------------------------------
4513       Check a parameter value in user's preferences
4514    -------------------------------------------------------------------------- */
4516   const char *value = ns_get_defaults_value (parameter);
4518   if (value)
4519     {
4520       double f;
4521       char *pos;
4522       if (c_strcasecmp (value, "YES") == 0)
4523         *result = yesval;
4524       else if (c_strcasecmp (value, "NO") == 0)
4525         *result = noval;
4526       else if (is_float && (f = strtod (value, &pos), pos != value))
4527         *result = make_float (f);
4528       else if (is_modstring && value)
4529         *result = ns_string_to_lispmod (value);
4530       else fprintf (stderr,
4531                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4532     }
4536 static void
4537 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4538 /* --------------------------------------------------------------------------
4539       Initialize global info and storage for display.
4540    -------------------------------------------------------------------------- */
4542     NSScreen *screen = [NSScreen mainScreen];
4543     NSWindowDepth depth = [screen depth];
4545     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4546     dpyinfo->resy = 72.27;
4547     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4548                                                   NSColorSpaceFromDepth (depth)]
4549                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4550                                                  NSColorSpaceFromDepth (depth)];
4551     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4552     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4553     dpyinfo->color_table->colors = NULL;
4554     dpyinfo->root_window = 42; /* a placeholder.. */
4555     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4556     dpyinfo->n_fonts = 0;
4557     dpyinfo->smallest_font_height = 1;
4558     dpyinfo->smallest_char_width = 1;
4560     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4564 /* This and next define (many of the) public functions in this file. */
4565 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4566          with using despite presence in the "system dependent" redisplay
4567          interface.  In addition, many of the ns_ methods have code that is
4568          shared with all terms, indicating need for further refactoring. */
4569 extern frame_parm_handler ns_frame_parm_handlers[];
4570 static struct redisplay_interface ns_redisplay_interface =
4572   ns_frame_parm_handlers,
4573   x_produce_glyphs,
4574   x_write_glyphs,
4575   x_insert_glyphs,
4576   x_clear_end_of_line,
4577   ns_scroll_run,
4578   ns_after_update_window_line,
4579   ns_update_window_begin,
4580   ns_update_window_end,
4581   0, /* flush_display */
4582   x_clear_window_mouse_face,
4583   x_get_glyph_overhangs,
4584   x_fix_overlapping_area,
4585   ns_draw_fringe_bitmap,
4586   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4587   0, /* destroy_fringe_bitmap */
4588   ns_compute_glyph_string_overhangs,
4589   ns_draw_glyph_string,
4590   ns_define_frame_cursor,
4591   ns_clear_frame_area,
4592   ns_draw_window_cursor,
4593   ns_draw_vertical_window_border,
4594   ns_draw_window_divider,
4595   ns_shift_glyphs_for_insert,
4596   ns_show_hourglass,
4597   ns_hide_hourglass
4601 static void
4602 ns_delete_display (struct ns_display_info *dpyinfo)
4604   /* TODO... */
4608 /* This function is called when the last frame on a display is deleted. */
4609 static void
4610 ns_delete_terminal (struct terminal *terminal)
4612   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4614   NSTRACE ("ns_delete_terminal");
4616   /* Protect against recursive calls.  delete_frame in
4617      delete_terminal calls us back when it deletes our last frame.  */
4618   if (!terminal->name)
4619     return;
4621   block_input ();
4623   x_destroy_all_bitmaps (dpyinfo);
4624   ns_delete_display (dpyinfo);
4625   unblock_input ();
4629 static struct terminal *
4630 ns_create_terminal (struct ns_display_info *dpyinfo)
4631 /* --------------------------------------------------------------------------
4632       Set up use of NS before we make the first connection.
4633    -------------------------------------------------------------------------- */
4635   struct terminal *terminal;
4637   NSTRACE ("ns_create_terminal");
4639   terminal = create_terminal (output_ns, &ns_redisplay_interface);
4641   terminal->display_info.ns = dpyinfo;
4642   dpyinfo->terminal = terminal;
4644   terminal->clear_frame_hook = ns_clear_frame;
4645   terminal->ring_bell_hook = ns_ring_bell;
4646   terminal->update_begin_hook = ns_update_begin;
4647   terminal->update_end_hook = ns_update_end;
4648   terminal->read_socket_hook = ns_read_socket;
4649   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4650   terminal->mouse_position_hook = ns_mouse_position;
4651   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4652   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4653   terminal->fullscreen_hook = ns_fullscreen_hook;
4654   terminal->menu_show_hook = ns_menu_show;
4655   terminal->popup_dialog_hook = ns_popup_dialog;
4656   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4657   terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4658   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4659   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4660   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4661   terminal->delete_frame_hook = x_destroy_window;
4662   terminal->delete_terminal_hook = ns_delete_terminal;
4663   /* Other hooks are NULL by default.  */
4665   return terminal;
4669 struct ns_display_info *
4670 ns_term_init (Lisp_Object display_name)
4671 /* --------------------------------------------------------------------------
4672      Start the Application and get things rolling.
4673    -------------------------------------------------------------------------- */
4675   struct terminal *terminal;
4676   struct ns_display_info *dpyinfo;
4677   static int ns_initialized = 0;
4678   Lisp_Object tmp;
4680   if (ns_initialized) return x_display_list;
4681   ns_initialized = 1;
4683   block_input ();
4685   NSTRACE ("ns_term_init");
4687   [outerpool release];
4688   outerpool = [[NSAutoreleasePool alloc] init];
4690   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4691   /*GSDebugAllocationActive (YES); */
4692   block_input ();
4694   baud_rate = 38400;
4695   Fset_input_interrupt_mode (Qnil);
4697   if (selfds[0] == -1)
4698     {
4699       if (emacs_pipe (selfds) != 0)
4700         {
4701           fprintf (stderr, "Failed to create pipe: %s\n",
4702                    emacs_strerror (errno));
4703           emacs_abort ();
4704         }
4706       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4707       FD_ZERO (&select_readfds);
4708       FD_ZERO (&select_writefds);
4709       pthread_mutex_init (&select_mutex, NULL);
4710     }
4712   ns_pending_files = [[NSMutableArray alloc] init];
4713   ns_pending_service_names = [[NSMutableArray alloc] init];
4714   ns_pending_service_args = [[NSMutableArray alloc] init];
4716 /* Start app and create the main menu, window, view.
4717      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4718      The view will then ask the NSApp to stop and return to Emacs. */
4719   [EmacsApp sharedApplication];
4720   if (NSApp == nil)
4721     return NULL;
4722   [NSApp setDelegate: NSApp];
4724   /* Start the select thread.  */
4725   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4726                            toTarget:NSApp
4727                          withObject:nil];
4729   /* debugging: log all notifications */
4730   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4731                                          selector: @selector (logNotification:)
4732                                              name: nil object: nil]; */
4734   dpyinfo = xzalloc (sizeof *dpyinfo);
4736   ns_initialize_display_info (dpyinfo);
4737   terminal = ns_create_terminal (dpyinfo);
4739   terminal->kboard = allocate_kboard (Qns);
4740   /* Don't let the initial kboard remain current longer than necessary.
4741      That would cause problems if a file loaded on startup tries to
4742      prompt in the mini-buffer.  */
4743   if (current_kboard == initial_kboard)
4744     current_kboard = terminal->kboard;
4745   terminal->kboard->reference_count++;
4747   dpyinfo->next = x_display_list;
4748   x_display_list = dpyinfo;
4750   dpyinfo->name_list_element = Fcons (display_name, Qnil);
4752   terminal->name = xlispstrdup (display_name);
4754   unblock_input ();
4756   if (!inhibit_x_resources)
4757     {
4758       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4759                  Qt, Qnil, NO, NO);
4760       tmp = Qnil;
4761       /* this is a standard variable */
4762       ns_default ("AppleAntiAliasingThreshold", &tmp,
4763                  make_float (10.0), make_float (6.0), YES, NO);
4764       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4765     }
4767   NSTRACE_MSG ("Colors");
4769   {
4770     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4772     if ( cl == nil )
4773       {
4774         Lisp_Object color_file, color_map, color;
4775         unsigned long c;
4776         char *name;
4778         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4779                          Fsymbol_value (intern ("data-directory")));
4781         color_map = Fx_load_color_file (color_file);
4782         if (NILP (color_map))
4783           fatal ("Could not read %s.\n", SDATA (color_file));
4785         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4786         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4787           {
4788             color = XCAR (color_map);
4789             name = SSDATA (XCAR (color));
4790             c = XINT (XCDR (color));
4791             [cl setColor:
4792                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4793                                       green: GREEN_FROM_ULONG (c) / 255.0
4794                                        blue: BLUE_FROM_ULONG (c) / 255.0
4795                                       alpha: 1.0]
4796                   forKey: [NSString stringWithUTF8String: name]];
4797           }
4798         [cl writeToFile: nil];
4799       }
4800   }
4802   NSTRACE_MSG ("Versions");
4804   {
4805 #ifdef NS_IMPL_GNUSTEP
4806     Vwindow_system_version = build_string (gnustep_base_version);
4807 #else
4808     /*PSnextrelease (128, c); */
4809     char c[DBL_BUFSIZE_BOUND];
4810     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4811     Vwindow_system_version = make_unibyte_string (c, len);
4812 #endif
4813   }
4815   delete_keyboard_wait_descriptor (0);
4817   ns_app_name = [[NSProcessInfo processInfo] processName];
4819   /* Set up OS X app menu */
4821   NSTRACE_MSG ("Menu init");
4823 #ifdef NS_IMPL_COCOA
4824   {
4825     NSMenu *appMenu;
4826     NSMenuItem *item;
4827     /* set up the application menu */
4828     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4829     [svcsMenu setAutoenablesItems: NO];
4830     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4831     [appMenu setAutoenablesItems: NO];
4832     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4833     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4835     [appMenu insertItemWithTitle: @"About Emacs"
4836                           action: @selector (orderFrontStandardAboutPanel:)
4837                    keyEquivalent: @""
4838                          atIndex: 0];
4839     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4840     [appMenu insertItemWithTitle: @"Preferences..."
4841                           action: @selector (showPreferencesWindow:)
4842                    keyEquivalent: @","
4843                          atIndex: 2];
4844     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4845     item = [appMenu insertItemWithTitle: @"Services"
4846                                  action: @selector (menuDown:)
4847                           keyEquivalent: @""
4848                                 atIndex: 4];
4849     [appMenu setSubmenu: svcsMenu forItem: item];
4850     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4851     [appMenu insertItemWithTitle: @"Hide Emacs"
4852                           action: @selector (hide:)
4853                    keyEquivalent: @"h"
4854                          atIndex: 6];
4855     item =  [appMenu insertItemWithTitle: @"Hide Others"
4856                           action: @selector (hideOtherApplications:)
4857                    keyEquivalent: @"h"
4858                          atIndex: 7];
4859     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4860     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4861     [appMenu insertItemWithTitle: @"Quit Emacs"
4862                           action: @selector (terminate:)
4863                    keyEquivalent: @"q"
4864                          atIndex: 9];
4866     item = [mainMenu insertItemWithTitle: ns_app_name
4867                                   action: @selector (menuDown:)
4868                            keyEquivalent: @""
4869                                  atIndex: 0];
4870     [mainMenu setSubmenu: appMenu forItem: item];
4871     [dockMenu insertItemWithTitle: @"New Frame"
4872                            action: @selector (newFrame:)
4873                     keyEquivalent: @""
4874                           atIndex: 0];
4876     [NSApp setMainMenu: mainMenu];
4877     [NSApp setAppleMenu: appMenu];
4878     [NSApp setServicesMenu: svcsMenu];
4879     /* Needed at least on Cocoa, to get dock menu to show windows */
4880     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4882     [[NSNotificationCenter defaultCenter]
4883       addObserver: mainMenu
4884          selector: @selector (trackingNotification:)
4885              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4886     [[NSNotificationCenter defaultCenter]
4887       addObserver: mainMenu
4888          selector: @selector (trackingNotification:)
4889              name: NSMenuDidEndTrackingNotification object: mainMenu];
4890   }
4891 #endif /* MAC OS X menu setup */
4893   /* Register our external input/output types, used for determining
4894      applicable services and also drag/drop eligibility. */
4896   NSTRACE_MSG ("Input/output types");
4898   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4899   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4900                       retain];
4901   ns_drag_types = [[NSArray arrayWithObjects:
4902                             NSStringPboardType,
4903                             NSTabularTextPboardType,
4904                             NSFilenamesPboardType,
4905                             NSURLPboardType, nil] retain];
4907   /* If fullscreen is in init/default-frame-alist, focus isn't set
4908      right for fullscreen windows, so set this.  */
4909   [NSApp activateIgnoringOtherApps:YES];
4911   NSTRACE_MSG ("Call NSApp run");
4913   [NSApp run];
4914   ns_do_open_file = YES;
4916 #ifdef NS_IMPL_GNUSTEP
4917   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4918      We must re-catch it so subprocess works.  */
4919   catch_child_signal ();
4920 #endif
4922   NSTRACE_MSG ("ns_term_init done");
4924   unblock_input ();
4926   return dpyinfo;
4930 void
4931 ns_term_shutdown (int sig)
4933   [[NSUserDefaults standardUserDefaults] synchronize];
4935   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4936   if (STRINGP (Vauto_save_list_file_name))
4937     unlink (SSDATA (Vauto_save_list_file_name));
4939   if (sig == 0 || sig == SIGTERM)
4940     {
4941       [NSApp terminate: NSApp];
4942     }
4943   else // force a stack trace to happen
4944     {
4945       emacs_abort ();
4946     }
4950 /* ==========================================================================
4952     EmacsApp implementation
4954    ========================================================================== */
4957 @implementation EmacsApp
4959 - (id)init
4961   NSTRACE ("[EmacsApp init]");
4963   if ((self = [super init]))
4964     {
4965 #ifdef NS_IMPL_COCOA
4966       self->isFirst = YES;
4967 #endif
4968 #ifdef NS_IMPL_GNUSTEP
4969       self->applicationDidFinishLaunchingCalled = NO;
4970 #endif
4971     }
4973   return self;
4976 #ifdef NS_IMPL_COCOA
4977 - (void)run
4979   NSTRACE ("[EmacsApp run]");
4981 #ifndef NSAppKitVersionNumber10_9
4982 #define NSAppKitVersionNumber10_9 1265
4983 #endif
4985     if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
4986       {
4987         [super run];
4988         return;
4989       }
4991   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4993   if (isFirst) [self finishLaunching];
4994   isFirst = NO;
4996   shouldKeepRunning = YES;
4997   do
4998     {
4999       [pool release];
5000       pool = [[NSAutoreleasePool alloc] init];
5002       NSEvent *event =
5003         [self nextEventMatchingMask:NSAnyEventMask
5004                           untilDate:[NSDate distantFuture]
5005                              inMode:NSDefaultRunLoopMode
5006                             dequeue:YES];
5008       [self sendEvent:event];
5009       [self updateWindows];
5010     } while (shouldKeepRunning);
5012   [pool release];
5015 - (void)stop: (id)sender
5017   NSTRACE ("[EmacsApp stop:]");
5019     shouldKeepRunning = NO;
5020     // Stop possible dialog also.  Noop if no dialog present.
5021     // The file dialog still leaks 7k - 10k on 10.9 though.
5022     [super stop:sender];
5024 #endif /* NS_IMPL_COCOA */
5026 - (void)logNotification: (NSNotification *)notification
5028   NSTRACE ("[EmacsApp logNotification:]");
5030   const char *name = [[notification name] UTF8String];
5031   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5032       && !strstr (name, "WindowNumber"))
5033     NSLog (@"notification: '%@'", [notification name]);
5037 - (void)sendEvent: (NSEvent *)theEvent
5038 /* --------------------------------------------------------------------------
5039      Called when NSApp is running for each event received.  Used to stop
5040      the loop when we choose, since there's no way to just run one iteration.
5041    -------------------------------------------------------------------------- */
5043   int type = [theEvent type];
5044   NSWindow *window = [theEvent window];
5046   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5047   NSTRACE_MSG ("Type: %d", type);
5049 #ifdef NS_IMPL_GNUSTEP
5050   // Keyboard events aren't propagated to file dialogs for some reason.
5051   if ([NSApp modalWindow] != nil &&
5052       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
5053     {
5054       [[NSApp modalWindow] sendEvent: theEvent];
5055       return;
5056     }
5057 #endif
5059   if (represented_filename != nil && represented_frame)
5060     {
5061       NSString *fstr = represented_filename;
5062       NSView *view = FRAME_NS_VIEW (represented_frame);
5063 #ifdef NS_IMPL_COCOA
5064       /* work around a bug observed on 10.3 and later where
5065          setTitleWithRepresentedFilename does not clear out previous state
5066          if given filename does not exist */
5067       if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5068         [[view window] setRepresentedFilename: @""];
5069 #endif
5070       [[view window] setRepresentedFilename: fstr];
5071       [represented_filename release];
5072       represented_filename = nil;
5073       represented_frame = NULL;
5074     }
5076   if (type == NSApplicationDefined)
5077     {
5078       switch ([theEvent data2])
5079         {
5080 #ifdef NS_IMPL_COCOA
5081         case NSAPP_DATA2_RUNASSCRIPT:
5082           ns_run_ascript ();
5083           [self stop: self];
5084           return;
5085 #endif
5086         case NSAPP_DATA2_RUNFILEDIALOG:
5087           ns_run_file_dialog ();
5088           [self stop: self];
5089           return;
5090         }
5091     }
5093   if (type == NSCursorUpdate && window == nil)
5094     {
5095       fprintf (stderr, "Dropping external cursor update event.\n");
5096       return;
5097     }
5099   if (type == NSApplicationDefined)
5100     {
5101       /* Events posted by ns_send_appdefined interrupt the run loop here.
5102          But, if a modal window is up, an appdefined can still come through,
5103          (e.g., from a makeKeyWindow event) but stopping self also stops the
5104          modal loop. Just defer it until later. */
5105       if ([NSApp modalWindow] == nil)
5106         {
5107           last_appdefined_event_data = [theEvent data1];
5108           [self stop: self];
5109         }
5110       else
5111         {
5112           send_appdefined = YES;
5113         }
5114     }
5117 #ifdef NS_IMPL_COCOA
5118   /* If no dialog and none of our frames have focus and it is a move, skip it.
5119      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
5120      such as Wifi, sound, date or similar.
5121      This prevents "spooky" highlighting in the frame under the menu.  */
5122   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
5123     {
5124       struct ns_display_info *di;
5125       BOOL has_focus = NO;
5126       for (di = x_display_list; ! has_focus && di; di = di->next)
5127         has_focus = di->x_focus_frame != 0;
5128       if (! has_focus)
5129         return;
5130     }
5131 #endif
5133   NSTRACE_UNSILENCE();
5135   [super sendEvent: theEvent];
5139 - (void)showPreferencesWindow: (id)sender
5141   struct frame *emacsframe = SELECTED_FRAME ();
5142   NSEvent *theEvent = [NSApp currentEvent];
5144   if (!emacs_event)
5145     return;
5146   emacs_event->kind = NS_NONKEY_EVENT;
5147   emacs_event->code = KEY_NS_SHOW_PREFS;
5148   emacs_event->modifiers = 0;
5149   EV_TRAILER (theEvent);
5153 - (void)newFrame: (id)sender
5155   NSTRACE ("[EmacsApp newFrame:]");
5157   struct frame *emacsframe = SELECTED_FRAME ();
5158   NSEvent *theEvent = [NSApp currentEvent];
5160   if (!emacs_event)
5161     return;
5162   emacs_event->kind = NS_NONKEY_EVENT;
5163   emacs_event->code = KEY_NS_NEW_FRAME;
5164   emacs_event->modifiers = 0;
5165   EV_TRAILER (theEvent);
5169 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5170 - (BOOL) openFile: (NSString *)fileName
5172   NSTRACE ("[EmacsApp openFile:]");
5174   struct frame *emacsframe = SELECTED_FRAME ();
5175   NSEvent *theEvent = [NSApp currentEvent];
5177   if (!emacs_event)
5178     return NO;
5180   emacs_event->kind = NS_NONKEY_EVENT;
5181   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5182   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5183   ns_input_line = Qnil; /* can be start or cons start,end */
5184   emacs_event->modifiers =0;
5185   EV_TRAILER (theEvent);
5187   return YES;
5191 /* **************************************************************************
5193       EmacsApp delegate implementation
5195    ************************************************************************** */
5197 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5198 /* --------------------------------------------------------------------------
5199      When application is loaded, terminate event loop in ns_term_init
5200    -------------------------------------------------------------------------- */
5202   NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5204 #ifdef NS_IMPL_GNUSTEP
5205   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5206 #endif
5207   [NSApp setServicesProvider: NSApp];
5209   [self antialiasThresholdDidChange:nil];
5210 #ifdef NS_IMPL_COCOA
5211   [[NSNotificationCenter defaultCenter]
5212     addObserver:self
5213        selector:@selector(antialiasThresholdDidChange:)
5214            name:NSAntialiasThresholdChangedNotification
5215          object:nil];
5216 #endif
5218   ns_send_appdefined (-2);
5221 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5223 #ifdef NS_IMPL_COCOA
5224   macfont_update_antialias_threshold ();
5225 #endif
5229 /* Termination sequences:
5230     C-x C-c:
5231     Cmd-Q:
5232     MenuBar | File | Exit:
5233     Select Quit from App menubar:
5234         -terminate
5235         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5236         ns_term_shutdown()
5238     Select Quit from Dock menu:
5239     Logout attempt:
5240         -appShouldTerminate
5241           Cancel -> Nothing else
5242           Accept ->
5244           -terminate
5245           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5246           ns_term_shutdown()
5250 - (void) terminate: (id)sender
5252   NSTRACE ("[EmacsApp terminate:]");
5254   struct frame *emacsframe = SELECTED_FRAME ();
5256   if (!emacs_event)
5257     return;
5259   emacs_event->kind = NS_NONKEY_EVENT;
5260   emacs_event->code = KEY_NS_POWER_OFF;
5261   emacs_event->arg = Qt; /* mark as non-key event */
5262   EV_TRAILER ((id)nil);
5265 static bool
5266 runAlertPanel(NSString *title,
5267               NSString *msgFormat,
5268               NSString *defaultButton,
5269               NSString *alternateButton)
5271 #if !defined (NS_IMPL_COCOA) || \
5272   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
5273   return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5274     == NSAlertDefaultReturn;
5275 #else
5276   NSAlert *alert = [[NSAlert alloc] init];
5277   [alert setAlertStyle: NSCriticalAlertStyle];
5278   [alert setMessageText: msgFormat];
5279   [alert addButtonWithTitle: defaultButton];
5280   [alert addButtonWithTitle: alternateButton];
5281   NSInteger ret = [alert runModal];
5282   [alert release];
5283   return ret == NSAlertFirstButtonReturn;
5284 #endif
5288 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5290   NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5292   bool ret;
5294   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
5295     return NSTerminateNow;
5297     ret = runAlertPanel(ns_app_name,
5298                         @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
5299                         @"Save Buffers and Exit", @"Cancel");
5301     if (ret)
5302         return NSTerminateNow;
5303     else
5304         return NSTerminateCancel;
5305     return NSTerminateNow;  /* just in case */
5308 static int
5309 not_in_argv (NSString *arg)
5311   int k;
5312   const char *a = [arg UTF8String];
5313   for (k = 1; k < initial_argc; ++k)
5314     if (strcmp (a, initial_argv[k]) == 0) return 0;
5315   return 1;
5318 /*   Notification from the Workspace to open a file */
5319 - (BOOL)application: sender openFile: (NSString *)file
5321   if (ns_do_open_file || not_in_argv (file))
5322     [ns_pending_files addObject: file];
5323   return YES;
5327 /*   Open a file as a temporary file */
5328 - (BOOL)application: sender openTempFile: (NSString *)file
5330   if (ns_do_open_file || not_in_argv (file))
5331     [ns_pending_files addObject: file];
5332   return YES;
5336 /*   Notification from the Workspace to open a file noninteractively (?) */
5337 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5339   if (ns_do_open_file || not_in_argv (file))
5340     [ns_pending_files addObject: file];
5341   return YES;
5344 /*   Notification from the Workspace to open multiple files */
5345 - (void)application: sender openFiles: (NSArray *)fileList
5347   NSEnumerator *files = [fileList objectEnumerator];
5348   NSString *file;
5349   /* Don't open files from the command line unconditionally,
5350      Cocoa parses the command line wrong, --option value tries to open value
5351      if --option is the last option.  */
5352   while ((file = [files nextObject]) != nil)
5353     if (ns_do_open_file || not_in_argv (file))
5354       [ns_pending_files addObject: file];
5356   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5361 /* Handle dock menu requests.  */
5362 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5364   return dockMenu;
5368 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5369 - (void)applicationWillBecomeActive: (NSNotification *)notification
5371   NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5372   //ns_app_active=YES;
5375 - (void)applicationDidBecomeActive: (NSNotification *)notification
5377   NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5379 #ifdef NS_IMPL_GNUSTEP
5380   if (! applicationDidFinishLaunchingCalled)
5381     [self applicationDidFinishLaunching:notification];
5382 #endif
5383   //ns_app_active=YES;
5385   ns_update_auto_hide_menu_bar ();
5386   // No constraining takes place when the application is not active.
5387   ns_constrain_all_frames ();
5389 - (void)applicationDidResignActive: (NSNotification *)notification
5391   NSTRACE ("[EmacsApp applicationDidResignActive:]");
5393   //ns_app_active=NO;
5394   ns_send_appdefined (-1);
5399 /* ==========================================================================
5401     EmacsApp aux handlers for managing event loop
5403    ========================================================================== */
5406 - (void)timeout_handler: (NSTimer *)timedEntry
5407 /* --------------------------------------------------------------------------
5408      The timeout specified to ns_select has passed.
5409    -------------------------------------------------------------------------- */
5411   /*NSTRACE ("timeout_handler"); */
5412   ns_send_appdefined (-2);
5415 #ifdef NS_IMPL_GNUSTEP
5416 - (void)sendFromMainThread:(id)unused
5418   ns_send_appdefined (nextappdefined);
5420 #endif
5422 - (void)fd_handler:(id)unused
5423 /* --------------------------------------------------------------------------
5424      Check data waiting on file descriptors and terminate if so
5425    -------------------------------------------------------------------------- */
5427   int result;
5428   int waiting = 1, nfds;
5429   char c;
5431   fd_set readfds, writefds, *wfds;
5432   struct timespec timeout, *tmo;
5433   NSAutoreleasePool *pool = nil;
5435   /* NSTRACE ("fd_handler"); */
5437   for (;;)
5438     {
5439       [pool release];
5440       pool = [[NSAutoreleasePool alloc] init];
5442       if (waiting)
5443         {
5444           fd_set fds;
5445           FD_ZERO (&fds);
5446           FD_SET (selfds[0], &fds);
5447           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5448           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5449             waiting = 0;
5450         }
5451       else
5452         {
5453           pthread_mutex_lock (&select_mutex);
5454           nfds = select_nfds;
5456           if (select_valid & SELECT_HAVE_READ)
5457             readfds = select_readfds;
5458           else
5459             FD_ZERO (&readfds);
5461           if (select_valid & SELECT_HAVE_WRITE)
5462             {
5463               writefds = select_writefds;
5464               wfds = &writefds;
5465             }
5466           else
5467             wfds = NULL;
5468           if (select_valid & SELECT_HAVE_TMO)
5469             {
5470               timeout = select_timeout;
5471               tmo = &timeout;
5472             }
5473           else
5474             tmo = NULL;
5476           pthread_mutex_unlock (&select_mutex);
5478           FD_SET (selfds[0], &readfds);
5479           if (selfds[0] >= nfds) nfds = selfds[0]+1;
5481           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5483           if (result == 0)
5484             ns_send_appdefined (-2);
5485           else if (result > 0)
5486             {
5487               if (FD_ISSET (selfds[0], &readfds))
5488                 {
5489                   if (read (selfds[0], &c, 1) == 1 && c == 's')
5490                     waiting = 1;
5491                 }
5492               else
5493                 {
5494                   pthread_mutex_lock (&select_mutex);
5495                   if (select_valid & SELECT_HAVE_READ)
5496                     select_readfds = readfds;
5497                   if (select_valid & SELECT_HAVE_WRITE)
5498                     select_writefds = writefds;
5499                   if (select_valid & SELECT_HAVE_TMO)
5500                     select_timeout = timeout;
5501                   pthread_mutex_unlock (&select_mutex);
5503                   ns_send_appdefined (result);
5504                 }
5505             }
5506           waiting = 1;
5507         }
5508     }
5513 /* ==========================================================================
5515     Service provision
5517    ========================================================================== */
5519 /* called from system: queue for next pass through event loop */
5520 - (void)requestService: (NSPasteboard *)pboard
5521               userData: (NSString *)userData
5522                  error: (NSString **)error
5524   [ns_pending_service_names addObject: userData];
5525   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5526       SSDATA (ns_string_from_pasteboard (pboard))]];
5530 /* called from ns_read_socket to clear queue */
5531 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5533   struct frame *emacsframe = SELECTED_FRAME ();
5534   NSEvent *theEvent = [NSApp currentEvent];
5536   NSTRACE ("[EmacsApp fulfillService:withArg:]");
5538   if (!emacs_event)
5539     return NO;
5541   emacs_event->kind = NS_NONKEY_EVENT;
5542   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5543   ns_input_spi_name = build_string ([name UTF8String]);
5544   ns_input_spi_arg = build_string ([arg UTF8String]);
5545   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5546   EV_TRAILER (theEvent);
5548   return YES;
5552 @end  /* EmacsApp */
5556 /* ==========================================================================
5558     EmacsView implementation
5560    ========================================================================== */
5563 @implementation EmacsView
5565 /* needed to inform when window closed from LISP */
5566 - (void) setWindowClosing: (BOOL)closing
5568   NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5570   windowClosing = closing;
5574 - (void)dealloc
5576   NSTRACE ("[EmacsView dealloc]");
5577   [toolbar release];
5578   if (fs_state == FULLSCREEN_BOTH)
5579     [nonfs_window release];
5580   [super dealloc];
5584 /* called on font panel selection */
5585 - (void)changeFont: (id)sender
5587   NSEvent *e = [[self window] currentEvent];
5588   struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5589   struct font *font = face->font;
5590   id newFont;
5591   CGFloat size;
5592   NSFont *nsfont;
5594   NSTRACE ("[EmacsView changeFont:]");
5596   if (!emacs_event)
5597     return;
5599 #ifdef NS_IMPL_GNUSTEP
5600   nsfont = ((struct nsfont_info *)font)->nsfont;
5601 #endif
5602 #ifdef NS_IMPL_COCOA
5603   nsfont = (NSFont *) macfont_get_nsctfont (font);
5604 #endif
5606   if ((newFont = [sender convertFont: nsfont]))
5607     {
5608       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5610       emacs_event->kind = NS_NONKEY_EVENT;
5611       emacs_event->modifiers = 0;
5612       emacs_event->code = KEY_NS_CHANGE_FONT;
5614       size = [newFont pointSize];
5615       ns_input_fontsize = make_number (lrint (size));
5616       ns_input_font = build_string ([[newFont familyName] UTF8String]);
5617       EV_TRAILER (e);
5618     }
5622 - (BOOL)acceptsFirstResponder
5624   NSTRACE ("[EmacsView acceptsFirstResponder]");
5625   return YES;
5629 - (void)resetCursorRects
5631   NSRect visible = [self visibleRect];
5632   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5633   NSTRACE ("[EmacsView resetCursorRects]");
5635   if (currentCursor == nil)
5636     currentCursor = [NSCursor arrowCursor];
5638   if (!NSIsEmptyRect (visible))
5639     [self addCursorRect: visible cursor: currentCursor];
5640   [currentCursor setOnMouseEntered: YES];
5645 /*****************************************************************************/
5646 /* Keyboard handling. */
5647 #define NS_KEYLOG 0
5649 - (void)keyDown: (NSEvent *)theEvent
5651   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5652   int code;
5653   unsigned fnKeysym = 0;
5654   static NSMutableArray *nsEvArray;
5655   int left_is_none;
5656   unsigned int flags = [theEvent modifierFlags];
5658   NSTRACE ("[EmacsView keyDown:]");
5660   /* Rhapsody and OS X give up and down events for the arrow keys */
5661   if (ns_fake_keydown == YES)
5662     ns_fake_keydown = NO;
5663   else if ([theEvent type] != NSKeyDown)
5664     return;
5666   if (!emacs_event)
5667     return;
5669  if (![[self window] isKeyWindow]
5670      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5671      /* we must avoid an infinite loop here. */
5672      && (EmacsView *)[[theEvent window] delegate] != self)
5673    {
5674      /* XXX: There is an occasional condition in which, when Emacs display
5675          updates a different frame from the current one, and temporarily
5676          selects it, then processes some interrupt-driven input
5677          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5678          for some reason that window has its first responder set to the NSView
5679          most recently updated (I guess), which is not the correct one. */
5680      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5681      return;
5682    }
5684   if (nsEvArray == nil)
5685     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5687   [NSCursor setHiddenUntilMouseMoves: YES];
5689   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5690     {
5691       clear_mouse_face (hlinfo);
5692       hlinfo->mouse_face_hidden = 1;
5693     }
5695   if (!processingCompose)
5696     {
5697       /* When using screen sharing, no left or right information is sent,
5698          so use Left key in those cases.  */
5699       int is_left_key, is_right_key;
5701       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5702         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5704       /* (Carbon way: [theEvent keyCode]) */
5706       /* is it a "function key"? */
5707       /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5708          flag set (this is probably a bug in the OS).
5709       */
5710       if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5711         {
5712           fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5713         }
5714       if (fnKeysym == 0)
5715         {
5716           fnKeysym = ns_convert_key (code);
5717         }
5719       if (fnKeysym)
5720         {
5721           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5722              because Emacs treats Delete and KP-Delete same (in simple.el). */
5723           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5724 #ifdef NS_IMPL_GNUSTEP
5725               /*  GNUstep uses incompatible keycodes, even for those that are
5726                   supposed to be hardware independent.  Just check for delete.
5727                   Keypad delete does not have keysym 0xFFFF.
5728                   See http://savannah.gnu.org/bugs/?25395
5729               */
5730               || (fnKeysym == 0xFFFF && code == 127)
5731 #endif
5732             )
5733             code = 0xFF08; /* backspace */
5734           else
5735             code = fnKeysym;
5736         }
5738       /* are there modifiers? */
5739       emacs_event->modifiers = 0;
5741       if (flags & NSHelpKeyMask)
5742           emacs_event->modifiers |= hyper_modifier;
5744       if (flags & NSShiftKeyMask)
5745         emacs_event->modifiers |= shift_modifier;
5747       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5748       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5749         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5751       if (is_right_key)
5752         emacs_event->modifiers |= parse_solitary_modifier
5753           (EQ (ns_right_command_modifier, Qleft)
5754            ? ns_command_modifier
5755            : ns_right_command_modifier);
5757       if (is_left_key)
5758         {
5759           emacs_event->modifiers |= parse_solitary_modifier
5760             (ns_command_modifier);
5762           /* if super (default), take input manager's word so things like
5763              dvorak / qwerty layout work */
5764           if (EQ (ns_command_modifier, Qsuper)
5765               && !fnKeysym
5766               && [[theEvent characters] length] != 0)
5767             {
5768               /* XXX: the code we get will be unshifted, so if we have
5769                  a shift modifier, must convert ourselves */
5770               if (!(flags & NSShiftKeyMask))
5771                 code = [[theEvent characters] characterAtIndex: 0];
5772 #if 0
5773               /* this is ugly and also requires linking w/Carbon framework
5774                  (for LMGetKbdType) so for now leave this rare (?) case
5775                  undealt with.. in future look into CGEvent methods */
5776               else
5777                 {
5778                   long smv = GetScriptManagerVariable (smKeyScript);
5779                   Handle uchrHandle = GetResource
5780                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5781                   UInt32 dummy = 0;
5782                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5783                                  [[theEvent characters] characterAtIndex: 0],
5784                                  kUCKeyActionDisplay,
5785                                  (flags & ~NSCommandKeyMask) >> 8,
5786                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5787                                  &dummy, 1, &dummy, &code);
5788                   code &= 0xFF;
5789                 }
5790 #endif
5791             }
5792         }
5794       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5795       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5796         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5798       if (is_right_key)
5799           emacs_event->modifiers |= parse_solitary_modifier
5800               (EQ (ns_right_control_modifier, Qleft)
5801                ? ns_control_modifier
5802                : ns_right_control_modifier);
5804       if (is_left_key)
5805         emacs_event->modifiers |= parse_solitary_modifier
5806           (ns_control_modifier);
5808       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5809           emacs_event->modifiers |=
5810             parse_solitary_modifier (ns_function_modifier);
5812       left_is_none = NILP (ns_alternate_modifier)
5813         || EQ (ns_alternate_modifier, Qnone);
5815       is_right_key = (flags & NSRightAlternateKeyMask)
5816         == NSRightAlternateKeyMask;
5817       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5818         || (! is_right_key
5819             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5821       if (is_right_key)
5822         {
5823           if ((NILP (ns_right_alternate_modifier)
5824                || EQ (ns_right_alternate_modifier, Qnone)
5825                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5826               && !fnKeysym)
5827             {   /* accept pre-interp alt comb */
5828               if ([[theEvent characters] length] > 0)
5829                 code = [[theEvent characters] characterAtIndex: 0];
5830               /*HACK: clear lone shift modifier to stop next if from firing */
5831               if (emacs_event->modifiers == shift_modifier)
5832                 emacs_event->modifiers = 0;
5833             }
5834           else
5835             emacs_event->modifiers |= parse_solitary_modifier
5836               (EQ (ns_right_alternate_modifier, Qleft)
5837                ? ns_alternate_modifier
5838                : ns_right_alternate_modifier);
5839         }
5841       if (is_left_key) /* default = meta */
5842         {
5843           if (left_is_none && !fnKeysym)
5844             {   /* accept pre-interp alt comb */
5845               if ([[theEvent characters] length] > 0)
5846                 code = [[theEvent characters] characterAtIndex: 0];
5847               /*HACK: clear lone shift modifier to stop next if from firing */
5848               if (emacs_event->modifiers == shift_modifier)
5849                 emacs_event->modifiers = 0;
5850             }
5851           else
5852               emacs_event->modifiers |=
5853                 parse_solitary_modifier (ns_alternate_modifier);
5854         }
5856   if (NS_KEYLOG)
5857     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5858              code, fnKeysym, flags, emacs_event->modifiers);
5860       /* if it was a function key or had modifiers, pass it directly to emacs */
5861       if (fnKeysym || (emacs_event->modifiers
5862                        && (emacs_event->modifiers != shift_modifier)
5863                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5864 /*[[theEvent characters] length] */
5865         {
5866           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5867           if (code < 0x20)
5868             code |= (1<<28)|(3<<16);
5869           else if (code == 0x7f)
5870             code |= (1<<28)|(3<<16);
5871           else if (!fnKeysym)
5872             emacs_event->kind = code > 0xFF
5873               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5875           emacs_event->code = code;
5876           EV_TRAILER (theEvent);
5877           processingCompose = NO;
5878           return;
5879         }
5880     }
5883   if (NS_KEYLOG && !processingCompose)
5884     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5886   processingCompose = YES;
5887   [nsEvArray addObject: theEvent];
5888   [self interpretKeyEvents: nsEvArray];
5889   [nsEvArray removeObject: theEvent];
5893 #ifdef NS_IMPL_COCOA
5894 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5895    decided not to send key-down for.
5896    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5897    This only applies on Tiger and earlier.
5898    If it matches one of these, send it on to keyDown. */
5899 -(void)keyUp: (NSEvent *)theEvent
5901   int flags = [theEvent modifierFlags];
5902   int code = [theEvent keyCode];
5904   NSTRACE ("[EmacsView keyUp:]");
5906   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5907       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5908     {
5909       if (NS_KEYLOG)
5910         fprintf (stderr, "keyUp: passed test");
5911       ns_fake_keydown = YES;
5912       [self keyDown: theEvent];
5913     }
5915 #endif
5918 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5921 /* <NSTextInput>: called when done composing;
5922    NOTE: also called when we delete over working text, followed immed.
5923          by doCommandBySelector: deleteBackward: */
5924 - (void)insertText: (id)aString
5926   int code;
5927   int len = [(NSString *)aString length];
5928   int i;
5930   NSTRACE ("[EmacsView insertText:]");
5932   if (NS_KEYLOG)
5933     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5934   processingCompose = NO;
5936   if (!emacs_event)
5937     return;
5939   /* first, clear any working text */
5940   if (workingText != nil)
5941     [self deleteWorkingText];
5943   /* now insert the string as keystrokes */
5944   for (i =0; i<len; i++)
5945     {
5946       code = [aString characterAtIndex: i];
5947       /* TODO: still need this? */
5948       if (code == 0x2DC)
5949         code = '~'; /* 0x7E */
5950       if (code != 32) /* Space */
5951         emacs_event->modifiers = 0;
5952       emacs_event->kind
5953         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5954       emacs_event->code = code;
5955       EV_TRAILER ((id)nil);
5956     }
5960 /* <NSTextInput>: inserts display of composing characters */
5961 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5963   NSString *str = [aString respondsToSelector: @selector (string)] ?
5964     [aString string] : aString;
5966   NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
5968   if (NS_KEYLOG)
5969     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5970            str, (unsigned long)[str length],
5971            (unsigned long)selRange.length,
5972            (unsigned long)selRange.location);
5974   if (workingText != nil)
5975     [self deleteWorkingText];
5976   if ([str length] == 0)
5977     return;
5979   if (!emacs_event)
5980     return;
5982   processingCompose = YES;
5983   workingText = [str copy];
5984   ns_working_text = build_string ([workingText UTF8String]);
5986   emacs_event->kind = NS_TEXT_EVENT;
5987   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5988   EV_TRAILER ((id)nil);
5992 /* delete display of composing characters [not in <NSTextInput>] */
5993 - (void)deleteWorkingText
5995   NSTRACE ("[EmacsView deleteWorkingText]");
5997   if (workingText == nil)
5998     return;
5999   if (NS_KEYLOG)
6000     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6001   [workingText release];
6002   workingText = nil;
6003   processingCompose = NO;
6005   if (!emacs_event)
6006     return;
6008   emacs_event->kind = NS_TEXT_EVENT;
6009   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6010   EV_TRAILER ((id)nil);
6014 - (BOOL)hasMarkedText
6016   NSTRACE ("[EmacsView hasMarkedText]");
6018   return workingText != nil;
6022 - (NSRange)markedRange
6024   NSTRACE ("[EmacsView markedRange]");
6026   NSRange rng = workingText != nil
6027     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6028   if (NS_KEYLOG)
6029     NSLog (@"markedRange request");
6030   return rng;
6034 - (void)unmarkText
6036   NSTRACE ("[EmacsView unmarkText]");
6038   if (NS_KEYLOG)
6039     NSLog (@"unmark (accept) text");
6040   [self deleteWorkingText];
6041   processingCompose = NO;
6045 /* used to position char selection windows, etc. */
6046 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6048   NSRect rect;
6049   NSPoint pt;
6050   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6052   NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6054   if (NS_KEYLOG)
6055     NSLog (@"firstRectForCharRange request");
6057   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6058   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6059   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6060   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6061                                        +FRAME_LINE_HEIGHT (emacsframe));
6063   pt = [self convertPoint: pt toView: nil];
6064   pt = [[self window] convertBaseToScreen: pt];
6065   rect.origin = pt;
6066   return rect;
6070 - (NSInteger)conversationIdentifier
6072   return (NSInteger)self;
6076 - (void)doCommandBySelector: (SEL)aSelector
6078   NSTRACE ("[EmacsView doCommandBySelector:]");
6080   if (NS_KEYLOG)
6081     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6083   processingCompose = NO;
6084   if (aSelector == @selector (deleteBackward:))
6085     {
6086       /* happens when user backspaces over an ongoing composition:
6087          throw a 'delete' into the event queue */
6088       if (!emacs_event)
6089         return;
6090       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6091       emacs_event->code = 0xFF08;
6092       EV_TRAILER ((id)nil);
6093     }
6096 - (NSArray *)validAttributesForMarkedText
6098   static NSArray *arr = nil;
6099   if (arr == nil) arr = [NSArray new];
6100  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6101   return arr;
6104 - (NSRange)selectedRange
6106   if (NS_KEYLOG)
6107     NSLog (@"selectedRange request");
6108   return NSMakeRange (NSNotFound, 0);
6111 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6112     GNUSTEP_GUI_MINOR_VERSION > 22
6113 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6114 #else
6115 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6116 #endif
6118   if (NS_KEYLOG)
6119     NSLog (@"characterIndexForPoint request");
6120   return 0;
6123 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6125   static NSAttributedString *str = nil;
6126   if (str == nil) str = [NSAttributedString new];
6127   if (NS_KEYLOG)
6128     NSLog (@"attributedSubstringFromRange request");
6129   return str;
6132 /* End <NSTextInput> impl. */
6133 /*****************************************************************************/
6136 /* This is what happens when the user presses a mouse button.  */
6137 - (void)mouseDown: (NSEvent *)theEvent
6139   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6140   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6142   NSTRACE ("[EmacsView mouseDown:]");
6144   [self deleteWorkingText];
6146   if (!emacs_event)
6147     return;
6149   dpyinfo->last_mouse_frame = emacsframe;
6150   /* appears to be needed to prevent spurious movement events generated on
6151      button clicks */
6152   emacsframe->mouse_moved = 0;
6154   if ([theEvent type] == NSScrollWheel)
6155     {
6156       CGFloat delta = [theEvent deltaY];
6157       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6158       if (delta == 0)
6159         {
6160           delta = [theEvent deltaX];
6161           if (delta == 0)
6162             {
6163               NSTRACE_MSG ("deltaIsZero");
6164               return;
6165             }
6166           emacs_event->kind = HORIZ_WHEEL_EVENT;
6167         }
6168       else
6169         emacs_event->kind = WHEEL_EVENT;
6171       emacs_event->code = 0;
6172       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6173         ((delta > 0) ? up_modifier : down_modifier);
6174     }
6175   else
6176     {
6177       emacs_event->kind = MOUSE_CLICK_EVENT;
6178       emacs_event->code = EV_BUTTON (theEvent);
6179       emacs_event->modifiers = EV_MODIFIERS (theEvent)
6180                              | EV_UDMODIFIERS (theEvent);
6181     }
6182   XSETINT (emacs_event->x, lrint (p.x));
6183   XSETINT (emacs_event->y, lrint (p.y));
6184   EV_TRAILER (theEvent);
6188 - (void)rightMouseDown: (NSEvent *)theEvent
6190   NSTRACE ("[EmacsView rightMouseDown:]");
6191   [self mouseDown: theEvent];
6195 - (void)otherMouseDown: (NSEvent *)theEvent
6197   NSTRACE ("[EmacsView otherMouseDown:]");
6198   [self mouseDown: theEvent];
6202 - (void)mouseUp: (NSEvent *)theEvent
6204   NSTRACE ("[EmacsView mouseUp:]");
6205   [self mouseDown: theEvent];
6209 - (void)rightMouseUp: (NSEvent *)theEvent
6211   NSTRACE ("[EmacsView rightMouseUp:]");
6212   [self mouseDown: theEvent];
6216 - (void)otherMouseUp: (NSEvent *)theEvent
6218   NSTRACE ("[EmacsView otherMouseUp:]");
6219   [self mouseDown: theEvent];
6223 - (void) scrollWheel: (NSEvent *)theEvent
6225   NSTRACE ("[EmacsView scrollWheel:]");
6226   [self mouseDown: theEvent];
6230 /* Tell emacs the mouse has moved. */
6231 - (void)mouseMoved: (NSEvent *)e
6233   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6234   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6235   Lisp_Object frame;
6236   NSPoint pt;
6238   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6240   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6241   pt = [self convertPoint: [e locationInWindow] fromView: nil];
6242   dpyinfo->last_mouse_motion_x = pt.x;
6243   dpyinfo->last_mouse_motion_y = pt.y;
6245   /* update any mouse face */
6246   if (hlinfo->mouse_face_hidden)
6247     {
6248       hlinfo->mouse_face_hidden = 0;
6249       clear_mouse_face (hlinfo);
6250     }
6252   /* tooltip handling */
6253   previous_help_echo_string = help_echo_string;
6254   help_echo_string = Qnil;
6256   if (!NILP (Vmouse_autoselect_window))
6257     {
6258       NSTRACE_MSG ("mouse_autoselect_window");
6259       static Lisp_Object last_mouse_window;
6260       Lisp_Object window
6261         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6263       if (WINDOWP (window)
6264           && !EQ (window, last_mouse_window)
6265           && !EQ (window, selected_window)
6266           && (focus_follows_mouse
6267               || (EQ (XWINDOW (window)->frame,
6268                       XWINDOW (selected_window)->frame))))
6269         {
6270           NSTRACE_MSG ("in_window");
6271           emacs_event->kind = SELECT_WINDOW_EVENT;
6272           emacs_event->frame_or_window = window;
6273           EV_TRAILER2 (e);
6274         }
6275       /* Remember the last window where we saw the mouse.  */
6276       last_mouse_window = window;
6277     }
6279   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6280     help_echo_string = previous_help_echo_string;
6282   XSETFRAME (frame, emacsframe);
6283   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6284     {
6285       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6286          (note_mouse_highlight), which is called through the
6287          note_mouse_movement () call above */
6288       any_help_event_p = YES;
6289       gen_help_event (help_echo_string, frame, help_echo_window,
6290                       help_echo_object, help_echo_pos);
6291     }
6293   if (emacsframe->mouse_moved && send_appdefined)
6294     ns_send_appdefined (-1);
6298 - (void)mouseDragged: (NSEvent *)e
6300   NSTRACE ("[EmacsView mouseDragged:]");
6301   [self mouseMoved: e];
6305 - (void)rightMouseDragged: (NSEvent *)e
6307   NSTRACE ("[EmacsView rightMouseDragged:]");
6308   [self mouseMoved: e];
6312 - (void)otherMouseDragged: (NSEvent *)e
6314   NSTRACE ("[EmacsView otherMouseDragged:]");
6315   [self mouseMoved: e];
6319 - (BOOL)windowShouldClose: (id)sender
6321   NSEvent *e =[[self window] currentEvent];
6323   NSTRACE ("[EmacsView windowShouldClose:]");
6324   windowClosing = YES;
6325   if (!emacs_event)
6326     return NO;
6327   emacs_event->kind = DELETE_WINDOW_EVENT;
6328   emacs_event->modifiers = 0;
6329   emacs_event->code = 0;
6330   EV_TRAILER (e);
6331   /* Don't close this window, let this be done from lisp code.  */
6332   return NO;
6335 - (void) updateFrameSize: (BOOL) delay;
6337   NSWindow *window = [self window];
6338   NSRect wr = [window frame];
6339   int extra = 0;
6340   int oldc = cols, oldr = rows;
6341   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6342   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6343   int neww, newh;
6345   NSTRACE ("[EmacsView updateFrameSize:]");
6346   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6347   NSTRACE_RECT ("Original frame", wr);
6348   NSTRACE_MSG  ("Original columns: %d", cols);
6349   NSTRACE_MSG  ("Original rows: %d", rows);
6351   if (! [self isFullscreen])
6352     {
6353 #ifdef NS_IMPL_GNUSTEP
6354       // GNUstep does not always update the tool bar height.  Force it.
6355       if (toolbar && [toolbar isVisible])
6356           update_frame_tool_bar (emacsframe);
6357 #endif
6359       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6360         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6361     }
6363   if (wait_for_tool_bar)
6364     {
6365       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
6366         {
6367           NSTRACE_MSG ("Waiting for toolbar");
6368           return;
6369         }
6370       wait_for_tool_bar = NO;
6371     }
6373   neww = (int)wr.size.width - emacsframe->border_width;
6374   newh = (int)wr.size.height - extra;
6376   NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6377   NSTRACE_MSG ("tool_bar_height: %d", emacsframe->tool_bar_height);
6379   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6380   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6382   if (cols < MINWIDTH)
6383     cols = MINWIDTH;
6385   if (rows < MINHEIGHT)
6386     rows = MINHEIGHT;
6388   NSTRACE_MSG ("New columns: %d", cols);
6389   NSTRACE_MSG ("New rows: %d", rows);
6391   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6392     {
6393       NSView *view = FRAME_NS_VIEW (emacsframe);
6395       change_frame_size (emacsframe,
6396                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6397                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6398                          0, delay, 0, 1);
6399       SET_FRAME_GARBAGED (emacsframe);
6400       cancel_mouse_face (emacsframe);
6402       wr = NSMakeRect (0, 0, neww, newh);
6404       [view setFrame: wr];
6406       // to do: consider using [NSNotificationCenter postNotificationName:].
6407       [self windowDidMove: // Update top/left.
6408               [NSNotification notificationWithName:NSWindowDidMoveNotification
6409                                             object:[view window]]];
6410     }
6411   else
6412     {
6413       NSTRACE_MSG ("No change");
6414     }
6417 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6418 /* normalize frame to gridded text size */
6420   int extra = 0;
6422   NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6423            NSTRACE_ARG_SIZE (frameSize));
6424   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6425   NSTRACE_FSTYPE ("fs_state", fs_state);
6427   if (fs_state == FULLSCREEN_MAXIMIZED
6428       && (maximized_width != (int)frameSize.width
6429           || maximized_height != (int)frameSize.height))
6430     [self setFSValue: FULLSCREEN_NONE];
6431   else if (fs_state == FULLSCREEN_WIDTH
6432            && maximized_width != (int)frameSize.width)
6433     [self setFSValue: FULLSCREEN_NONE];
6434   else if (fs_state == FULLSCREEN_HEIGHT
6435            && maximized_height != (int)frameSize.height)
6436     [self setFSValue: FULLSCREEN_NONE];
6438   if (fs_state == FULLSCREEN_NONE)
6439     maximized_width = maximized_height = -1;
6441   if (! [self isFullscreen])
6442     {
6443       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6444         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6445     }
6447   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6448   if (cols < MINWIDTH)
6449     cols = MINWIDTH;
6451   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6452                                            frameSize.height - extra);
6453   if (rows < MINHEIGHT)
6454     rows = MINHEIGHT;
6455 #ifdef NS_IMPL_COCOA
6456   {
6457     /* this sets window title to have size in it; the wm does this under GS */
6458     NSRect r = [[self window] frame];
6459     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6460       {
6461         if (old_title != 0)
6462           {
6463             xfree (old_title);
6464             old_title = 0;
6465           }
6466       }
6467     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
6468       {
6469         char *size_title;
6470         NSWindow *window = [self window];
6471         if (old_title == 0)
6472           {
6473             char *t = strdup ([[[self window] title] UTF8String]);
6474             char *pos = strstr (t, "  â€”  ");
6475             if (pos)
6476               *pos = '\0';
6477             old_title = t;
6478           }
6479         size_title = xmalloc (strlen (old_title) + 40);
6480         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
6481         [window setTitle: [NSString stringWithUTF8String: size_title]];
6482         [window display];
6483         xfree (size_title);
6484       }
6485   }
6486 #endif /* NS_IMPL_COCOA */
6488   NSTRACE_MSG ("cols: %d  rows: %d", cols, rows);
6490   /* Restrict the new size to the text gird.
6492      Don't restrict the width if the user only adjusted the height, and
6493      vice versa.  (Without this, the frame would shrink, and move
6494      slightly, if the window was resized by dragging one of its
6495      borders.) */
6496   if (!frame_resize_pixelwise)
6497     {
6498       NSRect r = [[self window] frame];
6500       if (r.size.width != frameSize.width)
6501         {
6502           frameSize.width =
6503             FRAME_TEXT_COLS_TO_PIXEL_WIDTH  (emacsframe, cols);
6504         }
6506       if (r.size.height != frameSize.height)
6507         {
6508           frameSize.height =
6509             FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6510         }
6511     }
6513   NSTRACE_RETURN_SIZE (frameSize);
6515   return frameSize;
6519 - (void)windowDidResize: (NSNotification *)notification
6521   NSTRACE ("[EmacsView windowDidResize:]");
6522   if (!FRAME_LIVE_P (emacsframe))
6523     {
6524       NSTRACE_MSG ("Ignored (frame dead)");
6525       return;
6526     }
6527   if (emacsframe->output_data.ns->in_animation)
6528     {
6529       NSTRACE_MSG ("Ignored (in animation)");
6530       return;
6531     }
6533   if (! [self fsIsNative])
6534     {
6535       NSWindow *theWindow = [notification object];
6536       /* We can get notification on the non-FS window when in
6537          fullscreen mode.  */
6538       if ([self window] != theWindow) return;
6539     }
6541   NSTRACE_RECT ("frame", [[notification object] frame]);
6543 #ifdef NS_IMPL_GNUSTEP
6544   NSWindow *theWindow = [notification object];
6546    /* In GNUstep, at least currently, it's possible to get a didResize
6547       without getting a willResize.. therefore we need to act as if we got
6548       the willResize now */
6549   NSSize sz = [theWindow frame].size;
6550   sz = [self windowWillResize: theWindow toSize: sz];
6551 #endif /* NS_IMPL_GNUSTEP */
6553   if (cols > 0 && rows > 0)
6554     {
6555       [self updateFrameSize: YES];
6556     }
6558   ns_send_appdefined (-1);
6561 #ifdef NS_IMPL_COCOA
6562 - (void)viewDidEndLiveResize
6564   NSTRACE ("[EmacsView viewDidEndLiveResize]");
6566   [super viewDidEndLiveResize];
6567   if (old_title != 0)
6568     {
6569       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6570       xfree (old_title);
6571       old_title = 0;
6572     }
6573   maximizing_resize = NO;
6575 #endif /* NS_IMPL_COCOA */
6578 - (void)windowDidBecomeKey: (NSNotification *)notification
6579 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6581   [self windowDidBecomeKey];
6585 - (void)windowDidBecomeKey      /* for direct calls */
6587   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6588   struct frame *old_focus = dpyinfo->x_focus_frame;
6590   NSTRACE ("[EmacsView windowDidBecomeKey]");
6592   if (emacsframe != old_focus)
6593     dpyinfo->x_focus_frame = emacsframe;
6595   ns_frame_rehighlight (emacsframe);
6597   if (emacs_event)
6598     {
6599       emacs_event->kind = FOCUS_IN_EVENT;
6600       EV_TRAILER ((id)nil);
6601     }
6605 - (void)windowDidResignKey: (NSNotification *)notification
6606 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6608   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6609   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6610   NSTRACE ("[EmacsView windowDidResignKey:]");
6612   if (is_focus_frame)
6613     dpyinfo->x_focus_frame = 0;
6615   emacsframe->mouse_moved = 0;
6616   ns_frame_rehighlight (emacsframe);
6618   /* FIXME: for some reason needed on second and subsequent clicks away
6619             from sole-frame Emacs to get hollow box to show */
6620   if (!windowClosing && [[self window] isVisible] == YES)
6621     {
6622       x_update_cursor (emacsframe, 1);
6623       x_set_frame_alpha (emacsframe);
6624     }
6626   if (any_help_event_p)
6627     {
6628       Lisp_Object frame;
6629       XSETFRAME (frame, emacsframe);
6630       help_echo_string = Qnil;
6631       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6632     }
6634   if (emacs_event && is_focus_frame)
6635     {
6636       [self deleteWorkingText];
6637       emacs_event->kind = FOCUS_OUT_EVENT;
6638       EV_TRAILER ((id)nil);
6639     }
6643 - (void)windowWillMiniaturize: sender
6645   NSTRACE ("[EmacsView windowWillMiniaturize:]");
6649 - (void)setFrame:(NSRect)frameRect;
6651   NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
6652            NSTRACE_ARG_RECT (frameRect));
6654   [super setFrame:(NSRect)frameRect];
6658 - (BOOL)isFlipped
6660   return YES;
6664 - (BOOL)isOpaque
6666   return NO;
6670 - initFrameFromEmacs: (struct frame *)f
6672   NSRect r, wr;
6673   Lisp_Object tem;
6674   NSWindow *win;
6675   NSColor *col;
6676   NSString *name;
6678   NSTRACE ("[EmacsView initFrameFromEmacs:]");
6679   NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
6681   windowClosing = NO;
6682   processingCompose = NO;
6683   scrollbarsNeedingUpdate = 0;
6684   fs_state = FULLSCREEN_NONE;
6685   fs_before_fs = next_maximized = -1;
6686 #ifdef HAVE_NATIVE_FS
6687   fs_is_native = ns_use_native_fullscreen;
6688 #else
6689   fs_is_native = NO;
6690 #endif
6691   maximized_width = maximized_height = -1;
6692   nonfs_window = nil;
6694   ns_userRect = NSMakeRect (0, 0, 0, 0);
6695   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6696                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6697   [self initWithFrame: r];
6698   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6700   FRAME_NS_VIEW (f) = self;
6701   emacsframe = f;
6702 #ifdef NS_IMPL_COCOA
6703   old_title = 0;
6704   maximizing_resize = NO;
6705 #endif
6707   win = [[EmacsWindow alloc]
6708             initWithContentRect: r
6709                       styleMask: (NSResizableWindowMask |
6710 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6711                                   NSTitledWindowMask |
6712 #endif
6713                                   NSMiniaturizableWindowMask |
6714                                   NSClosableWindowMask)
6715                         backing: NSBackingStoreBuffered
6716                           defer: YES];
6718 #ifdef HAVE_NATIVE_FS
6719     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6720 #endif
6722   wr = [win frame];
6723   bwidth = f->border_width = wr.size.width - r.size.width;
6724   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6726   [win setAcceptsMouseMovedEvents: YES];
6727   [win setDelegate: self];
6728 #if !defined (NS_IMPL_COCOA) || \
6729   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6730   [win useOptimizedDrawing: YES];
6731 #endif
6733   [[win contentView] addSubview: self];
6735   if (ns_drag_types)
6736     [self registerForDraggedTypes: ns_drag_types];
6738   tem = f->name;
6739   name = [NSString stringWithUTF8String:
6740                    NILP (tem) ? "Emacs" : SSDATA (tem)];
6741   [win setTitle: name];
6743   /* toolbar support */
6744   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6745                          [NSString stringWithFormat: @"Emacs Frame %d",
6746                                    ns_window_num]];
6747   [win setToolbar: toolbar];
6748   [toolbar setVisible: NO];
6750   /* Don't set frame garbaged until tool bar is up to date?
6751      This avoids an extra clear and redraw (flicker) at frame creation.  */
6752   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6753   else wait_for_tool_bar = NO;
6756 #ifdef NS_IMPL_COCOA
6757   {
6758     NSButton *toggleButton;
6759   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6760   [toggleButton setTarget: self];
6761   [toggleButton setAction: @selector (toggleToolbar: )];
6762   }
6763 #endif
6764   FRAME_TOOLBAR_HEIGHT (f) = 0;
6766   tem = f->icon_name;
6767   if (!NILP (tem))
6768     [win setMiniwindowTitle:
6769            [NSString stringWithUTF8String: SSDATA (tem)]];
6771   {
6772     NSScreen *screen = [win screen];
6774     if (screen != 0)
6775       {
6776         NSPoint pt = NSMakePoint
6777           (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6778            IN_BOUND (-SCREENMAX,
6779                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX));
6781         [win setFrameTopLeftPoint: pt];
6783         NSTRACE_RECT ("new frame", [win frame]);
6784       }
6785   }
6787   [win makeFirstResponder: self];
6789   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6790                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6791   [win setBackgroundColor: col];
6792   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6793     [win setOpaque: NO];
6795 #if !defined (NS_IMPL_COCOA) || \
6796   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6797   [self allocateGState];
6798 #endif
6799   [NSApp registerServicesMenuSendTypes: ns_send_types
6800                            returnTypes: nil];
6802   ns_window_num++;
6803   return self;
6807 - (void)windowDidMove: sender
6809   NSWindow *win = [self window];
6810   NSRect r = [win frame];
6811   NSArray *screens = [NSScreen screens];
6812   NSScreen *screen = [screens objectAtIndex: 0];
6814   NSTRACE ("[EmacsView windowDidMove:]");
6816   if (!emacsframe->output_data.ns)
6817     return;
6818   if (screen != nil)
6819     {
6820       emacsframe->left_pos = r.origin.x;
6821       emacsframe->top_pos =
6822         [screen frame].size.height - (r.origin.y + r.size.height);
6823     }
6827 /* Called AFTER method below, but before our windowWillResize call there leads
6828    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
6829    location so set_window_size moves the frame. */
6830 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6832   NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
6833             NSTRACE_FMT_RETURN "YES"),
6834            NSTRACE_ARG_RECT (newFrame));
6836   emacsframe->output_data.ns->zooming = 1;
6837   return YES;
6841 /* Override to do something slightly nonstandard, but nice.  First click on
6842    zoom button will zoom vertically.  Second will zoom completely.  Third
6843    returns to original. */
6844 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6845                         defaultFrame:(NSRect)defaultFrame
6847   // TODO: Rename to "currentFrame" and assign "result" properly in
6848   // all paths.
6849   NSRect result = [sender frame];
6851   NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
6852             NSTRACE_FMT_RECT "]"),
6853            NSTRACE_ARG_RECT (defaultFrame));
6854   NSTRACE_FSTYPE ("fs_state", fs_state);
6855   NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
6856   NSTRACE_FSTYPE ("next_maximized", next_maximized);
6857   NSTRACE_RECT   ("ns_userRect", ns_userRect);
6858   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6860   if (fs_before_fs != -1) /* Entering fullscreen */
6861     {
6862       NSTRACE_MSG ("Entering fullscreen");
6863       result = defaultFrame;
6864     }
6865   else
6866     {
6867       // Save the window size and position (frame) before the resize.
6868       if (fs_state != FULLSCREEN_MAXIMIZED
6869           && fs_state != FULLSCREEN_WIDTH)
6870         {
6871           ns_userRect.size.width = result.size.width;
6872           ns_userRect.origin.x   = result.origin.x;
6873         }
6875       if (fs_state != FULLSCREEN_MAXIMIZED
6876           && fs_state != FULLSCREEN_HEIGHT)
6877         {
6878           ns_userRect.size.height = result.size.height;
6879           ns_userRect.origin.y    = result.origin.y;
6880         }
6882       NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
6884       if (next_maximized == FULLSCREEN_HEIGHT
6885           || (next_maximized == -1
6886               && abs ((int)(defaultFrame.size.height - result.size.height))
6887               > FRAME_LINE_HEIGHT (emacsframe)))
6888         {
6889           /* first click */
6890           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
6891           maximized_height = result.size.height = defaultFrame.size.height;
6892           maximized_width = -1;
6893           result.origin.y = defaultFrame.origin.y;
6894           if (ns_userRect.size.height != 0)
6895             {
6896               result.origin.x = ns_userRect.origin.x;
6897               result.size.width = ns_userRect.size.width;
6898             }
6899           [self setFSValue: FULLSCREEN_HEIGHT];
6900 #ifdef NS_IMPL_COCOA
6901           maximizing_resize = YES;
6902 #endif
6903         }
6904       else if (next_maximized == FULLSCREEN_WIDTH)
6905         {
6906           NSTRACE_MSG ("FULLSCREEN_WIDTH");
6907           maximized_width = result.size.width = defaultFrame.size.width;
6908           maximized_height = -1;
6909           result.origin.x = defaultFrame.origin.x;
6910           if (ns_userRect.size.width != 0)
6911             {
6912               result.origin.y = ns_userRect.origin.y;
6913               result.size.height = ns_userRect.size.height;
6914             }
6915           [self setFSValue: FULLSCREEN_WIDTH];
6916         }
6917       else if (next_maximized == FULLSCREEN_MAXIMIZED
6918                || (next_maximized == -1
6919                    && abs ((int)(defaultFrame.size.width - result.size.width))
6920                    > FRAME_COLUMN_WIDTH (emacsframe)))
6921         {
6922           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
6924           result = defaultFrame;  /* second click */
6925           maximized_width = result.size.width;
6926           maximized_height = result.size.height;
6927           [self setFSValue: FULLSCREEN_MAXIMIZED];
6928 #ifdef NS_IMPL_COCOA
6929           maximizing_resize = YES;
6930 #endif
6931         }
6932       else
6933         {
6934           /* restore */
6935           NSTRACE_MSG ("Restore");
6936           result = ns_userRect.size.height ? ns_userRect : result;
6937           NSTRACE_RECT ("restore (2)", result);
6938           ns_userRect = NSMakeRect (0, 0, 0, 0);
6939 #ifdef NS_IMPL_COCOA
6940           maximizing_resize = fs_state != FULLSCREEN_NONE;
6941 #endif
6942           [self setFSValue: FULLSCREEN_NONE];
6943           maximized_width = maximized_height = -1;
6944         }
6945     }
6947   if (fs_before_fs == -1) next_maximized = -1;
6949   NSTRACE_RECT   ("Final ns_userRect", ns_userRect);
6950   NSTRACE_MSG    ("Final maximized_width: %d", maximized_width);
6951   NSTRACE_MSG    ("Final maximized_height: %d", maximized_height);
6952   NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
6954   [self windowWillResize: sender toSize: result.size];
6956   NSTRACE_RETURN_RECT (result);
6958   return result;
6962 - (void)windowDidDeminiaturize: sender
6964   NSTRACE ("[EmacsView windowDidDeminiaturize:]");
6965   if (!emacsframe->output_data.ns)
6966     return;
6968   SET_FRAME_ICONIFIED (emacsframe, 0);
6969   SET_FRAME_VISIBLE (emacsframe, 1);
6970   windows_or_buffers_changed = 63;
6972   if (emacs_event)
6973     {
6974       emacs_event->kind = DEICONIFY_EVENT;
6975       EV_TRAILER ((id)nil);
6976     }
6980 - (void)windowDidExpose: sender
6982   NSTRACE ("[EmacsView windowDidExpose:]");
6983   if (!emacsframe->output_data.ns)
6984     return;
6986   SET_FRAME_VISIBLE (emacsframe, 1);
6987   SET_FRAME_GARBAGED (emacsframe);
6989   if (send_appdefined)
6990     ns_send_appdefined (-1);
6994 - (void)windowDidMiniaturize: sender
6996   NSTRACE ("[EmacsView windowDidMiniaturize:]");
6997   if (!emacsframe->output_data.ns)
6998     return;
7000   SET_FRAME_ICONIFIED (emacsframe, 1);
7001   SET_FRAME_VISIBLE (emacsframe, 0);
7003   if (emacs_event)
7004     {
7005       emacs_event->kind = ICONIFY_EVENT;
7006       EV_TRAILER ((id)nil);
7007     }
7010 #ifdef HAVE_NATIVE_FS
7011 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7012       willUseFullScreenPresentationOptions:
7013   (NSApplicationPresentationOptions)proposedOptions
7015   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7017 #endif
7019 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7021   NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7022   [self windowWillEnterFullScreen];
7024 - (void)windowWillEnterFullScreen /* provided for direct calls */
7026   NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7027   fs_before_fs = fs_state;
7030 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7032   NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7033   [self windowDidEnterFullScreen];
7036 - (void)windowDidEnterFullScreen /* provided for direct calls */
7038   NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7039   [self setFSValue: FULLSCREEN_BOTH];
7040   if (! [self fsIsNative])
7041     {
7042       [self windowDidBecomeKey];
7043       [nonfs_window orderOut:self];
7044     }
7045   else
7046     {
7047       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7048 #ifdef NS_IMPL_COCOA
7049 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
7050       unsigned val = (unsigned)[NSApp presentationOptions];
7052       // OSX 10.7 bug fix, the menu won't appear without this.
7053       // val is non-zero on other OSX versions.
7054       if (val == 0)
7055         {
7056           NSApplicationPresentationOptions options
7057             = NSApplicationPresentationAutoHideDock
7058             | NSApplicationPresentationAutoHideMenuBar
7059             | NSApplicationPresentationFullScreen
7060             | NSApplicationPresentationAutoHideToolbar;
7062           [NSApp setPresentationOptions: options];
7063         }
7064 #endif
7065 #endif
7066       [toolbar setVisible:tbar_visible];
7067     }
7070 - (void)windowWillExitFullScreen:(NSNotification *)notification
7072   NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7073   [self windowWillExitFullScreen];
7076 - (void)windowWillExitFullScreen /* provided for direct calls */
7078   NSTRACE ("[EmacsView windowWillExitFullScreen]");
7079   if (!FRAME_LIVE_P (emacsframe))
7080     {
7081       NSTRACE_MSG ("Ignored (frame dead)");
7082       return;
7083     }
7084   if (next_maximized != -1)
7085     fs_before_fs = next_maximized;
7088 - (void)windowDidExitFullScreen:(NSNotification *)notification
7090   NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7091   [self windowDidExitFullScreen];
7094 - (void)windowDidExitFullScreen /* provided for direct calls */
7096   NSTRACE ("[EmacsView windowDidExitFullScreen]");
7097   if (!FRAME_LIVE_P (emacsframe))
7098     {
7099       NSTRACE_MSG ("Ignored (frame dead)");
7100       return;
7101     }
7102   [self setFSValue: fs_before_fs];
7103   fs_before_fs = -1;
7104 #ifdef HAVE_NATIVE_FS
7105   [self updateCollectionBehavior];
7106 #endif
7107   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7108     {
7109       [toolbar setVisible:YES];
7110       update_frame_tool_bar (emacsframe);
7111       [self updateFrameSize:YES];
7112       [[self window] display];
7113     }
7114   else
7115     [toolbar setVisible:NO];
7117   if (next_maximized != -1)
7118     [[self window] performZoom:self];
7121 - (BOOL)fsIsNative
7123   return fs_is_native;
7126 - (BOOL)isFullscreen
7128   BOOL res;
7130   if (! fs_is_native)
7131     {
7132       res = (nonfs_window != nil);
7133     }
7134   else
7135     {
7136 #ifdef HAVE_NATIVE_FS
7137       res = (([[self window] styleMask] & NSFullScreenWindowMask) != 0);
7138 #else
7139       res = NO;
7140 #endif
7141     }
7143   NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7144            (int) res);
7146   return res;
7149 #ifdef HAVE_NATIVE_FS
7150 - (void)updateCollectionBehavior
7152   NSTRACE ("[EmacsView updateCollectionBehavior]");
7154   if (! [self isFullscreen])
7155     {
7156       NSWindow *win = [self window];
7157       NSWindowCollectionBehavior b = [win collectionBehavior];
7158       if (ns_use_native_fullscreen)
7159         b |= NSWindowCollectionBehaviorFullScreenPrimary;
7160       else
7161         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7163       [win setCollectionBehavior: b];
7164       fs_is_native = ns_use_native_fullscreen;
7165     }
7167 #endif
7169 - (void)toggleFullScreen: (id)sender
7171   NSWindow *w, *fw;
7172   BOOL onFirstScreen;
7173   struct frame *f;
7174   NSRect r, wr;
7175   NSColor *col;
7177   NSTRACE ("[EmacsView toggleFullScreen:]");
7179   if (fs_is_native)
7180     {
7181 #ifdef HAVE_NATIVE_FS
7182       [[self window] toggleFullScreen:sender];
7183 #endif
7184       return;
7185     }
7187   w = [self window];
7188   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7189   f = emacsframe;
7190   wr = [w frame];
7191   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7192                                  (FRAME_DEFAULT_FACE (f)),
7193                                  f);
7195   if (fs_state != FULLSCREEN_BOTH)
7196     {
7197       NSScreen *screen = [w screen];
7199 #if defined (NS_IMPL_COCOA) && \
7200   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7201       /* Hide ghost menu bar on secondary monitor? */
7202       if (! onFirstScreen)
7203         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7204 #endif
7205       /* Hide dock and menubar if we are on the primary screen.  */
7206       if (onFirstScreen)
7207         {
7208 #ifdef NS_IMPL_COCOA
7209           NSApplicationPresentationOptions options
7210             = NSApplicationPresentationAutoHideDock
7211             | NSApplicationPresentationAutoHideMenuBar;
7213           [NSApp setPresentationOptions: options];
7214 #else
7215           [NSMenu setMenuBarVisible:NO];
7216 #endif
7217         }
7219       fw = [[EmacsFSWindow alloc]
7220                        initWithContentRect:[w contentRectForFrameRect:wr]
7221                                  styleMask:NSBorderlessWindowMask
7222                                    backing:NSBackingStoreBuffered
7223                                      defer:YES
7224                                     screen:screen];
7226       [fw setContentView:[w contentView]];
7227       [fw setTitle:[w title]];
7228       [fw setDelegate:self];
7229       [fw setAcceptsMouseMovedEvents: YES];
7230 #if !defined (NS_IMPL_COCOA) || \
7231   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7232       [fw useOptimizedDrawing: YES];
7233 #endif
7234       [fw setBackgroundColor: col];
7235       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7236         [fw setOpaque: NO];
7238       f->border_width = 0;
7239       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
7240       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
7241       FRAME_TOOLBAR_HEIGHT (f) = 0;
7243       nonfs_window = w;
7245       [self windowWillEnterFullScreen];
7246       [fw makeKeyAndOrderFront:NSApp];
7247       [fw makeFirstResponder:self];
7248       [w orderOut:self];
7249       r = [fw frameRectForContentRect:[screen frame]];
7250       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7251       [self windowDidEnterFullScreen];
7252       [fw display];
7253     }
7254   else
7255     {
7256       fw = w;
7257       w = nonfs_window;
7258       nonfs_window = nil;
7260       if (onFirstScreen)
7261         {
7262 #ifdef NS_IMPL_COCOA
7263           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7264 #else
7265           [NSMenu setMenuBarVisible:YES];
7266 #endif
7267         }
7269       [w setContentView:[fw contentView]];
7270       [w setBackgroundColor: col];
7271       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7272         [w setOpaque: NO];
7274       f->border_width = bwidth;
7275       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
7276       if (FRAME_EXTERNAL_TOOL_BAR (f))
7277         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
7279       // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7281       [self windowWillExitFullScreen];
7282       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7283       [fw close];
7284       [w makeKeyAndOrderFront:NSApp];
7285       [self windowDidExitFullScreen];
7286       [self updateFrameSize:YES];
7287     }
7290 - (void)handleFS
7292   NSTRACE ("[EmacsView handleFS]");
7294   if (fs_state != emacsframe->want_fullscreen)
7295     {
7296       if (fs_state == FULLSCREEN_BOTH)
7297         {
7298           NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7299           [self toggleFullScreen:self];
7300         }
7302       switch (emacsframe->want_fullscreen)
7303         {
7304         case FULLSCREEN_BOTH:
7305           NSTRACE_MSG ("FULLSCREEN_BOTH");
7306           [self toggleFullScreen:self];
7307           break;
7308         case FULLSCREEN_WIDTH:
7309           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7310           next_maximized = FULLSCREEN_WIDTH;
7311           if (fs_state != FULLSCREEN_BOTH)
7312             [[self window] performZoom:self];
7313           break;
7314         case FULLSCREEN_HEIGHT:
7315           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7316           next_maximized = FULLSCREEN_HEIGHT;
7317           if (fs_state != FULLSCREEN_BOTH)
7318             [[self window] performZoom:self];
7319           break;
7320         case FULLSCREEN_MAXIMIZED:
7321           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7322           next_maximized = FULLSCREEN_MAXIMIZED;
7323           if (fs_state != FULLSCREEN_BOTH)
7324             [[self window] performZoom:self];
7325           break;
7326         case FULLSCREEN_NONE:
7327           NSTRACE_MSG ("FULLSCREEN_NONE");
7328           if (fs_state != FULLSCREEN_BOTH)
7329             {
7330               next_maximized = FULLSCREEN_NONE;
7331               [[self window] performZoom:self];
7332             }
7333           break;
7334         }
7336       emacsframe->want_fullscreen = FULLSCREEN_NONE;
7337     }
7341 - (void) setFSValue: (int)value
7343   NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7344            NSTRACE_ARG_FSTYPE(value));
7346   Lisp_Object lval = Qnil;
7347   switch (value)
7348     {
7349     case FULLSCREEN_BOTH:
7350       lval = Qfullboth;
7351       break;
7352     case FULLSCREEN_WIDTH:
7353       lval = Qfullwidth;
7354       break;
7355     case FULLSCREEN_HEIGHT:
7356       lval = Qfullheight;
7357       break;
7358     case FULLSCREEN_MAXIMIZED:
7359       lval = Qmaximized;
7360       break;
7361     }
7362   store_frame_param (emacsframe, Qfullscreen, lval);
7363   fs_state = value;
7366 - (void)mouseEntered: (NSEvent *)theEvent
7368   NSTRACE ("[EmacsView mouseEntered:]");
7369   if (emacsframe)
7370     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7371       = EV_TIMESTAMP (theEvent);
7375 - (void)mouseExited: (NSEvent *)theEvent
7377   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7379   NSTRACE ("[EmacsView mouseExited:]");
7381   if (!hlinfo)
7382     return;
7384   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7385     = EV_TIMESTAMP (theEvent);
7387   if (emacsframe == hlinfo->mouse_face_mouse_frame)
7388     {
7389       clear_mouse_face (hlinfo);
7390       hlinfo->mouse_face_mouse_frame = 0;
7391     }
7395 - menuDown: sender
7397   NSTRACE ("[EmacsView menuDown:]");
7398   if (context_menu_value == -1)
7399     context_menu_value = [sender tag];
7400   else
7401     {
7402       NSInteger tag = [sender tag];
7403       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7404                                     emacsframe->menu_bar_vector,
7405                                     (void *)tag);
7406     }
7408   ns_send_appdefined (-1);
7409   return self;
7413 - (EmacsToolbar *)toolbar
7415   return toolbar;
7419 /* this gets called on toolbar button click */
7420 - toolbarClicked: (id)item
7422   NSEvent *theEvent;
7423   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7425   NSTRACE ("[EmacsView toolbarClicked:]");
7427   if (!emacs_event)
7428     return self;
7430   /* send first event (for some reason two needed) */
7431   theEvent = [[self window] currentEvent];
7432   emacs_event->kind = TOOL_BAR_EVENT;
7433   XSETFRAME (emacs_event->arg, emacsframe);
7434   EV_TRAILER (theEvent);
7436   emacs_event->kind = TOOL_BAR_EVENT;
7437 /*   XSETINT (emacs_event->code, 0); */
7438   emacs_event->arg = AREF (emacsframe->tool_bar_items,
7439                            idx + TOOL_BAR_ITEM_KEY);
7440   emacs_event->modifiers = EV_MODIFIERS (theEvent);
7441   EV_TRAILER (theEvent);
7442   return self;
7446 - toggleToolbar: (id)sender
7448   NSTRACE ("[EmacsView toggleToolbar:]");
7450   if (!emacs_event)
7451     return self;
7453   emacs_event->kind = NS_NONKEY_EVENT;
7454   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7455   EV_TRAILER ((id)nil);
7456   return self;
7460 - (void)drawRect: (NSRect)rect
7462   int x = NSMinX (rect), y = NSMinY (rect);
7463   int width = NSWidth (rect), height = NSHeight (rect);
7465   NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7466            NSTRACE_ARG_RECT(rect));
7468   if (!emacsframe || !emacsframe->output_data.ns)
7469     return;
7471   ns_clear_frame_area (emacsframe, x, y, width, height);
7472   block_input ();
7473   expose_frame (emacsframe, x, y, width, height);
7474   unblock_input ();
7476   /*
7477     drawRect: may be called (at least in OS X 10.5) for invisible
7478     views as well for some reason.  Thus, do not infer visibility
7479     here.
7481     emacsframe->async_visible = 1;
7482     emacsframe->async_iconified = 0;
7483   */
7487 /* NSDraggingDestination protocol methods.  Actually this is not really a
7488    protocol, but a category of Object.  O well...  */
7490 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7492   NSTRACE ("[EmacsView draggingEntered:]");
7493   return NSDragOperationGeneric;
7497 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7499   return YES;
7503 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7505   id pb;
7506   int x, y;
7507   NSString *type;
7508   NSEvent *theEvent = [[self window] currentEvent];
7509   NSPoint position;
7510   NSDragOperation op = [sender draggingSourceOperationMask];
7511   int modifiers = 0;
7513   NSTRACE ("[EmacsView performDragOperation:]");
7515   if (!emacs_event)
7516     return NO;
7518   position = [self convertPoint: [sender draggingLocation] fromView: nil];
7519   x = lrint (position.x);  y = lrint (position.y);
7521   pb = [sender draggingPasteboard];
7522   type = [pb availableTypeFromArray: ns_drag_types];
7524   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7525       // URL drags contain all operations (0xf), don't allow all to be set.
7526       (op & 0xf) != 0xf)
7527     {
7528       if (op & NSDragOperationLink)
7529         modifiers |= NSControlKeyMask;
7530       if (op & NSDragOperationCopy)
7531         modifiers |= NSAlternateKeyMask;
7532       if (op & NSDragOperationGeneric)
7533         modifiers |= NSCommandKeyMask;
7534     }
7536   modifiers = EV_MODIFIERS2 (modifiers);
7537   if (type == 0)
7538     {
7539       return NO;
7540     }
7541   else if ([type isEqualToString: NSFilenamesPboardType])
7542     {
7543       NSArray *files;
7544       NSEnumerator *fenum;
7545       NSString *file;
7547       if (!(files = [pb propertyListForType: type]))
7548         return NO;
7550       fenum = [files objectEnumerator];
7551       while ( (file = [fenum nextObject]) )
7552         {
7553           emacs_event->kind = DRAG_N_DROP_EVENT;
7554           XSETINT (emacs_event->x, x);
7555           XSETINT (emacs_event->y, y);
7556           ns_input_file = append2 (ns_input_file,
7557                                    build_string ([file UTF8String]));
7558           emacs_event->modifiers = modifiers;
7559           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
7560           EV_TRAILER (theEvent);
7561         }
7562       return YES;
7563     }
7564   else if ([type isEqualToString: NSURLPboardType])
7565     {
7566       NSURL *url = [NSURL URLFromPasteboard: pb];
7567       if (url == nil) return NO;
7569       emacs_event->kind = DRAG_N_DROP_EVENT;
7570       XSETINT (emacs_event->x, x);
7571       XSETINT (emacs_event->y, y);
7572       emacs_event->modifiers = modifiers;
7573       emacs_event->arg =  list2 (Qurl,
7574                                  build_string ([[url absoluteString]
7575                                                  UTF8String]));
7576       EV_TRAILER (theEvent);
7578       if ([url isFileURL] != NO)
7579         {
7580           NSString *file = [url path];
7581           ns_input_file = append2 (ns_input_file,
7582                                    build_string ([file UTF8String]));
7583         }
7584       return YES;
7585     }
7586   else if ([type isEqualToString: NSStringPboardType]
7587            || [type isEqualToString: NSTabularTextPboardType])
7588     {
7589       NSString *data;
7591       if (! (data = [pb stringForType: type]))
7592         return NO;
7594       emacs_event->kind = DRAG_N_DROP_EVENT;
7595       XSETINT (emacs_event->x, x);
7596       XSETINT (emacs_event->y, y);
7597       emacs_event->modifiers = modifiers;
7598       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
7599       EV_TRAILER (theEvent);
7600       return YES;
7601     }
7602   else
7603     {
7604       fprintf (stderr, "Invalid data type in dragging pasteboard");
7605       return NO;
7606     }
7610 - (id) validRequestorForSendType: (NSString *)typeSent
7611                       returnType: (NSString *)typeReturned
7613   NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
7614   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7615       && typeReturned == nil)
7616     {
7617       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7618         return self;
7619     }
7621   return [super validRequestorForSendType: typeSent
7622                                returnType: typeReturned];
7626 /* The next two methods are part of NSServicesRequests informal protocol,
7627    supposedly called when a services menu item is chosen from this app.
7628    But this should not happen because we override the services menu with our
7629    own entries which call ns-perform-service.
7630    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7631    So let's at least stub them out until further investigation can be done. */
7633 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7635   /* we could call ns_string_from_pasteboard(pboard) here but then it should
7636      be written into the buffer in place of the existing selection..
7637      ordinary service calls go through functions defined in ns-win.el */
7638   return NO;
7641 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7643   NSArray *typesDeclared;
7644   Lisp_Object val;
7646   NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
7648   /* We only support NSStringPboardType */
7649   if ([types containsObject:NSStringPboardType] == NO) {
7650     return NO;
7651   }
7653   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7654   if (CONSP (val) && SYMBOLP (XCAR (val)))
7655     {
7656       val = XCDR (val);
7657       if (CONSP (val) && NILP (XCDR (val)))
7658         val = XCAR (val);
7659     }
7660   if (! STRINGP (val))
7661     return NO;
7663   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7664   [pb declareTypes:typesDeclared owner:nil];
7665   ns_string_to_pasteboard (pb, val);
7666   return YES;
7670 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7671    (gives a miniaturized version of the window); currently we use the latter for
7672    frames whose active buffer doesn't correspond to any file
7673    (e.g., '*scratch*') */
7674 - setMiniwindowImage: (BOOL) setMini
7676   id image = [[self window] miniwindowImage];
7677   NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
7679   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7680      about "AppleDockIconEnabled" notwithstanding, however the set message
7681      below has its effect nonetheless. */
7682   if (image != emacsframe->output_data.ns->miniimage)
7683     {
7684       if (image && [image isKindOfClass: [EmacsImage class]])
7685         [image release];
7686       [[self window] setMiniwindowImage:
7687                        setMini ? emacsframe->output_data.ns->miniimage : nil];
7688     }
7690   return self;
7694 - (void) setRows: (int) r andColumns: (int) c
7696   NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
7697   rows = r;
7698   cols = c;
7701 - (int) fullscreenState
7703   return fs_state;
7706 @end  /* EmacsView */
7710 /* ==========================================================================
7712     EmacsWindow implementation
7714    ========================================================================== */
7716 @implementation EmacsWindow
7718 #ifdef NS_IMPL_COCOA
7719 - (id)accessibilityAttributeValue:(NSString *)attribute
7721   Lisp_Object str = Qnil;
7722   struct frame *f = SELECTED_FRAME ();
7723   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7725   NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
7727   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7728     return NSAccessibilityTextFieldRole;
7730   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7731       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7732     {
7733       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7734     }
7735   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7736     {
7737       if (! NILP (BVAR (curbuf, mark_active)))
7738           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7740       if (NILP (str))
7741         {
7742           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7743           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7744           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7746           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7747             str = make_uninit_multibyte_string (range, byte_range);
7748           else
7749             str = make_uninit_string (range);
7750           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7751              Is this a problem?  */
7752           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7753         }
7754     }
7757   if (! NILP (str))
7758     {
7759       if (CONSP (str) && SYMBOLP (XCAR (str)))
7760         {
7761           str = XCDR (str);
7762           if (CONSP (str) && NILP (XCDR (str)))
7763             str = XCAR (str);
7764         }
7765       if (STRINGP (str))
7766         {
7767           const char *utfStr = SSDATA (str);
7768           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7769           return nsStr;
7770         }
7771     }
7773   return [super accessibilityAttributeValue:attribute];
7775 #endif /* NS_IMPL_COCOA */
7777 /* Constrain size and placement of a frame.
7779    By returning the original "frameRect", the frame is not
7780    constrained. This can lead to unwanted situations where, for
7781    example, the menu bar covers the frame.
7783    The default implementation (accessed using "super") constrains the
7784    frame to the visible area of SCREEN, minus the menu bar (if
7785    present) and the Dock.  Note that default implementation also calls
7786    windowWillResize, with the frame it thinks should have.  (This can
7787    make the frame exit maximized mode.)
7789    Note that this should work in situations where multiple monitors
7790    are present.  Common configurations are side-by-side monitors and a
7791    monitor on top of another (e.g. when a laptop is placed under a
7792    large screen). */
7793 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7795   NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
7796              NSTRACE_ARG_RECT (frameRect));
7798 #ifdef NS_IMPL_COCOA
7799 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7800   // If separate spaces is on, it is like each screen is independent.  There is
7801   // no spanning of frames across screens.
7802   if ([NSScreen screensHaveSeparateSpaces])
7803     {
7804       NSTRACE_MSG ("Screens have separate spaces");
7805       frameRect = [super constrainFrameRect:frameRect toScreen:screen];
7806       NSTRACE_RETURN_RECT (frameRect);
7807       return frameRect;
7808     }
7809 #endif
7810 #endif
7812   return constrain_frame_rect(frameRect,
7813                               [(EmacsView *)[self delegate] isFullscreen]);
7817 - (void)performZoom:(id)sender
7819   NSTRACE ("[EmacsWindow performZoom:]");
7821   return [super performZoom:sender];
7824 - (void)zoom:(id)sender
7826   NSTRACE ("[EmacsWindow zoom:]");
7828   ns_update_auto_hide_menu_bar();
7830   // Below are three zoom implementations.  In the final commit, the
7831   // idea is that the last should be included.
7833 #if 0
7834   // Native zoom done using the standard zoom animation.  Size of the
7835   // resulting frame reduced to accommodate the Dock and, if present,
7836   // the menu-bar.
7837   [super zoom:sender];
7839 #elsif 0
7840   // Native zoom done using the standard zoom animation, plus an
7841   // explicit resize to cover the full screen.
7842   [super zoom:sender];
7844   // After the native zoom, resize the resulting frame to fill the
7845   // entire screen, except the menu-bar.
7846   //
7847   // This works for all practical purposes.  (The only minor oddity is
7848   // when transiting from full-height frame to a maximized, the
7849   // animation reduces the height of the frame slightly (to the 4
7850   // pixels needed to accommodate the Doc) before it snaps back into
7851   // full height.  The user would need a very trained eye to spot
7852   // this.)
7853   NSScreen * screen = [self screen];
7854   if (screen != nil)
7855     {
7856       int fs_state = [(EmacsView *)[self delegate] fullscreenState];
7858       NSTRACE_FSTYPE ("fullscreenState", fs_state);
7860       NSRect sr = [screen frame];
7861       NSRect wr = [self frame];
7862       NSTRACE_RECT ("Rect after zoom", wr);
7864       NSRect newWr = wr;
7866       if (fs_state == FULLSCREEN_MAXIMIZED
7867           || fs_state == FULLSCREEN_HEIGHT)
7868         {
7869           newWr.origin.x = 0;
7870           newWr.size.height = sr.size.height - ns_menu_bar_height(screen);
7871         }
7873       if (fs_state == FULLSCREEN_MAXIMIZED
7874           || fs_state == FULLSCREEN_WIDTH)
7875         {
7876           newWr.origin.y = 0;
7877           newWr.size.width = sr.size.width;
7878         }
7880       if (newWr.size.width     != wr.size.width
7881           || newWr.size.height != wr.size.height
7882           || newWr.origin.x    != wr.origin.x
7883           || newWr.origin.y    != wr.origin.y)
7884         {
7885           NSTRACE_MSG ("New frame different");
7886           [self setFrame: newWr display: NO];
7887         }
7888     }
7889 #else
7890   // Non-native zoom which is done instantaneously.  The resulting frame
7891   // covers the entire screen, except the menu-bar, if present.
7892   NSScreen * screen = [self screen];
7893   if (screen != nil)
7894     {
7895       NSRect sr = [screen frame];
7896       sr.size.height -= ns_menu_bar_height (screen);
7898       sr = [[self delegate] windowWillUseStandardFrame:self
7899                                           defaultFrame:sr];
7900       [self setFrame: sr display: NO];
7901     }
7902 #endif
7905 - (void)setFrame:(NSRect)windowFrame
7906          display:(BOOL)displayViews
7908   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
7909            NSTRACE_ARG_RECT (windowFrame), displayViews);
7911   [super setFrame:windowFrame display:displayViews];
7914 - (void)setFrame:(NSRect)windowFrame
7915          display:(BOOL)displayViews
7916          animate:(BOOL)performAnimation
7918   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
7919            " display:%d performAnimation:%d]",
7920            NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
7922   [super setFrame:windowFrame display:displayViews animate:performAnimation];
7925 - (void)setFrameTopLeftPoint:(NSPoint)point
7927   NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
7928            NSTRACE_ARG_POINT (point));
7930   [super setFrameTopLeftPoint:point];
7932 @end /* EmacsWindow */
7935 @implementation EmacsFSWindow
7937 - (BOOL)canBecomeKeyWindow
7939   return YES;
7942 - (BOOL)canBecomeMainWindow
7944   return YES;
7947 @end
7949 /* ==========================================================================
7951     EmacsScroller implementation
7953    ========================================================================== */
7956 @implementation EmacsScroller
7958 /* for repeat button push */
7959 #define SCROLL_BAR_FIRST_DELAY 0.5
7960 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
7962 + (CGFloat) scrollerWidth
7964   /* TODO: if we want to allow variable widths, this is the place to do it,
7965            however neither GNUstep nor Cocoa support it very well */
7966   CGFloat r;
7967 #if !defined (NS_IMPL_COCOA) || \
7968   MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
7969   r = [NSScroller scrollerWidth];
7970 #else
7971   r = [NSScroller scrollerWidthForControlSize: NSRegularControlSize
7972                                 scrollerStyle: NSScrollerStyleLegacy];
7973 #endif
7974   return r;
7978 - initFrame: (NSRect )r window: (Lisp_Object)nwin
7980   NSTRACE ("[EmacsScroller initFrame: window:]");
7982   r.size.width = [EmacsScroller scrollerWidth];
7983   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
7984   [self setContinuous: YES];
7985   [self setEnabled: YES];
7987   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
7988      locked against the top and bottom edges, and right edge on OS X, where
7989      scrollers are on right. */
7990 #ifdef NS_IMPL_GNUSTEP
7991   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
7992 #else
7993   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
7994 #endif
7996   window = XWINDOW (nwin);
7997   condemned = NO;
7998   pixel_height = NSHeight (r);
7999   if (pixel_height == 0) pixel_height = 1;
8000   min_portion = 20 / pixel_height;
8002   frame = XFRAME (window->frame);
8003   if (FRAME_LIVE_P (frame))
8004     {
8005       int i;
8006       EmacsView *view = FRAME_NS_VIEW (frame);
8007       NSView *sview = [[view window] contentView];
8008       NSArray *subs = [sview subviews];
8010       /* disable optimization stopping redraw of other scrollbars */
8011       view->scrollbarsNeedingUpdate = 0;
8012       for (i =[subs count]-1; i >= 0; i--)
8013         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8014           view->scrollbarsNeedingUpdate++;
8015       [sview addSubview: self];
8016     }
8018 /*  [self setFrame: r]; */
8020   return self;
8024 - (void)setFrame: (NSRect)newRect
8026   NSTRACE ("[EmacsScroller setFrame:]");
8028 /*  block_input (); */
8029   pixel_height = NSHeight (newRect);
8030   if (pixel_height == 0) pixel_height = 1;
8031   min_portion = 20 / pixel_height;
8032   [super setFrame: newRect];
8033 /*  unblock_input (); */
8037 - (void)dealloc
8039   NSTRACE ("[EmacsScroller dealloc]");
8040   if (window)
8041     wset_vertical_scroll_bar (window, Qnil);
8042   window = 0;
8043   [super dealloc];
8047 - condemn
8049   NSTRACE ("[EmacsScroller condemn]");
8050   condemned =YES;
8051   return self;
8055 - reprieve
8057   NSTRACE ("[EmacsScroller reprieve]");
8058   condemned =NO;
8059   return self;
8063 -(bool)judge
8065   NSTRACE ("[EmacsScroller judge]");
8066   bool ret = condemned;
8067   if (condemned)
8068     {
8069       EmacsView *view;
8070       block_input ();
8071       /* ensure other scrollbar updates after deletion */
8072       view = (EmacsView *)FRAME_NS_VIEW (frame);
8073       if (view != nil)
8074         view->scrollbarsNeedingUpdate++;
8075       if (window)
8076         wset_vertical_scroll_bar (window, Qnil);
8077       window = 0;
8078       [self removeFromSuperview];
8079       [self release];
8080       unblock_input ();
8081     }
8082   return ret;
8086 - (void)resetCursorRects
8088   NSRect visible = [self visibleRect];
8089   NSTRACE ("[EmacsScroller resetCursorRects]");
8091   if (!NSIsEmptyRect (visible))
8092     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8093   [[NSCursor arrowCursor] setOnMouseEntered: YES];
8097 - (int) checkSamePosition: (int) position portion: (int) portion
8098                     whole: (int) whole
8100   return em_position ==position && em_portion ==portion && em_whole ==whole
8101     && portion != whole; /* needed for resize empty buf */
8105 - setPosition: (int)position portion: (int)portion whole: (int)whole
8107   NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8109   em_position = position;
8110   em_portion = portion;
8111   em_whole = whole;
8113   if (portion >= whole)
8114     {
8115 #ifdef NS_IMPL_COCOA
8116       [self setKnobProportion: 1.0];
8117       [self setDoubleValue: 1.0];
8118 #else
8119       [self setFloatValue: 0.0 knobProportion: 1.0];
8120 #endif
8121     }
8122   else
8123     {
8124       float pos;
8125       CGFloat por;
8126       portion = max ((float)whole*min_portion/pixel_height, portion);
8127       pos = (float)position / (whole - portion);
8128       por = (CGFloat)portion/whole;
8129 #ifdef NS_IMPL_COCOA
8130       [self setKnobProportion: por];
8131       [self setDoubleValue: pos];
8132 #else
8133       [self setFloatValue: pos knobProportion: por];
8134 #endif
8135     }
8137   return self;
8140 /* set up emacs_event */
8141 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8143   Lisp_Object win;
8145   NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8147   if (!emacs_event)
8148     return;
8150   emacs_event->part = last_hit_part;
8151   emacs_event->code = 0;
8152   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8153   XSETWINDOW (win, window);
8154   emacs_event->frame_or_window = win;
8155   emacs_event->timestamp = EV_TIMESTAMP (e);
8156   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8157   emacs_event->arg = Qnil;
8158   XSETINT (emacs_event->x, loc * pixel_height);
8159   XSETINT (emacs_event->y, pixel_height-20);
8161   if (q_event_ptr)
8162     {
8163       n_emacs_events_pending++;
8164       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8165     }
8166   else
8167     hold_event (emacs_event);
8168   EVENT_INIT (*emacs_event);
8169   ns_send_appdefined (-1);
8173 /* called manually thru timer to implement repeated button action w/hold-down */
8174 - repeatScroll: (NSTimer *)scrollEntry
8176   NSEvent *e = [[self window] currentEvent];
8177   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
8178   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8180   NSTRACE ("[EmacsScroller repeatScroll:]");
8182   /* clear timer if need be */
8183   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8184     {
8185         [scroll_repeat_entry invalidate];
8186         [scroll_repeat_entry release];
8187         scroll_repeat_entry = nil;
8189         if (inKnob)
8190           return self;
8192         scroll_repeat_entry
8193           = [[NSTimer scheduledTimerWithTimeInterval:
8194                         SCROLL_BAR_CONTINUOUS_DELAY
8195                                             target: self
8196                                           selector: @selector (repeatScroll:)
8197                                           userInfo: 0
8198                                            repeats: YES]
8199               retain];
8200     }
8202   [self sendScrollEventAtLoc: 0 fromEvent: e];
8203   return self;
8207 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
8208    mouseDragged events without going into a modal loop. */
8209 - (void)mouseDown: (NSEvent *)e
8211   NSRect sr, kr;
8212   /* hitPart is only updated AFTER event is passed on */
8213   NSScrollerPart part = [self testPart: [e locationInWindow]];
8214   CGFloat inc = 0.0, loc, kloc, pos;
8215   int edge = 0;
8217   NSTRACE ("[EmacsScroller mouseDown:]");
8219   switch (part)
8220     {
8221     case NSScrollerDecrementPage:
8222         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
8223     case NSScrollerIncrementPage:
8224         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
8225     case NSScrollerDecrementLine:
8226       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
8227     case NSScrollerIncrementLine:
8228       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
8229     case NSScrollerKnob:
8230       last_hit_part = scroll_bar_handle; break;
8231     case NSScrollerKnobSlot:  /* GNUstep-only */
8232       last_hit_part = scroll_bar_move_ratio; break;
8233     default:  /* NSScrollerNoPart? */
8234       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
8235                (long) part);
8236       return;
8237     }
8239   if (inc != 0.0)
8240     {
8241       pos = 0;      /* ignored */
8243       /* set a timer to repeat, as we can't let superclass do this modally */
8244       scroll_repeat_entry
8245         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8246                                             target: self
8247                                           selector: @selector (repeatScroll:)
8248                                           userInfo: 0
8249                                            repeats: YES]
8250             retain];
8251     }
8252   else
8253     {
8254       /* handle, or on GNUstep possibly slot */
8255       NSEvent *fake_event;
8257       /* compute float loc in slot and mouse offset on knob */
8258       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8259                       toView: nil];
8260       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
8261       if (loc <= 0.0)
8262         {
8263           loc = 0.0;
8264           edge = -1;
8265         }
8266       else if (loc >= NSHeight (sr))
8267         {
8268           loc = NSHeight (sr);
8269           edge = 1;
8270         }
8272       if (edge)
8273         kloc = 0.5 * edge;
8274       else
8275         {
8276           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8277                           toView: nil];
8278           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8279         }
8280       last_mouse_offset = kloc;
8282       /* if knob, tell emacs a location offset by knob pos
8283          (to indicate top of handle) */
8284       if (part == NSScrollerKnob)
8285           pos = (loc - last_mouse_offset) / NSHeight (sr);
8286       else
8287         /* else this is a slot click on GNUstep: go straight there */
8288         pos = loc / NSHeight (sr);
8290       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8291       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
8292                                       location: [e locationInWindow]
8293                                  modifierFlags: [e modifierFlags]
8294                                      timestamp: [e timestamp]
8295                                   windowNumber: [e windowNumber]
8296                                        context: [e context]
8297                                    eventNumber: [e eventNumber]
8298                                     clickCount: [e clickCount]
8299                                       pressure: [e pressure]];
8300       [super mouseUp: fake_event];
8301     }
8303   if (part != NSScrollerKnob)
8304     [self sendScrollEventAtLoc: pos fromEvent: e];
8308 /* Called as we manually track scroller drags, rather than superclass. */
8309 - (void)mouseDragged: (NSEvent *)e
8311     NSRect sr;
8312     double loc, pos;
8314     NSTRACE ("[EmacsScroller mouseDragged:]");
8316       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8317                       toView: nil];
8318       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
8320       if (loc <= 0.0)
8321         {
8322           loc = 0.0;
8323         }
8324       else if (loc >= NSHeight (sr) + last_mouse_offset)
8325         {
8326           loc = NSHeight (sr) + last_mouse_offset;
8327         }
8329       pos = (loc - last_mouse_offset) / NSHeight (sr);
8330       [self sendScrollEventAtLoc: pos fromEvent: e];
8334 - (void)mouseUp: (NSEvent *)e
8336   NSTRACE ("[EmacsScroller mouseUp:]");
8338   if (scroll_repeat_entry)
8339     {
8340       [scroll_repeat_entry invalidate];
8341       [scroll_repeat_entry release];
8342       scroll_repeat_entry = nil;
8343     }
8344   last_hit_part = scroll_bar_above_handle;
8348 /* treat scrollwheel events in the bar as though they were in the main window */
8349 - (void) scrollWheel: (NSEvent *)theEvent
8351   NSTRACE ("[EmacsScroller scrollWheel:]");
8353   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8354   [view mouseDown: theEvent];
8357 @end  /* EmacsScroller */
8360 #ifdef NS_IMPL_GNUSTEP
8361 /* Dummy class to get rid of startup warnings.  */
8362 @implementation EmacsDocument
8364 @end
8365 #endif
8368 /* ==========================================================================
8370    Font-related functions; these used to be in nsfaces.m
8372    ========================================================================== */
8375 Lisp_Object
8376 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8378   struct font *font = XFONT_OBJECT (font_object);
8379   EmacsView *view = FRAME_NS_VIEW (f);
8380   int font_ascent, font_descent;
8382   if (fontset < 0)
8383     fontset = fontset_from_font (font_object);
8384   FRAME_FONTSET (f) = fontset;
8386   if (FRAME_FONT (f) == font)
8387     /* This font is already set in frame F.  There's nothing more to
8388        do.  */
8389     return font_object;
8391   FRAME_FONT (f) = font;
8393   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8394   FRAME_COLUMN_WIDTH (f) = font->average_width;
8395   get_font_ascent_descent (font, &font_ascent, &font_descent);
8396   FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8398   /* Compute the scroll bar width in character columns.  */
8399   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8400     {
8401       int wid = FRAME_COLUMN_WIDTH (f);
8402       FRAME_CONFIG_SCROLL_BAR_COLS (f)
8403         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8404     }
8405   else
8406     {
8407       int wid = FRAME_COLUMN_WIDTH (f);
8408       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8409     }
8411   /* Compute the scroll bar height in character lines.  */
8412   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8413     {
8414       int height = FRAME_LINE_HEIGHT (f);
8415       FRAME_CONFIG_SCROLL_BAR_LINES (f)
8416         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8417     }
8418   else
8419     {
8420       int height = FRAME_LINE_HEIGHT (f);
8421       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8422     }
8424   /* Now make the frame display the given font.  */
8425   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8426     adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8427                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8428                        false, Qfont);
8430   return font_object;
8434 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8435 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8436          in 1.43. */
8438 const char *
8439 ns_xlfd_to_fontname (const char *xlfd)
8440 /* --------------------------------------------------------------------------
8441     Convert an X font name (XLFD) to an NS font name.
8442     Only family is used.
8443     The string returned is temporarily allocated.
8444    -------------------------------------------------------------------------- */
8446   char *name = xmalloc (180);
8447   int i, len;
8448   const char *ret;
8450   if (!strncmp (xlfd, "--", 2))
8451     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8452   else
8453     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8455   /* stopgap for malformed XLFD input */
8456   if (strlen (name) == 0)
8457     strcpy (name, "Monaco");
8459   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8460      also uppercase after '-' or ' ' */
8461   name[0] = c_toupper (name[0]);
8462   for (len =strlen (name), i =0; i<len; i++)
8463     {
8464       if (name[i] == '$')
8465         {
8466           name[i] = '-';
8467           if (i+1<len)
8468             name[i+1] = c_toupper (name[i+1]);
8469         }
8470       else if (name[i] == '_')
8471         {
8472           name[i] = ' ';
8473           if (i+1<len)
8474             name[i+1] = c_toupper (name[i+1]);
8475         }
8476     }
8477 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
8478   ret = [[NSString stringWithUTF8String: name] UTF8String];
8479   xfree (name);
8480   return ret;
8484 void
8485 syms_of_nsterm (void)
8487   NSTRACE ("syms_of_nsterm");
8489   ns_antialias_threshold = 10.0;
8491   /* from 23+ we need to tell emacs what modifiers there are.. */
8492   DEFSYM (Qmodifier_value, "modifier-value");
8493   DEFSYM (Qalt, "alt");
8494   DEFSYM (Qhyper, "hyper");
8495   DEFSYM (Qmeta, "meta");
8496   DEFSYM (Qsuper, "super");
8497   DEFSYM (Qcontrol, "control");
8498   DEFSYM (QUTF8_STRING, "UTF8_STRING");
8500   DEFSYM (Qfile, "file");
8501   DEFSYM (Qurl, "url");
8503   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8504   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8505   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8506   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8507   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8509   DEFVAR_LISP ("ns-input-file", ns_input_file,
8510               "The file specified in the last NS event.");
8511   ns_input_file =Qnil;
8513   DEFVAR_LISP ("ns-working-text", ns_working_text,
8514               "String for visualizing working composition sequence.");
8515   ns_working_text =Qnil;
8517   DEFVAR_LISP ("ns-input-font", ns_input_font,
8518               "The font specified in the last NS event.");
8519   ns_input_font =Qnil;
8521   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8522               "The fontsize specified in the last NS event.");
8523   ns_input_fontsize =Qnil;
8525   DEFVAR_LISP ("ns-input-line", ns_input_line,
8526                "The line specified in the last NS event.");
8527   ns_input_line =Qnil;
8529   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
8530                "The service name specified in the last NS event.");
8531   ns_input_spi_name =Qnil;
8533   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
8534                "The service argument specified in the last NS event.");
8535   ns_input_spi_arg =Qnil;
8537   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
8538                "This variable describes the behavior of the alternate or option key.\n\
8539 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8540 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8541 at all, allowing it to be used at a lower level for accented character entry.");
8542   ns_alternate_modifier = Qmeta;
8544   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
8545                "This variable describes the behavior of the right alternate or option key.\n\
8546 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8547 Set to left means be the same key as `ns-alternate-modifier'.\n\
8548 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8549 at all, allowing it to be used at a lower level for accented character entry.");
8550   ns_right_alternate_modifier = Qleft;
8552   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
8553                "This variable describes the behavior of the command key.\n\
8554 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8555   ns_command_modifier = Qsuper;
8557   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
8558                "This variable describes the behavior of the right command key.\n\
8559 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8560 Set to left means be the same key as `ns-command-modifier'.\n\
8561 Set to none means that the command / option key is not interpreted by Emacs\n\
8562 at all, allowing it to be used at a lower level for accented character entry.");
8563   ns_right_command_modifier = Qleft;
8565   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
8566                "This variable describes the behavior of the control key.\n\
8567 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8568   ns_control_modifier = Qcontrol;
8570   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
8571                "This variable describes the behavior of the right control key.\n\
8572 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8573 Set to left means be the same key as `ns-control-modifier'.\n\
8574 Set to none means that the control / option key is not interpreted by Emacs\n\
8575 at all, allowing it to be used at a lower level for accented character entry.");
8576   ns_right_control_modifier = Qleft;
8578   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
8579                "This variable describes the behavior of the function key (on laptops).\n\
8580 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8581 Set to none means that the function key is not interpreted by Emacs at all,\n\
8582 allowing it to be used at a lower level for accented character entry.");
8583   ns_function_modifier = Qnone;
8585   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
8586                "Non-nil (the default) means to render text antialiased.");
8587   ns_antialias_text = Qt;
8589   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
8590                "Whether to confirm application quit using dialog.");
8591   ns_confirm_quit = Qnil;
8593   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
8594                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
8595 Only works on OSX 10.6 or later.  */);
8596   ns_auto_hide_menu_bar = Qnil;
8598   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
8599      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
8600 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
8601 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
8602 Default is t for OSX >= 10.7, nil otherwise.  */);
8603 #ifdef HAVE_NATIVE_FS
8604   ns_use_native_fullscreen = YES;
8605 #else
8606   ns_use_native_fullscreen = NO;
8607 #endif
8608   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
8610   DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
8611      doc: /*Non-nil means use animation on non-native fullscreen.
8612 For native fullscreen, this does nothing.
8613 Default is nil.  */);
8614   ns_use_fullscreen_animation = NO;
8616   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
8617      doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
8618 Note that this does not apply to images.
8619 This variable is ignored on OSX < 10.7 and GNUstep.  */);
8620   ns_use_srgb_colorspace = YES;
8622   /* TODO: move to common code */
8623   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
8624                doc: /* Which toolkit scroll bars Emacs uses, if any.
8625 A value of nil means Emacs doesn't use toolkit scroll bars.
8626 With the X Window system, the value is a symbol describing the
8627 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
8628 With MS Windows or Nextstep, the value is t.  */);
8629   Vx_toolkit_scroll_bars = Qt;
8631   DEFVAR_BOOL ("x-use-underline-position-properties",
8632                x_use_underline_position_properties,
8633      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
8634 A value of nil means ignore them.  If you encounter fonts with bogus
8635 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
8636 to 4.1, set this to nil. */);
8637   x_use_underline_position_properties = 0;
8639   DEFVAR_BOOL ("x-underline-at-descent-line",
8640                x_underline_at_descent_line,
8641      doc: /* Non-nil means to draw the underline at the same place as the descent line.
8642 A value of nil means to draw the underline according to the value of the
8643 variable `x-use-underline-position-properties', which is usually at the
8644 baseline level.  The default value is nil.  */);
8645   x_underline_at_descent_line = 0;
8647   /* Tell Emacs about this window system.  */
8648   Fprovide (Qns, Qnil);
8650   DEFSYM (Qcocoa, "cocoa");
8651   DEFSYM (Qgnustep, "gnustep");
8653 #ifdef NS_IMPL_COCOA
8654   Fprovide (Qcocoa, Qnil);
8655   syms_of_macfont ();
8656 #else
8657   Fprovide (Qgnustep, Qnil);
8658   syms_of_nsfont ();
8659 #endif