Default to 'configure --enable-silent-rules'
[emacs.git] / src / nsterm.m
blobbf3192bf43232fe679d17ce05890591938209610
1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2015 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
71 /* call tracing */
72 #if 0
73 int term_trace_num = 0;
74 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
75                                 __FILE__, __LINE__, ++term_trace_num)
76 #else
77 #define NSTRACE(x)
78 #endif
80 /* Detailed tracing. "S" means "size" and "LL" stands for "lower left". */
81 #if 0
82 int term_trace_num = 0;
83 #define NSTRACE_SIZE(str,size) fprintf (stderr,                         \
84                                    "%s:%d: [%d]   " str                 \
85                                    " (S:%.0f x %.0f)\n", \
86                                    __FILE__, __LINE__, ++term_trace_num,\
87                                    size.height,                       \
88                                    size.width)
89 #define NSTRACE_RECT(s,r) fprintf (stderr,                              \
90                                    "%s:%d: [%d]   " s                   \
91                                    " (LL:%.0f x %.0f -> S:%.0f x %.0f)\n", \
92                                    __FILE__, __LINE__, ++term_trace_num,\
93                                    r.origin.x,                          \
94                                    r.origin.y,                          \
95                                    r.size.height,                       \
96                                    r.size.width)
97 #else
98 #define NSTRACE_SIZE(str,size)
99 #define NSTRACE_RECT(s,r)
100 #endif
102 extern NSString *NSMenuDidBeginTrackingNotification;
104 /* ==========================================================================
106    NSColor, EmacsColor category.
108    ========================================================================== */
109 @implementation NSColor (EmacsColor)
110 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
111                          blue:(CGFloat)blue alpha:(CGFloat)alpha
113 #ifdef NS_IMPL_COCOA
114 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
115   if (ns_use_srgb_colorspace)
116       return [NSColor colorWithSRGBRed: red
117                                  green: green
118                                   blue: blue
119                                  alpha: alpha];
120 #endif
121 #endif
122   return [NSColor colorWithCalibratedRed: red
123                                    green: green
124                                     blue: blue
125                                    alpha: alpha];
128 - (NSColor *)colorUsingDefaultColorSpace
130 #ifdef NS_IMPL_COCOA
131 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
132   if (ns_use_srgb_colorspace)
133     return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
134 #endif
135 #endif
136   return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
139 @end
141 /* ==========================================================================
143     Local declarations
145    ========================================================================== */
147 /* Convert a symbol indexed with an NSxxx value to a value as defined
148    in keyboard.c (lispy_function_key). I hope this is a correct way
149    of doing things... */
150 static unsigned convert_ns_to_X_keysym[] =
152   NSHomeFunctionKey,            0x50,
153   NSLeftArrowFunctionKey,       0x51,
154   NSUpArrowFunctionKey,         0x52,
155   NSRightArrowFunctionKey,      0x53,
156   NSDownArrowFunctionKey,       0x54,
157   NSPageUpFunctionKey,          0x55,
158   NSPageDownFunctionKey,        0x56,
159   NSEndFunctionKey,             0x57,
160   NSBeginFunctionKey,           0x58,
161   NSSelectFunctionKey,          0x60,
162   NSPrintFunctionKey,           0x61,
163   NSClearLineFunctionKey,       0x0B,
164   NSExecuteFunctionKey,         0x62,
165   NSInsertFunctionKey,          0x63,
166   NSUndoFunctionKey,            0x65,
167   NSRedoFunctionKey,            0x66,
168   NSMenuFunctionKey,            0x67,
169   NSFindFunctionKey,            0x68,
170   NSHelpFunctionKey,            0x6A,
171   NSBreakFunctionKey,           0x6B,
173   NSF1FunctionKey,              0xBE,
174   NSF2FunctionKey,              0xBF,
175   NSF3FunctionKey,              0xC0,
176   NSF4FunctionKey,              0xC1,
177   NSF5FunctionKey,              0xC2,
178   NSF6FunctionKey,              0xC3,
179   NSF7FunctionKey,              0xC4,
180   NSF8FunctionKey,              0xC5,
181   NSF9FunctionKey,              0xC6,
182   NSF10FunctionKey,             0xC7,
183   NSF11FunctionKey,             0xC8,
184   NSF12FunctionKey,             0xC9,
185   NSF13FunctionKey,             0xCA,
186   NSF14FunctionKey,             0xCB,
187   NSF15FunctionKey,             0xCC,
188   NSF16FunctionKey,             0xCD,
189   NSF17FunctionKey,             0xCE,
190   NSF18FunctionKey,             0xCF,
191   NSF19FunctionKey,             0xD0,
192   NSF20FunctionKey,             0xD1,
193   NSF21FunctionKey,             0xD2,
194   NSF22FunctionKey,             0xD3,
195   NSF23FunctionKey,             0xD4,
196   NSF24FunctionKey,             0xD5,
198   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
199   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
200   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
202   NSTabCharacter,               0x09,
203   0x19,                         0x09,  /* left tab->regular since pass shift */
204   NSCarriageReturnCharacter,    0x0D,
205   NSNewlineCharacter,           0x0D,
206   NSEnterCharacter,             0x8D,
208   0x41|NSNumericPadKeyMask,     0xAE,  /* KP_Decimal */
209   0x43|NSNumericPadKeyMask,     0xAA,  /* KP_Multiply */
210   0x45|NSNumericPadKeyMask,     0xAB,  /* KP_Add */
211   0x4B|NSNumericPadKeyMask,     0xAF,  /* KP_Divide */
212   0x4E|NSNumericPadKeyMask,     0xAD,  /* KP_Subtract */
213   0x51|NSNumericPadKeyMask,     0xBD,  /* KP_Equal */
214   0x52|NSNumericPadKeyMask,     0xB0,  /* KP_0 */
215   0x53|NSNumericPadKeyMask,     0xB1,  /* KP_1 */
216   0x54|NSNumericPadKeyMask,     0xB2,  /* KP_2 */
217   0x55|NSNumericPadKeyMask,     0xB3,  /* KP_3 */
218   0x56|NSNumericPadKeyMask,     0xB4,  /* KP_4 */
219   0x57|NSNumericPadKeyMask,     0xB5,  /* KP_5 */
220   0x58|NSNumericPadKeyMask,     0xB6,  /* KP_6 */
221   0x59|NSNumericPadKeyMask,     0xB7,  /* KP_7 */
222   0x5B|NSNumericPadKeyMask,     0xB8,  /* KP_8 */
223   0x5C|NSNumericPadKeyMask,     0xB9,  /* KP_9 */
225   0x1B,                         0x1B   /* escape */
228 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
229    the maximum font size to NOT antialias.  On GNUstep there is currently
230    no way to control this behavior. */
231 float ns_antialias_threshold;
233 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
234 NSString *ns_app_name = @"Emacs";  /* default changed later */
236 /* Display variables */
237 struct ns_display_info *x_display_list; /* Chain of existing displays */
238 long context_menu_value = 0;
240 /* display update */
241 static struct frame *ns_updating_frame;
242 static NSView *focus_view = NULL;
243 static int ns_window_num = 0;
244 #ifdef NS_IMPL_GNUSTEP
245 static NSRect uRect;
246 #endif
247 static BOOL gsaved = NO;
248 static BOOL ns_fake_keydown = NO;
249 #ifdef NS_IMPL_COCOA
250 static BOOL ns_menu_bar_is_hidden = NO;
251 #endif
252 /*static int debug_lock = 0; */
254 /* event loop */
255 static BOOL send_appdefined = YES;
256 #define NO_APPDEFINED_DATA (-8)
257 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
258 static NSTimer *timed_entry = 0;
259 static NSTimer *scroll_repeat_entry = nil;
260 static fd_set select_readfds, select_writefds;
261 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
262 static int select_nfds = 0, select_valid = 0;
263 static struct timespec select_timeout = { 0, 0 };
264 static int selfds[2] = { -1, -1 };
265 static pthread_mutex_t select_mutex;
266 static int apploopnr = 0;
267 static NSAutoreleasePool *outerpool;
268 static struct input_event *emacs_event = NULL;
269 static struct input_event *q_event_ptr = NULL;
270 static int n_emacs_events_pending = 0;
271 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
272   *ns_pending_service_args;
273 static BOOL ns_do_open_file = NO;
274 static BOOL ns_last_use_native_fullscreen;
276 /* Non-zero means that a HELP_EVENT has been generated since Emacs
277    start.  */
279 static BOOL any_help_event_p = NO;
281 static struct {
282   struct input_event *q;
283   int nr, cap;
284 } hold_event_q = {
285   NULL, 0, 0
288 static NSString *represented_filename = nil;
289 static struct frame *represented_frame = 0;
291 #ifdef NS_IMPL_COCOA
293  * State for pending menu activation:
294  * MENU_NONE     Normal state
295  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
296  *               run lisp to update the menu.
297  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
298  *               will open.
299  */
300 #define MENU_NONE 0
301 #define MENU_PENDING 1
302 #define MENU_OPENING 2
303 static int menu_will_open_state = MENU_NONE;
305 /* Saved position for menu click.  */
306 static CGPoint menu_mouse_point;
307 #endif
309 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
310 #define NS_FUNCTION_KEY_MASK 0x800000
311 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
312 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
313 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
314 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
315 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
316 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
317 #define EV_MODIFIERS2(flags)                          \
318     (((flags & NSHelpKeyMask) ?           \
319            hyper_modifier : 0)                        \
320      | (!EQ (ns_right_alternate_modifier, Qleft) && \
321         ((flags & NSRightAlternateKeyMask) \
322          == NSRightAlternateKeyMask) ? \
323            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
324      | ((flags & NSAlternateKeyMask) ?                 \
325            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
326      | ((flags & NSShiftKeyMask) ?     \
327            shift_modifier : 0)                        \
328      | (!EQ (ns_right_control_modifier, Qleft) && \
329         ((flags & NSRightControlKeyMask) \
330          == NSRightControlKeyMask) ? \
331            parse_solitary_modifier (ns_right_control_modifier) : 0) \
332      | ((flags & NSControlKeyMask) ?      \
333            parse_solitary_modifier (ns_control_modifier) : 0)     \
334      | ((flags & NS_FUNCTION_KEY_MASK) ?  \
335            parse_solitary_modifier (ns_function_modifier) : 0)    \
336      | (!EQ (ns_right_command_modifier, Qleft) && \
337         ((flags & NSRightCommandKeyMask) \
338          == NSRightCommandKeyMask) ? \
339            parse_solitary_modifier (ns_right_command_modifier) : 0) \
340      | ((flags & NSCommandKeyMask) ?      \
341            parse_solitary_modifier (ns_command_modifier):0))
342 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
344 #define EV_UDMODIFIERS(e)                                      \
345     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
346      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
347      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
348      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
349      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
350      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
351      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
352      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
353      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
355 #define EV_BUTTON(e)                                                         \
356     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
357       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
358      [e buttonNumber] - 1)
360 /* Convert the time field to a timestamp in milliseconds. */
361 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
363 /* This is a piece of code which is common to all the event handling
364    methods.  Maybe it should even be a function.  */
365 #define EV_TRAILER(e)                                                   \
366   {                                                                     \
367     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
368     EV_TRAILER2 (e);                                                    \
369   }
371 #define EV_TRAILER2(e)                                                  \
372   {                                                                     \
373       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
374       if (q_event_ptr)                                                  \
375         {                                                               \
376           n_emacs_events_pending++;                                     \
377           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
378         }                                                               \
379       else                                                              \
380         hold_event (emacs_event);                                       \
381       EVENT_INIT (*emacs_event);                                        \
382       ns_send_appdefined (-1);                                          \
383     }
385 /* TODO: get rid of need for these forward declarations */
386 static void ns_condemn_scroll_bars (struct frame *f);
387 static void ns_judge_scroll_bars (struct frame *f);
388 void x_set_frame_alpha (struct frame *f);
391 /* ==========================================================================
393     Utilities
395    ========================================================================== */
397 void
398 ns_set_represented_filename (NSString* fstr, struct frame *f)
400   represented_filename = [fstr retain];
401   represented_frame = f;
404 void
405 ns_init_events (struct input_event* ev)
407   EVENT_INIT (*ev);
408   emacs_event = ev;
411 void
412 ns_finish_events ()
414   emacs_event = NULL;
417 static void
418 hold_event (struct input_event *event)
420   if (hold_event_q.nr == hold_event_q.cap)
421     {
422       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
423       else hold_event_q.cap *= 2;
424       hold_event_q.q =
425         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
426     }
428   hold_event_q.q[hold_event_q.nr++] = *event;
429   /* Make sure ns_read_socket is called, i.e. we have input.  */
430   raise (SIGIO);
431   send_appdefined = YES;
434 static Lisp_Object
435 append2 (Lisp_Object list, Lisp_Object item)
436 /* --------------------------------------------------------------------------
437    Utility to append to a list
438    -------------------------------------------------------------------------- */
440   Lisp_Object array[2];
441   array[0] = list;
442   array[1] = list1 (item);
443   return Fnconc (2, &array[0]);
447 const char *
448 ns_etc_directory (void)
449 /* If running as a self-contained app bundle, return as a string the
450    filename of the etc directory, if present; else nil.  */
452   NSBundle *bundle = [NSBundle mainBundle];
453   NSString *resourceDir = [bundle resourcePath];
454   NSString *resourcePath;
455   NSFileManager *fileManager = [NSFileManager defaultManager];
456   BOOL isDir;
458   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
459   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
460     {
461       if (isDir) return [resourcePath UTF8String];
462     }
463   return NULL;
467 const char *
468 ns_exec_path (void)
469 /* If running as a self-contained app bundle, return as a path string
470    the filenames of the libexec and bin directories, ie libexec:bin.
471    Otherwise, return nil.
472    Normally, Emacs does not add its own bin/ directory to the PATH.
473    However, a self-contained NS build has a different layout, with
474    bin/ and libexec/ subdirectories in the directory that contains
475    Emacs.app itself.
476    We put libexec first, because init_callproc_1 uses the first
477    element to initialize exec-directory.  An alternative would be
478    for init_callproc to check for invocation-directory/libexec.
481   NSBundle *bundle = [NSBundle mainBundle];
482   NSString *resourceDir = [bundle resourcePath];
483   NSString *binDir = [bundle bundlePath];
484   NSString *resourcePath, *resourcePaths;
485   NSRange range;
486   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
487   NSFileManager *fileManager = [NSFileManager defaultManager];
488   NSArray *paths;
489   NSEnumerator *pathEnum;
490   BOOL isDir;
492   range = [resourceDir rangeOfString: @"Contents"];
493   if (range.location != NSNotFound)
494     {
495       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
496 #ifdef NS_IMPL_COCOA
497       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
498 #endif
499     }
501   paths = [binDir stringsByAppendingPaths:
502                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
503   pathEnum = [paths objectEnumerator];
504   resourcePaths = @"";
506   while ((resourcePath = [pathEnum nextObject]))
507     {
508       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
509         if (isDir)
510           {
511             if ([resourcePaths length] > 0)
512               resourcePaths
513                 = [resourcePaths stringByAppendingString: pathSeparator];
514             resourcePaths
515               = [resourcePaths stringByAppendingString: resourcePath];
516           }
517     }
518   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
520   return NULL;
524 const char *
525 ns_load_path (void)
526 /* If running as a self-contained app bundle, return as a path string
527    the filenames of the site-lisp and lisp directories.
528    Ie, site-lisp:lisp.  Otherwise, return nil.  */
530   NSBundle *bundle = [NSBundle mainBundle];
531   NSString *resourceDir = [bundle resourcePath];
532   NSString *resourcePath, *resourcePaths;
533   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
534   NSFileManager *fileManager = [NSFileManager defaultManager];
535   BOOL isDir;
536   NSArray *paths = [resourceDir stringsByAppendingPaths:
537                               [NSArray arrayWithObjects:
538                                          @"site-lisp", @"lisp", nil]];
539   NSEnumerator *pathEnum = [paths objectEnumerator];
540   resourcePaths = @"";
542   /* Hack to skip site-lisp.  */
543   if (no_site_lisp) resourcePath = [pathEnum nextObject];
545   while ((resourcePath = [pathEnum nextObject]))
546     {
547       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
548         if (isDir)
549           {
550             if ([resourcePaths length] > 0)
551               resourcePaths
552                 = [resourcePaths stringByAppendingString: pathSeparator];
553             resourcePaths
554               = [resourcePaths stringByAppendingString: resourcePath];
555           }
556     }
557   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
559   return NULL;
562 static void
563 ns_timeout (int usecs)
564 /* --------------------------------------------------------------------------
565      Blocking timer utility used by ns_ring_bell
566    -------------------------------------------------------------------------- */
568   struct timespec wakeup = timespec_add (current_timespec (),
569                                          make_timespec (0, usecs * 1000));
571   /* Keep waiting until past the time wakeup.  */
572   while (1)
573     {
574       struct timespec timeout, now = current_timespec ();
575       if (timespec_cmp (wakeup, now) <= 0)
576         break;
577       timeout = timespec_sub (wakeup, now);
579       /* Try to wait that long--but we might wake up sooner.  */
580       pselect (0, NULL, NULL, NULL, &timeout, NULL);
581     }
585 void
586 ns_release_object (void *obj)
587 /* --------------------------------------------------------------------------
588     Release an object (callable from C)
589    -------------------------------------------------------------------------- */
591     [(id)obj release];
595 void
596 ns_retain_object (void *obj)
597 /* --------------------------------------------------------------------------
598     Retain an object (callable from C)
599    -------------------------------------------------------------------------- */
601     [(id)obj retain];
605 void *
606 ns_alloc_autorelease_pool (void)
607 /* --------------------------------------------------------------------------
608      Allocate a pool for temporary objects (callable from C)
609    -------------------------------------------------------------------------- */
611   return [[NSAutoreleasePool alloc] init];
615 void
616 ns_release_autorelease_pool (void *pool)
617 /* --------------------------------------------------------------------------
618      Free a pool and temporary objects it refers to (callable from C)
619    -------------------------------------------------------------------------- */
621   ns_release_object (pool);
626 /* ==========================================================================
628     Focus (clipping) and screen update
630    ========================================================================== */
633 // Window constraining
634 // -------------------
636 // To ensure that the windows are not placed under the menu bar, they
637 // are typically moved by the call-back constrainFrameRect. However,
638 // by overriding it, it's possible to inhibit this, leaving the window
639 // in it's original position.
641 // It's possible to hide the menu bar. However, technically, it's only
642 // possible to hide it when the application is active. To ensure that
643 // this work properly, the menu bar and window constraining are
644 // deferred until the application becomes active.
646 // Even though it's not possible to manually move a window above the
647 // top of the screen, it is allowed if it's done programmatically,
648 // when the menu is hidden. This allows the editable area to cover the
649 // full screen height.
651 // Test cases
652 // ----------
654 // Use the following extra files:
656 //    init.el:
657 //       ;; Hide menu and place frame slightly above the top of the screen.
658 //       (setq ns-auto-hide-menu-bar t)
659 //       (set-frame-position (selected-frame) 0 -20)
661 // Test 1:
663 //    emacs -Q -l init.el
665 //    Result: No menu bar, and the title bar should be above the screen.
667 // Test 2:
669 //    emacs -Q
671 //    Result: Menu bar visible, frame placed immediately below the menu.
674 static void
675 ns_constrain_all_frames (void)
677   Lisp_Object tail, frame;
679   FOR_EACH_FRAME (tail, frame)
680     {
681       struct frame *f = XFRAME (frame);
682       if (FRAME_NS_P (f))
683         {
684           NSView *view = FRAME_NS_VIEW (f);
685           /* This no-op will trigger the default window placing
686            * constraint system. */
687           [[view window] setFrameOrigin:[[view window] frame].origin];
688         }
689     }
693 /* True, if the menu bar should be hidden.  */
695 static BOOL
696 ns_menu_bar_should_be_hidden (void)
698   return !NILP (ns_auto_hide_menu_bar)
699     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
703 /* Show or hide the menu bar, based on user setting.  */
705 static void
706 ns_update_auto_hide_menu_bar (void)
708 #ifdef NS_IMPL_COCOA
709   block_input ();
711   NSTRACE (ns_update_auto_hide_menu_bar);
713   if (NSApp != nil && [NSApp isActive])
714     {
715       // Note, "setPresentationOptions" triggers an error unless the
716       // application is active.
717       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
719       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
720         {
721           NSApplicationPresentationOptions options
722             = NSApplicationPresentationDefault;
724           if (menu_bar_should_be_hidden)
725             options |= NSApplicationPresentationAutoHideMenuBar
726               | NSApplicationPresentationAutoHideDock;
728           [NSApp setPresentationOptions: options];
730           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
732           if (!ns_menu_bar_is_hidden)
733             {
734               ns_constrain_all_frames ();
735             }
736         }
737     }
739   unblock_input ();
740 #endif
744 static void
745 ns_update_begin (struct frame *f)
746 /* --------------------------------------------------------------------------
747    Prepare for a grouped sequence of drawing calls
748    external (RIF) call; whole frame, called before update_window_begin
749    -------------------------------------------------------------------------- */
751   EmacsView *view = FRAME_NS_VIEW (f);
752   NSTRACE (ns_update_begin);
754   ns_update_auto_hide_menu_bar ();
756 #ifdef NS_IMPL_COCOA
757   if ([view isFullscreen] && [view fsIsNative])
758   {
759     // Fix reappearing tool bar in fullscreen for OSX 10.7
760     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
761     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
762     if (! tbar_visible != ! [toolbar isVisible])
763       [toolbar setVisible: tbar_visible];
764   }
765 #endif
767   ns_updating_frame = f;
768   [view lockFocus];
770   /* drawRect may have been called for say the minibuffer, and then clip path
771      is for the minibuffer.  But the display engine may draw more because
772      we have set the frame as garbaged.  So reset clip path to the whole
773      view.  */
774 #ifdef NS_IMPL_COCOA
775   {
776     NSBezierPath *bp;
777     NSRect r = [view frame];
778     NSRect cr = [[view window] frame];
779     /* If a large frame size is set, r may be larger than the window frame
780        before constrained.  In that case don't change the clip path, as we
781        will clear in to the tool bar and title bar.  */
782     if (r.size.height
783         + FRAME_NS_TITLEBAR_HEIGHT (f)
784         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
785       {
786         bp = [[NSBezierPath bezierPathWithRect: r] retain];
787         [bp setClip];
788         [bp release];
789       }
790   }
791 #endif
793 #ifdef NS_IMPL_GNUSTEP
794   uRect = NSMakeRect (0, 0, 0, 0);
795 #endif
799 static void
800 ns_update_window_begin (struct window *w)
801 /* --------------------------------------------------------------------------
802    Prepare for a grouped sequence of drawing calls
803    external (RIF) call; for one window, called after update_begin
804    -------------------------------------------------------------------------- */
806   struct frame *f = XFRAME (WINDOW_FRAME (w));
807   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
809   NSTRACE (ns_update_window_begin);
810   w->output_cursor = w->cursor;
812   block_input ();
814   if (f == hlinfo->mouse_face_mouse_frame)
815     {
816       /* Don't do highlighting for mouse motion during the update.  */
817       hlinfo->mouse_face_defer = 1;
819         /* If the frame needs to be redrawn,
820            simply forget about any prior mouse highlighting.  */
821       if (FRAME_GARBAGED_P (f))
822         hlinfo->mouse_face_window = Qnil;
824       /* (further code for mouse faces ifdef'd out in other terms elided) */
825     }
827   unblock_input ();
831 static void
832 ns_update_window_end (struct window *w, bool cursor_on_p,
833                       bool mouse_face_overwritten_p)
834 /* --------------------------------------------------------------------------
835    Finished a grouped sequence of drawing calls
836    external (RIF) call; for one window called before update_end
837    -------------------------------------------------------------------------- */
839   /* note: this fn is nearly identical in all terms */
840   if (!w->pseudo_window_p)
841     {
842       block_input ();
844       if (cursor_on_p)
845         display_and_set_cursor (w, 1,
846                                 w->output_cursor.hpos, w->output_cursor.vpos,
847                                 w->output_cursor.x, w->output_cursor.y);
849       if (draw_window_fringes (w, 1))
850         {
851           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
852             x_draw_right_divider (w);
853           else
854             x_draw_vertical_border (w);
855         }
857       unblock_input ();
858     }
860   /* If a row with mouse-face was overwritten, arrange for
861      frame_up_to_date to redisplay the mouse highlight.  */
862   if (mouse_face_overwritten_p)
863     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
865   NSTRACE (update_window_end);
869 static void
870 ns_update_end (struct frame *f)
871 /* --------------------------------------------------------------------------
872    Finished a grouped sequence of drawing calls
873    external (RIF) call; for whole frame, called after update_window_end
874    -------------------------------------------------------------------------- */
876   EmacsView *view = FRAME_NS_VIEW (f);
878 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
879   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
881   block_input ();
883   [view unlockFocus];
884   [[view window] flushWindow];
886   unblock_input ();
887   ns_updating_frame = NULL;
888   NSTRACE (ns_update_end);
891 static void
892 ns_focus (struct frame *f, NSRect *r, int n)
893 /* --------------------------------------------------------------------------
894    Internal: Focus on given frame.  During small local updates this is used to
895      draw, however during large updates, ns_update_begin and ns_update_end are
896      called to wrap the whole thing, in which case these calls are stubbed out.
897      Except, on GNUstep, we accumulate the rectangle being drawn into, because
898      the back end won't do this automatically, and will just end up flushing
899      the entire window.
900    -------------------------------------------------------------------------- */
902 //  NSTRACE (ns_focus);
903 /* static int c =0;
904    fprintf (stderr, "focus: %d", c++);
905    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
906    fprintf (stderr, "\n"); */
908   if (f != ns_updating_frame)
909     {
910       NSView *view = FRAME_NS_VIEW (f);
911       if (view != focus_view)
912         {
913           if (focus_view != NULL)
914             {
915               [focus_view unlockFocus];
916               [[focus_view window] flushWindow];
917 /*debug_lock--; */
918             }
920           if (view)
921             [view lockFocus];
922           focus_view = view;
923 /*if (view) debug_lock++; */
924         }
925     }
927   /* clipping */
928   if (r)
929     {
930       [[NSGraphicsContext currentContext] saveGraphicsState];
931       if (n == 2)
932         NSRectClipList (r, 2);
933       else
934         NSRectClip (*r);
935       gsaved = YES;
936     }
940 static void
941 ns_unfocus (struct frame *f)
942 /* --------------------------------------------------------------------------
943      Internal: Remove focus on given frame
944    -------------------------------------------------------------------------- */
946 //  NSTRACE (ns_unfocus);
948   if (gsaved)
949     {
950       [[NSGraphicsContext currentContext] restoreGraphicsState];
951       gsaved = NO;
952     }
954   if (f != ns_updating_frame)
955     {
956       if (focus_view != NULL)
957         {
958           [focus_view unlockFocus];
959           [[focus_view window] flushWindow];
960           focus_view = NULL;
961 /*debug_lock--; */
962         }
963     }
967 static void
968 ns_clip_to_row (struct window *w, struct glyph_row *row,
969                 enum glyph_row_area area, BOOL gc)
970 /* --------------------------------------------------------------------------
971      Internal (but parallels other terms): Focus drawing on given row
972    -------------------------------------------------------------------------- */
974   struct frame *f = XFRAME (WINDOW_FRAME (w));
975   NSRect clip_rect;
976   int window_x, window_y, window_width;
978   window_box (w, area, &window_x, &window_y, &window_width, 0);
980   clip_rect.origin.x = window_x;
981   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
982   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
983   clip_rect.size.width = window_width;
984   clip_rect.size.height = row->visible_height;
986   ns_focus (f, &clip_rect, 1);
990 static void
991 ns_ring_bell (struct frame *f)
992 /* --------------------------------------------------------------------------
993      "Beep" routine
994    -------------------------------------------------------------------------- */
996   NSTRACE (ns_ring_bell);
997   if (visible_bell)
998     {
999       NSAutoreleasePool *pool;
1000       struct frame *frame = SELECTED_FRAME ();
1001       NSView *view;
1003       block_input ();
1004       pool = [[NSAutoreleasePool alloc] init];
1006       view = FRAME_NS_VIEW (frame);
1007       if (view != nil)
1008         {
1009           NSRect r, surr;
1010           NSPoint dim = NSMakePoint (128, 128);
1012           r = [view bounds];
1013           r.origin.x += (r.size.width - dim.x) / 2;
1014           r.origin.y += (r.size.height - dim.y) / 2;
1015           r.size.width = dim.x;
1016           r.size.height = dim.y;
1017           surr = NSInsetRect (r, -2, -2);
1018           ns_focus (frame, &surr, 1);
1019           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
1020           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
1021                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
1022           NSRectFill (r);
1023           [[view window] flushWindow];
1024           ns_timeout (150000);
1025           [[view window] restoreCachedImage];
1026           [[view window] flushWindow];
1027           ns_unfocus (frame);
1028         }
1029       [pool release];
1030       unblock_input ();
1031     }
1032   else
1033     {
1034       NSBeep ();
1035     }
1038 /* ==========================================================================
1040     Frame / window manager related functions
1042    ========================================================================== */
1045 static void
1046 ns_raise_frame (struct frame *f)
1047 /* --------------------------------------------------------------------------
1048      Bring window to foreground and make it active
1049    -------------------------------------------------------------------------- */
1051   NSView *view;
1052   check_window_system (f);
1053   view = FRAME_NS_VIEW (f);
1054   block_input ();
1055   if (FRAME_VISIBLE_P (f))
1056     [[view window] makeKeyAndOrderFront: NSApp];
1057   unblock_input ();
1061 static void
1062 ns_lower_frame (struct frame *f)
1063 /* --------------------------------------------------------------------------
1064      Send window to back
1065    -------------------------------------------------------------------------- */
1067   NSView *view;
1068   check_window_system (f);
1069   view = FRAME_NS_VIEW (f);
1070   block_input ();
1071   [[view window] orderBack: NSApp];
1072   unblock_input ();
1076 static void
1077 ns_frame_raise_lower (struct frame *f, bool raise)
1078 /* --------------------------------------------------------------------------
1079      External (hook)
1080    -------------------------------------------------------------------------- */
1082   NSTRACE (ns_frame_raise_lower);
1084   if (raise)
1085     ns_raise_frame (f);
1086   else
1087     ns_lower_frame (f);
1091 static void
1092 ns_frame_rehighlight (struct frame *frame)
1093 /* --------------------------------------------------------------------------
1094      External (hook): called on things like window switching within frame
1095    -------------------------------------------------------------------------- */
1097   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1098   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1100   NSTRACE (ns_frame_rehighlight);
1101   if (dpyinfo->x_focus_frame)
1102     {
1103       dpyinfo->x_highlight_frame
1104         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1105            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1106            : dpyinfo->x_focus_frame);
1107       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1108         {
1109           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1110           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1111         }
1112     }
1113   else
1114       dpyinfo->x_highlight_frame = 0;
1116   if (dpyinfo->x_highlight_frame &&
1117          dpyinfo->x_highlight_frame != old_highlight)
1118     {
1119       if (old_highlight)
1120         {
1121           x_update_cursor (old_highlight, 1);
1122           x_set_frame_alpha (old_highlight);
1123         }
1124       if (dpyinfo->x_highlight_frame)
1125         {
1126           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1127           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1128         }
1129     }
1133 void
1134 x_make_frame_visible (struct frame *f)
1135 /* --------------------------------------------------------------------------
1136      External: Show the window (X11 semantics)
1137    -------------------------------------------------------------------------- */
1139   NSTRACE (x_make_frame_visible);
1140   /* XXX: at some points in past this was not needed, as the only place that
1141      called this (frame.c:Fraise_frame ()) also called raise_lower;
1142      if this ends up the case again, comment this out again. */
1143   if (!FRAME_VISIBLE_P (f))
1144     {
1145       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1147       SET_FRAME_VISIBLE (f, 1);
1148       ns_raise_frame (f);
1150       /* Making a new frame from a fullscreen frame will make the new frame
1151          fullscreen also.  So skip handleFS as this will print an error.  */
1152       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1153           && [view isFullscreen])
1154         return;
1156       if (f->want_fullscreen != FULLSCREEN_NONE)
1157         {
1158           block_input ();
1159           [view handleFS];
1160           unblock_input ();
1161         }
1162     }
1166 void
1167 x_make_frame_invisible (struct frame *f)
1168 /* --------------------------------------------------------------------------
1169      External: Hide the window (X11 semantics)
1170    -------------------------------------------------------------------------- */
1172   NSView *view;
1173   NSTRACE (x_make_frame_invisible);
1174   check_window_system (f);
1175   view = FRAME_NS_VIEW (f);
1176   [[view window] orderOut: NSApp];
1177   SET_FRAME_VISIBLE (f, 0);
1178   SET_FRAME_ICONIFIED (f, 0);
1182 void
1183 x_iconify_frame (struct frame *f)
1184 /* --------------------------------------------------------------------------
1185      External: Iconify window
1186    -------------------------------------------------------------------------- */
1188   NSView *view;
1189   struct ns_display_info *dpyinfo;
1191   NSTRACE (x_iconify_frame);
1192   check_window_system (f);
1193   view = FRAME_NS_VIEW (f);
1194   dpyinfo = FRAME_DISPLAY_INFO (f);
1196   if (dpyinfo->x_highlight_frame == f)
1197     dpyinfo->x_highlight_frame = 0;
1199   if ([[view window] windowNumber] <= 0)
1200     {
1201       /* the window is still deferred.  Make it very small, bring it
1202          on screen and order it out. */
1203       NSRect s = { { 100, 100}, {0, 0} };
1204       NSRect t;
1205       t = [[view window] frame];
1206       [[view window] setFrame: s display: NO];
1207       [[view window] orderBack: NSApp];
1208       [[view window] orderOut: NSApp];
1209       [[view window] setFrame: t display: NO];
1210     }
1211   [[view window] miniaturize: NSApp];
1214 /* Free X resources of frame F.  */
1216 void
1217 x_free_frame_resources (struct frame *f)
1219   NSView *view;
1220   struct ns_display_info *dpyinfo;
1221   Mouse_HLInfo *hlinfo;
1223   NSTRACE (x_free_frame_resources);
1224   check_window_system (f);
1225   view = FRAME_NS_VIEW (f);
1226   dpyinfo = FRAME_DISPLAY_INFO (f);
1227   hlinfo = MOUSE_HL_INFO (f);
1229   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1231   block_input ();
1233   free_frame_menubar (f);
1234   free_frame_faces (f);
1236   if (f == dpyinfo->x_focus_frame)
1237     dpyinfo->x_focus_frame = 0;
1238   if (f == dpyinfo->x_highlight_frame)
1239     dpyinfo->x_highlight_frame = 0;
1240   if (f == hlinfo->mouse_face_mouse_frame)
1241     reset_mouse_highlight (hlinfo);
1243   if (f->output_data.ns->miniimage != nil)
1244     [f->output_data.ns->miniimage release];
1246   [[view window] close];
1247   [view release];
1249   xfree (f->output_data.ns);
1251   unblock_input ();
1254 void
1255 x_destroy_window (struct frame *f)
1256 /* --------------------------------------------------------------------------
1257      External: Delete the window
1258    -------------------------------------------------------------------------- */
1260   NSTRACE (x_destroy_window);
1261   check_window_system (f);
1262   x_free_frame_resources (f);
1263   ns_window_num--;
1267 void
1268 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1269 /* --------------------------------------------------------------------------
1270      External: Position the window
1271    -------------------------------------------------------------------------- */
1273   NSView *view = FRAME_NS_VIEW (f);
1274   NSArray *screens = [NSScreen screens];
1275   NSScreen *fscreen = [screens objectAtIndex: 0];
1276   NSScreen *screen = [[view window] screen];
1278   NSTRACE (x_set_offset);
1280   block_input ();
1282   f->left_pos = xoff;
1283   f->top_pos = yoff;
1285   if (view != nil && screen && fscreen)
1286     {
1287       f->left_pos = f->size_hint_flags & XNegative
1288         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1289         : f->left_pos;
1290       /* We use visibleFrame here to take menu bar into account.
1291          Ideally we should also adjust left/top with visibleFrame.origin.  */
1293       f->top_pos = f->size_hint_flags & YNegative
1294         ? ([screen visibleFrame].size.height + f->top_pos
1295            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1296            - FRAME_TOOLBAR_HEIGHT (f))
1297         : f->top_pos;
1298 #ifdef NS_IMPL_GNUSTEP
1299       if (f->left_pos < 100)
1300         f->left_pos = 100;  /* don't overlap menu */
1301 #endif
1302       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1303          menu bar.  */
1304       [[view window] setFrameTopLeftPoint:
1305                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1306                                     SCREENMAXBOUND ([fscreen frame].size.height
1307                                                     - NS_TOP_POS (f)))];
1308       f->size_hint_flags &= ~(XNegative|YNegative);
1309     }
1311   unblock_input ();
1315 void
1316 x_set_window_size (struct frame *f,
1317                    bool change_gravity,
1318                    int width,
1319                    int height,
1320                    bool pixelwise)
1321 /* --------------------------------------------------------------------------
1322      Adjust window pixel size based on given character grid size
1323      Impl is a bit more complex than other terms, need to do some
1324      internal clipping.
1325    -------------------------------------------------------------------------- */
1327   EmacsView *view = FRAME_NS_VIEW (f);
1328   NSWindow *window = [view window];
1329   NSRect wr = [window frame];
1330   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1331   int pixelwidth, pixelheight;
1332   int rows, cols;
1334   NSTRACE (x_set_window_size);
1336   if (view == nil)
1337     return;
1339 /*fprintf (stderr, "\tsetWindowSize: %d x %d, pixelwise %d, font size %d x %d\n", width, height, pixelwise, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));*/
1341   block_input ();
1343   if (pixelwise)
1344     {
1345       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1346       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1347       cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
1348       rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
1349     }
1350   else
1351     {
1352       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1353       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1354       cols = width;
1355       rows = height;
1356     }
1358   /* If we have a toolbar, take its height into account. */
1359   if (tb && ! [view isFullscreen])
1360     {
1361     /* NOTE: previously this would generate wrong result if toolbar not
1362              yet displayed and fixing toolbar_height=32 helped, but
1363              now (200903) seems no longer needed */
1364     FRAME_TOOLBAR_HEIGHT (f) =
1365       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1366         - FRAME_NS_TITLEBAR_HEIGHT (f);
1367 #ifdef NS_IMPL_GNUSTEP
1368       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1369 #endif
1370     }
1371   else
1372     FRAME_TOOLBAR_HEIGHT (f) = 0;
1374   wr.size.width = pixelwidth + f->border_width;
1375   wr.size.height = pixelheight;
1376   if (! [view isFullscreen])
1377     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1378       + FRAME_TOOLBAR_HEIGHT (f);
1380   /* Do not try to constrain to this screen.  We may have multiple
1381      screens, and want Emacs to span those.  Constraining to screen
1382      prevents that, and that is not nice to the user.  */
1383  if (f->output_data.ns->zooming)
1384    f->output_data.ns->zooming = 0;
1385  else
1386    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1388   [view setRows: rows andColumns: cols];
1389   [window setFrame: wr display: YES];
1391   /* This is a trick to compensate for Emacs' managing the scrollbar area
1392      as a fixed number of standard character columns.  Instead of leaving
1393      blank space for the extra, we chopped it off above.  Now for
1394      left-hand scrollbars, we shift all rendering to the left by the
1395      difference between the real width and Emacs' imagined one.  For
1396      right-hand bars, don't worry about it since the extra is never used.
1397      (Obviously doesn't work for vertically split windows tho..) */
1398   {
1399     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1400       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1401                      - NS_SCROLL_BAR_WIDTH (f), 0)
1402       : NSMakePoint (0, 0);
1403     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1404     [view setBoundsOrigin: origin];
1405   }
1407   [view updateFrameSize: NO];
1408   unblock_input ();
1412 static void
1413 ns_fullscreen_hook (struct frame *f)
1415   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1417   if (!FRAME_VISIBLE_P (f))
1418     return;
1420    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1421     {
1422       /* Old style fs don't initiate correctly if created from
1423          init/default-frame alist, so use a timer (not nice...).
1424       */
1425       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1426                                      selector: @selector (handleFS)
1427                                      userInfo: nil repeats: NO];
1428       return;
1429     }
1431   block_input ();
1432   [view handleFS];
1433   unblock_input ();
1436 /* ==========================================================================
1438     Color management
1440    ========================================================================== */
1443 NSColor *
1444 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1446   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1447   if (idx < 1 || idx >= color_table->avail)
1448     return nil;
1449   return color_table->colors[idx];
1453 unsigned long
1454 ns_index_color (NSColor *color, struct frame *f)
1456   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1457   ptrdiff_t idx;
1458   ptrdiff_t i;
1460   if (!color_table->colors)
1461     {
1462       color_table->size = NS_COLOR_CAPACITY;
1463       color_table->avail = 1; /* skip idx=0 as marker */
1464       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1465       color_table->colors[0] = nil;
1466       color_table->empty_indices = [[NSMutableSet alloc] init];
1467     }
1469   /* Do we already have this color?  */
1470   for (i = 1; i < color_table->avail; i++)
1471     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1472       return i;
1474   if ([color_table->empty_indices count] > 0)
1475     {
1476       NSNumber *index = [color_table->empty_indices anyObject];
1477       [color_table->empty_indices removeObject: index];
1478       idx = [index unsignedLongValue];
1479     }
1480   else
1481     {
1482       if (color_table->avail == color_table->size)
1483         color_table->colors =
1484           xpalloc (color_table->colors, &color_table->size, 1,
1485                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1486       idx = color_table->avail++;
1487     }
1489   color_table->colors[idx] = color;
1490   [color retain];
1491 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1492   return idx;
1496 void
1497 ns_free_indexed_color (unsigned long idx, struct frame *f)
1499   struct ns_color_table *color_table;
1500   NSColor *color;
1501   NSNumber *index;
1503   if (!f)
1504     return;
1506   color_table = FRAME_DISPLAY_INFO (f)->color_table;
1508   if (idx <= 0 || idx >= color_table->size) {
1509     message1 ("ns_free_indexed_color: Color index out of range.\n");
1510     return;
1511   }
1513   index = [NSNumber numberWithUnsignedInt: idx];
1514   if ([color_table->empty_indices containsObject: index]) {
1515     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1516     return;
1517   }
1519   color = color_table->colors[idx];
1520   [color release];
1521   color_table->colors[idx] = nil;
1522   [color_table->empty_indices addObject: index];
1523 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1527 static int
1528 ns_get_color (const char *name, NSColor **col)
1529 /* --------------------------------------------------------------------------
1530      Parse a color name
1531    -------------------------------------------------------------------------- */
1532 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1533    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1534    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1536   NSColor *new = nil;
1537   static char hex[20];
1538   int scaling;
1539   float r = -1.0, g, b;
1540   NSString *nsname = [NSString stringWithUTF8String: name];
1542 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1543   block_input ();
1545   if ([nsname isEqualToString: @"ns_selection_bg_color"])
1546     {
1547 #ifdef NS_IMPL_COCOA
1548       NSString *defname = [[NSUserDefaults standardUserDefaults]
1549                             stringForKey: @"AppleHighlightColor"];
1550       if (defname != nil)
1551         nsname = defname;
1552       else
1553 #endif
1554       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1555         {
1556           *col = [new colorUsingDefaultColorSpace];
1557           unblock_input ();
1558           return 0;
1559         }
1560       else
1561         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1563       name = [nsname UTF8String];
1564     }
1565   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1566     {
1567       /* NOTE: OSX applications normally don't set foreground selection, but
1568          text may be unreadable if we don't.
1569       */
1570       if ((new = [NSColor selectedTextColor]) != nil)
1571         {
1572           *col = [new colorUsingDefaultColorSpace];
1573           unblock_input ();
1574           return 0;
1575         }
1577       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1578       name = [nsname UTF8String];
1579     }
1581   /* First, check for some sort of numeric specification. */
1582   hex[0] = '\0';
1584   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1585     {
1586       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1587       [scanner scanFloat: &r];
1588       [scanner scanFloat: &g];
1589       [scanner scanFloat: &b];
1590     }
1591   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1592     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1593   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1594     {
1595       int len = (strlen(name) - 1);
1596       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1597       int i;
1598       scaling = strlen(name+start) / 3;
1599       for (i = 0; i < 3; i++)
1600         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1601                  name + start + i * scaling);
1602       hex[3 * (scaling + 1) - 1] = '\0';
1603     }
1605   if (hex[0])
1606     {
1607       int rr, gg, bb;
1608       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1609       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1610         {
1611           r = rr / fscale;
1612           g = gg / fscale;
1613           b = bb / fscale;
1614         }
1615     }
1617   if (r >= 0.0F)
1618     {
1619       *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
1620       unblock_input ();
1621       return 0;
1622     }
1624   /* Otherwise, color is expected to be from a list */
1625   {
1626     NSEnumerator *lenum, *cenum;
1627     NSString *name;
1628     NSColorList *clist;
1630 #ifdef NS_IMPL_GNUSTEP
1631     /* XXX: who is wrong, the requestor or the implementation? */
1632     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1633         == NSOrderedSame)
1634       nsname = @"highlightColor";
1635 #endif
1637     lenum = [[NSColorList availableColorLists] objectEnumerator];
1638     while ( (clist = [lenum nextObject]) && new == nil)
1639       {
1640         cenum = [[clist allKeys] objectEnumerator];
1641         while ( (name = [cenum nextObject]) && new == nil )
1642           {
1643             if ([name compare: nsname
1644                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1645               new = [clist colorWithKey: name];
1646           }
1647       }
1648   }
1650   if (new)
1651     *col = [new colorUsingDefaultColorSpace];
1652   unblock_input ();
1653   return new ? 0 : 1;
1658 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1659 /* --------------------------------------------------------------------------
1660      Convert a Lisp string object to a NS color
1661    -------------------------------------------------------------------------- */
1663   NSTRACE (ns_lisp_to_color);
1664   if (STRINGP (color))
1665     return ns_get_color (SSDATA (color), col);
1666   else if (SYMBOLP (color))
1667     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1668   return 1;
1672 Lisp_Object
1673 ns_color_to_lisp (NSColor *col)
1674 /* --------------------------------------------------------------------------
1675      Convert a color to a lisp string with the RGB equivalent
1676    -------------------------------------------------------------------------- */
1678   EmacsCGFloat red, green, blue, alpha, gray;
1679   char buf[1024];
1680   const char *str;
1681   NSTRACE (ns_color_to_lisp);
1683   block_input ();
1684   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1686       if ((str =[[col colorNameComponent] UTF8String]))
1687         {
1688           unblock_input ();
1689           return build_string ((char *)str);
1690         }
1692     [[col colorUsingDefaultColorSpace]
1693         getRed: &red green: &green blue: &blue alpha: &alpha];
1694   if (red == green && red == blue)
1695     {
1696       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1697             getWhite: &gray alpha: &alpha];
1698       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1699                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1700       unblock_input ();
1701       return build_string (buf);
1702     }
1704   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1705             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1707   unblock_input ();
1708   return build_string (buf);
1712 void
1713 ns_query_color(void *col, XColor *color_def, int setPixel)
1714 /* --------------------------------------------------------------------------
1715          Get ARGB values out of NSColor col and put them into color_def.
1716          If setPixel, set the pixel to a concatenated version.
1717          and set color_def pixel to the resulting index.
1718    -------------------------------------------------------------------------- */
1720   EmacsCGFloat r, g, b, a;
1722   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1723   color_def->red   = r * 65535;
1724   color_def->green = g * 65535;
1725   color_def->blue  = b * 65535;
1727   if (setPixel == YES)
1728     color_def->pixel
1729       = ARGB_TO_ULONG((int)(a*255),
1730                       (int)(r*255), (int)(g*255), (int)(b*255));
1734 bool
1735 ns_defined_color (struct frame *f,
1736                   const char *name,
1737                   XColor *color_def,
1738                   bool alloc,
1739                   bool makeIndex)
1740 /* --------------------------------------------------------------------------
1741          Return true if named color found, and set color_def rgb accordingly.
1742          If makeIndex and alloc are nonzero put the color in the color_table,
1743          and set color_def pixel to the resulting index.
1744          If makeIndex is zero, set color_def pixel to ARGB.
1745          Return false if not found
1746    -------------------------------------------------------------------------- */
1748   NSColor *col;
1749   NSTRACE (ns_defined_color);
1751   block_input ();
1752   if (ns_get_color (name, &col) != 0) /* Color not found  */
1753     {
1754       unblock_input ();
1755       return 0;
1756     }
1757   if (makeIndex && alloc)
1758     color_def->pixel = ns_index_color (col, f);
1759   ns_query_color (col, color_def, !makeIndex);
1760   unblock_input ();
1761   return 1;
1765 void
1766 x_set_frame_alpha (struct frame *f)
1767 /* --------------------------------------------------------------------------
1768      change the entire-frame transparency
1769    -------------------------------------------------------------------------- */
1771   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1772   double alpha = 1.0;
1773   double alpha_min = 1.0;
1775   if (dpyinfo->x_highlight_frame == f)
1776     alpha = f->alpha[0];
1777   else
1778     alpha = f->alpha[1];
1780   if (FLOATP (Vframe_alpha_lower_limit))
1781     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1782   else if (INTEGERP (Vframe_alpha_lower_limit))
1783     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1785   if (alpha < 0.0)
1786     return;
1787   else if (1.0 < alpha)
1788     alpha = 1.0;
1789   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1790     alpha = alpha_min;
1792 #ifdef NS_IMPL_COCOA
1793   {
1794     EmacsView *view = FRAME_NS_VIEW (f);
1795   [[view window] setAlphaValue: alpha];
1796   }
1797 #endif
1801 /* ==========================================================================
1803     Mouse handling
1805    ========================================================================== */
1808 void
1809 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1810 /* --------------------------------------------------------------------------
1811      Programmatically reposition mouse pointer in pixel coordinates
1812    -------------------------------------------------------------------------- */
1814   NSTRACE (frame_set_mouse_pixel_position);
1815   ns_raise_frame (f);
1816 #if 0
1817   /* FIXME: this does not work, and what about GNUstep? */
1818 #ifdef NS_IMPL_COCOA
1819   [FRAME_NS_VIEW (f) lockFocus];
1820   PSsetmouse ((float)pix_x, (float)pix_y);
1821   [FRAME_NS_VIEW (f) unlockFocus];
1822 #endif
1823 #endif
1826 static int
1827 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1828 /*   ------------------------------------------------------------------------
1829      Called by EmacsView on mouseMovement events.  Passes on
1830      to emacs mainstream code if we moved off of a rect of interest
1831      known as last_mouse_glyph.
1832      ------------------------------------------------------------------------ */
1834   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1835   NSRect *r;
1837 //  NSTRACE (note_mouse_movement);
1839   dpyinfo->last_mouse_motion_frame = frame;
1840   r = &dpyinfo->last_mouse_glyph;
1842   /* Note, this doesn't get called for enter/leave, since we don't have a
1843      position.  Those are taken care of in the corresponding NSView methods. */
1845   /* has movement gone beyond last rect we were tracking? */
1846   if (x < r->origin.x || x >= r->origin.x + r->size.width
1847       || y < r->origin.y || y >= r->origin.y + r->size.height)
1848     {
1849       ns_update_begin (frame);
1850       frame->mouse_moved = 1;
1851       note_mouse_highlight (frame, x, y);
1852       remember_mouse_glyph (frame, x, y, r);
1853       ns_update_end (frame);
1854       return 1;
1855     }
1857   return 0;
1861 static void
1862 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1863                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1864                    Time *time)
1865 /* --------------------------------------------------------------------------
1866     External (hook): inform emacs about mouse position and hit parts.
1867     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1868     x & y should be position in the scrollbar (the whole bar, not the handle)
1869     and length of scrollbar respectively
1870    -------------------------------------------------------------------------- */
1872   id view;
1873   NSPoint position;
1874   Lisp_Object frame, tail;
1875   struct frame *f;
1876   struct ns_display_info *dpyinfo;
1878   NSTRACE (ns_mouse_position);
1880   if (*fp == NULL)
1881     {
1882       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1883       return;
1884     }
1886   dpyinfo = FRAME_DISPLAY_INFO (*fp);
1888   block_input ();
1890   /* Clear the mouse-moved flag for every frame on this display.  */
1891   FOR_EACH_FRAME (tail, frame)
1892     if (FRAME_NS_P (XFRAME (frame))
1893         && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1894       XFRAME (frame)->mouse_moved = 0;
1896   dpyinfo->last_mouse_scroll_bar = nil;
1897   if (dpyinfo->last_mouse_frame
1898       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
1899     f = dpyinfo->last_mouse_frame;
1900   else
1901     f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
1903   if (f && FRAME_NS_P (f))
1904     {
1905       view = FRAME_NS_VIEW (*fp);
1907       position = [[view window] mouseLocationOutsideOfEventStream];
1908       position = [view convertPoint: position fromView: nil];
1909       remember_mouse_glyph (f, position.x, position.y,
1910                             &dpyinfo->last_mouse_glyph);
1911 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1913       if (bar_window) *bar_window = Qnil;
1914       if (part) *part = scroll_bar_above_handle;
1916       if (x) XSETINT (*x, lrint (position.x));
1917       if (y) XSETINT (*y, lrint (position.y));
1918       if (time)
1919         *time = dpyinfo->last_mouse_movement_time;
1920       *fp = f;
1921     }
1923   unblock_input ();
1927 static void
1928 ns_frame_up_to_date (struct frame *f)
1929 /* --------------------------------------------------------------------------
1930     External (hook): Fix up mouse highlighting right after a full update.
1931     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1932    -------------------------------------------------------------------------- */
1934   NSTRACE (ns_frame_up_to_date);
1936   if (FRAME_NS_P (f))
1937     {
1938       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1939       if (f == hlinfo->mouse_face_mouse_frame)
1940         {
1941           block_input ();
1942           ns_update_begin(f);
1943           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1944                                 hlinfo->mouse_face_mouse_x,
1945                                 hlinfo->mouse_face_mouse_y);
1946           ns_update_end(f);
1947           unblock_input ();
1948         }
1949     }
1953 static void
1954 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1955 /* --------------------------------------------------------------------------
1956     External (RIF): set frame mouse pointer type.
1957    -------------------------------------------------------------------------- */
1959   NSTRACE (ns_define_frame_cursor);
1960   if (FRAME_POINTER_TYPE (f) != cursor)
1961     {
1962       EmacsView *view = FRAME_NS_VIEW (f);
1963       FRAME_POINTER_TYPE (f) = cursor;
1964       [[view window] invalidateCursorRectsForView: view];
1965       /* Redisplay assumes this function also draws the changed frame
1966          cursor, but this function doesn't, so do it explicitly.  */
1967       x_update_cursor (f, 1);
1968     }
1973 /* ==========================================================================
1975     Keyboard handling
1977    ========================================================================== */
1980 static unsigned
1981 ns_convert_key (unsigned code)
1982 /* --------------------------------------------------------------------------
1983     Internal call used by NSView-keyDown.
1984    -------------------------------------------------------------------------- */
1986   const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
1987   unsigned keysym;
1988   /* An array would be faster, but less easy to read. */
1989   for (keysym = 0; keysym < last_keysym; keysym += 2)
1990     if (code == convert_ns_to_X_keysym[keysym])
1991       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1992   return 0;
1993 /* if decide to use keyCode and Carbon table, use this line:
1994      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1998 char *
1999 x_get_keysym_name (int keysym)
2000 /* --------------------------------------------------------------------------
2001     Called by keyboard.c.  Not sure if the return val is important, except
2002     that it be unique.
2003    -------------------------------------------------------------------------- */
2005   static char value[16];
2006   NSTRACE (x_get_keysym_name);
2007   sprintf (value, "%d", keysym);
2008   return value;
2013 /* ==========================================================================
2015     Block drawing operations
2017    ========================================================================== */
2020 static void
2021 ns_redraw_scroll_bars (struct frame *f)
2023   int i;
2024   id view;
2025   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2026   NSTRACE (ns_redraw_scroll_bars);
2027   for (i =[subviews count]-1; i >= 0; i--)
2028     {
2029       view = [subviews objectAtIndex: i];
2030       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2031       [view display];
2032     }
2036 void
2037 ns_clear_frame (struct frame *f)
2038 /* --------------------------------------------------------------------------
2039       External (hook): Erase the entire frame
2040    -------------------------------------------------------------------------- */
2042   NSView *view = FRAME_NS_VIEW (f);
2043   NSRect r;
2045   NSTRACE (ns_clear_frame);
2047  /* comes on initial frame because we have
2048     after-make-frame-functions = select-frame */
2049  if (!FRAME_DEFAULT_FACE (f))
2050    return;
2052   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2054   r = [view bounds];
2056   block_input ();
2057   ns_focus (f, &r, 1);
2058   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2059   NSRectFill (r);
2060   ns_unfocus (f);
2062   /* as of 2006/11 or so this is now needed */
2063   ns_redraw_scroll_bars (f);
2064   unblock_input ();
2068 static void
2069 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2070 /* --------------------------------------------------------------------------
2071     External (RIF):  Clear section of frame
2072    -------------------------------------------------------------------------- */
2074   NSRect r = NSMakeRect (x, y, width, height);
2075   NSView *view = FRAME_NS_VIEW (f);
2076   struct face *face = FRAME_DEFAULT_FACE (f);
2078   if (!view || !face)
2079     return;
2081   NSTRACE (ns_clear_frame_area);
2083   r = NSIntersectionRect (r, [view frame]);
2084   ns_focus (f, &r, 1);
2085   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2087   NSRectFill (r);
2089   ns_unfocus (f);
2090   return;
2094 static void
2095 ns_scroll_run (struct window *w, struct run *run)
2096 /* --------------------------------------------------------------------------
2097     External (RIF):  Insert or delete n lines at line vpos
2098    -------------------------------------------------------------------------- */
2100   struct frame *f = XFRAME (w->frame);
2101   int x, y, width, height, from_y, to_y, bottom_y;
2103   NSTRACE (ns_scroll_run);
2105   /* begin copy from other terms */
2106   /* Get frame-relative bounding box of the text display area of W,
2107      without mode lines.  Include in this box the left and right
2108      fringe of W.  */
2109   window_box (w, ANY_AREA, &x, &y, &width, &height);
2111   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2112   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2113   bottom_y = y + height;
2115   if (to_y < from_y)
2116     {
2117       /* Scrolling up.  Make sure we don't copy part of the mode
2118          line at the bottom.  */
2119       if (from_y + run->height > bottom_y)
2120         height = bottom_y - from_y;
2121       else
2122         height = run->height;
2123     }
2124   else
2125     {
2126       /* Scrolling down.  Make sure we don't copy over the mode line.
2127          at the bottom.  */
2128       if (to_y + run->height > bottom_y)
2129         height = bottom_y - to_y;
2130       else
2131         height = run->height;
2132     }
2133   /* end copy from other terms */
2135   if (height == 0)
2136       return;
2138   block_input ();
2140   x_clear_cursor (w);
2142   {
2143     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2144     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2145     NSPoint dstOrigin = NSMakePoint (x, to_y);
2147     ns_focus (f, &dstRect, 1);
2148     NSCopyBits (0, srcRect , dstOrigin);
2149     ns_unfocus (f);
2150   }
2152   unblock_input ();
2156 static void
2157 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2158 /* --------------------------------------------------------------------------
2159     External (RIF): preparatory to fringe update after text was updated
2160    -------------------------------------------------------------------------- */
2162   struct frame *f;
2163   int width, height;
2165   NSTRACE (ns_after_update_window_line);
2167   /* begin copy from other terms */
2168   eassert (w);
2170   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2171     desired_row->redraw_fringe_bitmaps_p = 1;
2173   /* When a window has disappeared, make sure that no rest of
2174      full-width rows stays visible in the internal border.  */
2175   if (windows_or_buffers_changed
2176       && desired_row->full_width_p
2177       && (f = XFRAME (w->frame),
2178           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2179           width != 0)
2180       && (height = desired_row->visible_height,
2181           height > 0))
2182     {
2183       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2185       block_input ();
2186       ns_clear_frame_area (f, 0, y, width, height);
2187       ns_clear_frame_area (f,
2188                            FRAME_PIXEL_WIDTH (f) - width,
2189                            y, width, height);
2190       unblock_input ();
2191     }
2195 static void
2196 ns_shift_glyphs_for_insert (struct frame *f,
2197                            int x, int y, int width, int height,
2198                            int shift_by)
2199 /* --------------------------------------------------------------------------
2200     External (RIF): copy an area horizontally, don't worry about clearing src
2201    -------------------------------------------------------------------------- */
2203   NSRect srcRect = NSMakeRect (x, y, width, height);
2204   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2205   NSPoint dstOrigin = dstRect.origin;
2207   NSTRACE (ns_shift_glyphs_for_insert);
2209   ns_focus (f, &dstRect, 1);
2210   NSCopyBits (0, srcRect, dstOrigin);
2211   ns_unfocus (f);
2216 /* ==========================================================================
2218     Character encoding and metrics
2220    ========================================================================== */
2223 static void
2224 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2225 /* --------------------------------------------------------------------------
2226      External (RIF); compute left/right overhang of whole string and set in s
2227    -------------------------------------------------------------------------- */
2229   struct font *font = s->font;
2231   if (s->char2b)
2232     {
2233       struct font_metrics metrics;
2234       unsigned int codes[2];
2235       codes[0] = *(s->char2b);
2236       codes[1] = *(s->char2b + s->nchars - 1);
2238       font->driver->text_extents (font, codes, 2, &metrics);
2239       s->left_overhang = -metrics.lbearing;
2240       s->right_overhang
2241         = metrics.rbearing > metrics.width
2242         ? metrics.rbearing - metrics.width : 0;
2243     }
2244   else
2245     {
2246       s->left_overhang = 0;
2247       if (EQ (font->driver->type, Qns))
2248         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2249           FONT_HEIGHT (font) * 0.2 : 0;
2250       else
2251         s->right_overhang = 0;
2252     }
2257 /* ==========================================================================
2259     Fringe and cursor drawing
2261    ========================================================================== */
2264 extern int max_used_fringe_bitmap;
2265 static void
2266 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2267                       struct draw_fringe_bitmap_params *p)
2268 /* --------------------------------------------------------------------------
2269     External (RIF); fringe-related
2270    -------------------------------------------------------------------------- */
2272   struct frame *f = XFRAME (WINDOW_FRAME (w));
2273   struct face *face = p->face;
2274   static EmacsImage **bimgs = NULL;
2275   static int nBimgs = 0;
2277   /* grow bimgs if needed */
2278   if (nBimgs < max_used_fringe_bitmap)
2279     {
2280       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2281       memset (bimgs + nBimgs, 0,
2282               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2283       nBimgs = max_used_fringe_bitmap;
2284     }
2286   /* Must clip because of partially visible lines.  */
2287   ns_clip_to_row (w, row, ANY_AREA, YES);
2289   if (!p->overlay_p)
2290     {
2291       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2293       if (bx >= 0 && nx > 0)
2294         {
2295           NSRect r = NSMakeRect (bx, by, nx, ny);
2296           NSRectClip (r);
2297           [ns_lookup_indexed_color (face->background, f) set];
2298           NSRectFill (r);
2299         }
2300     }
2302   if (p->which)
2303     {
2304       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2305       EmacsImage *img = bimgs[p->which - 1];
2307       if (!img)
2308         {
2309           unsigned short *bits = p->bits + p->dh;
2310           int len = p->h;
2311           int i;
2312           unsigned char *cbits = xmalloc (len);
2314           for (i = 0; i < len; i++)
2315             cbits[i] = ~(bits[i] & 0xff);
2316           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2317                                            flip: NO];
2318           bimgs[p->which - 1] = img;
2319           xfree (cbits);
2320         }
2322       NSRectClip (r);
2323       /* Since we composite the bitmap instead of just blitting it, we need
2324          to erase the whole background. */
2325       [ns_lookup_indexed_color(face->background, f) set];
2326       NSRectFill (r);
2328       {
2329         NSColor *bm_color;
2330         if (!p->cursor_p)
2331           bm_color = ns_lookup_indexed_color(face->foreground, f);
2332         else if (p->overlay_p)
2333           bm_color = ns_lookup_indexed_color(face->background, f);
2334         else
2335           bm_color = f->output_data.ns->cursor_color;
2336         [img setXBMColor: bm_color];
2337       }
2339 #ifdef NS_IMPL_COCOA
2340       [img drawInRect: r
2341               fromRect: NSZeroRect
2342              operation: NSCompositeSourceOver
2343               fraction: 1.0
2344            respectFlipped: YES
2345                 hints: nil];
2346 #else
2347       {
2348         NSPoint pt = r.origin;
2349         pt.y += p->h;
2350         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2351       }
2352 #endif
2353     }
2354   ns_unfocus (f);
2358 static void
2359 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2360                        int x, int y, enum text_cursor_kinds cursor_type,
2361                        int cursor_width, bool on_p, bool active_p)
2362 /* --------------------------------------------------------------------------
2363      External call (RIF): draw cursor.
2364      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2365    -------------------------------------------------------------------------- */
2367   NSRect r, s;
2368   int fx, fy, h, cursor_height;
2369   struct frame *f = WINDOW_XFRAME (w);
2370   struct glyph *phys_cursor_glyph;
2371   struct glyph *cursor_glyph;
2372   struct face *face;
2373   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2375   /* If cursor is out of bounds, don't draw garbage.  This can happen
2376      in mini-buffer windows when switching between echo area glyphs
2377      and mini-buffer.  */
2379   NSTRACE (dumpcursor);
2381   if (!on_p)
2382     return;
2384   w->phys_cursor_type = cursor_type;
2385   w->phys_cursor_on_p = on_p;
2387   if (cursor_type == NO_CURSOR)
2388     {
2389       w->phys_cursor_width = 0;
2390       return;
2391     }
2393   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2394     {
2395       if (glyph_row->exact_window_width_line_p
2396           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2397         {
2398           glyph_row->cursor_in_fringe_p = 1;
2399           draw_fringe_bitmap (w, glyph_row, 0);
2400         }
2401       return;
2402     }
2404   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2405      (other terminals do it the other way round).  We must set
2406      w->phys_cursor_width to the cursor width.  For bar cursors, that
2407      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2408   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2410   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2411      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2412   if (cursor_type == BAR_CURSOR)
2413     {
2414       if (cursor_width < 1)
2415         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2416       w->phys_cursor_width = cursor_width;
2417     }
2418   /* If we have an HBAR, "cursor_width" MAY specify height. */
2419   else if (cursor_type == HBAR_CURSOR)
2420     {
2421       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2422       if (cursor_height > glyph_row->height)
2423         cursor_height = glyph_row->height;
2424       if (h > cursor_height) // Cursor smaller than line height, move down
2425         fy += h - cursor_height;
2426       h = cursor_height;
2427     }
2429   r.origin.x = fx, r.origin.y = fy;
2430   r.size.height = h;
2431   r.size.width = w->phys_cursor_width;
2433   /* TODO: only needed in rare cases with last-resort font in HELLO..
2434      should we do this more efficiently? */
2435   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2438   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2439   if (face && NS_FACE_BACKGROUND (face)
2440       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2441     {
2442       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2443       hollow_color = FRAME_CURSOR_COLOR (f);
2444     }
2445   else
2446     [FRAME_CURSOR_COLOR (f) set];
2448 #ifdef NS_IMPL_COCOA
2449   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2450            atomic.  Cleaner ways of doing this should be investigated.
2451            One way would be to set a global variable DRAWING_CURSOR
2452            when making the call to draw_phys..(), don't focus in that
2453            case, then move the ns_unfocus() here after that call. */
2454   NSDisableScreenUpdates ();
2455 #endif
2457   switch (cursor_type)
2458     {
2459     case NO_CURSOR:
2460       break;
2461     case FILLED_BOX_CURSOR:
2462       NSRectFill (r);
2463       break;
2464     case HOLLOW_BOX_CURSOR:
2465       NSRectFill (r);
2466       [hollow_color set];
2467       NSRectFill (NSInsetRect (r, 1, 1));
2468       [FRAME_CURSOR_COLOR (f) set];
2469       break;
2470     case HBAR_CURSOR:
2471       NSRectFill (r);
2472       break;
2473     case BAR_CURSOR:
2474       s = r;
2475       /* If the character under cursor is R2L, draw the bar cursor
2476          on the right of its glyph, rather than on the left.  */
2477       cursor_glyph = get_phys_cursor_glyph (w);
2478       if ((cursor_glyph->resolved_level & 1) != 0)
2479         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2481       NSRectFill (s);
2482       break;
2483     }
2484   ns_unfocus (f);
2486   /* draw the character under the cursor */
2487   if (cursor_type != NO_CURSOR)
2488     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2490 #ifdef NS_IMPL_COCOA
2491   NSEnableScreenUpdates ();
2492 #endif
2497 static void
2498 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2499 /* --------------------------------------------------------------------------
2500      External (RIF): Draw a vertical line.
2501    -------------------------------------------------------------------------- */
2503   struct frame *f = XFRAME (WINDOW_FRAME (w));
2504   struct face *face;
2505   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2507   NSTRACE (ns_draw_vertical_window_border);
2509   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2510   if (face)
2511       [ns_lookup_indexed_color(face->foreground, f) set];
2513   ns_focus (f, &r, 1);
2514   NSRectFill(r);
2515   ns_unfocus (f);
2519 static void
2520 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2521 /* --------------------------------------------------------------------------
2522      External (RIF): Draw a window divider.
2523    -------------------------------------------------------------------------- */
2525   struct frame *f = XFRAME (WINDOW_FRAME (w));
2526   struct face *face;
2527   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2529   NSTRACE (ns_draw_window_divider);
2531   face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2532   if (face)
2533       [ns_lookup_indexed_color(face->foreground, f) set];
2535   ns_focus (f, &r, 1);
2536   NSRectFill(r);
2537   ns_unfocus (f);
2540 static void
2541 ns_show_hourglass (struct frame *f)
2543   /* TODO: add NSProgressIndicator to all frames.  */
2546 static void
2547 ns_hide_hourglass (struct frame *f)
2549   /* TODO: remove NSProgressIndicator from all frames.  */
2552 /* ==========================================================================
2554     Glyph drawing operations
2556    ========================================================================== */
2558 static int
2559 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2560 /* --------------------------------------------------------------------------
2561     Wrapper utility to account for internal border width on full-width lines,
2562     and allow top full-width rows to hit the frame top.  nr should be pointer
2563     to two successive NSRects.  Number of rects actually used is returned.
2564    -------------------------------------------------------------------------- */
2566   int n = get_glyph_string_clip_rects (s, nr, 2);
2567   return n;
2570 /* --------------------------------------------------------------------
2571    Draw a wavy line under glyph string s. The wave fills wave_height
2572    pixels from y.
2574                     x          wave_length = 2
2575                                  --
2576                 y    *   *   *   *   *
2577                      |* * * * * * * * *
2578     wave_height = 3  | *   *   *   *
2579   --------------------------------------------------------------------- */
2581 static void
2582 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2584   int wave_height = 3, wave_length = 2;
2585   int y, dx, dy, odd, xmax;
2586   NSPoint a, b;
2587   NSRect waveClip;
2589   dx = wave_length;
2590   dy = wave_height - 1;
2591   y =  s->ybase - wave_height + 3;
2592   xmax = x + width;
2594   /* Find and set clipping rectangle */
2595   waveClip = NSMakeRect (x, y, width, wave_height);
2596   [[NSGraphicsContext currentContext] saveGraphicsState];
2597   NSRectClip (waveClip);
2599   /* Draw the waves */
2600   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2601   b.x = a.x + dx;
2602   odd = (int)(a.x/dx) % 2;
2603   a.y = b.y = y + 0.5;
2605   if (odd)
2606     a.y += dy;
2607   else
2608     b.y += dy;
2610   while (a.x <= xmax)
2611     {
2612       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2613       a.x = b.x, a.y = b.y;
2614       b.x += dx, b.y = y + 0.5 + odd*dy;
2615       odd = !odd;
2616     }
2618   /* Restore previous clipping rectangle(s) */
2619   [[NSGraphicsContext currentContext] restoreGraphicsState];
2624 void
2625 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2626                          NSColor *defaultCol, CGFloat width, CGFloat x)
2627 /* --------------------------------------------------------------------------
2628    Draw underline, overline, and strike-through on glyph string s.
2629    -------------------------------------------------------------------------- */
2631   if (s->for_overlaps)
2632     return;
2634   /* Do underline. */
2635   if (face->underline_p)
2636     {
2637       if (s->face->underline_type == FACE_UNDER_WAVE)
2638         {
2639           if (face->underline_defaulted_p)
2640             [defaultCol set];
2641           else
2642             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2644           ns_draw_underwave (s, width, x);
2645         }
2646       else if (s->face->underline_type == FACE_UNDER_LINE)
2647         {
2649           NSRect r;
2650           unsigned long thickness, position;
2652           /* If the prev was underlined, match its appearance. */
2653           if (s->prev && s->prev->face->underline_p
2654               && s->prev->face->underline_type == FACE_UNDER_LINE
2655               && s->prev->underline_thickness > 0)
2656             {
2657               thickness = s->prev->underline_thickness;
2658               position = s->prev->underline_position;
2659             }
2660           else
2661             {
2662               struct font *font;
2663               unsigned long descent;
2665               font=s->font;
2666               descent = s->y + s->height - s->ybase;
2668               /* Use underline thickness of font, defaulting to 1. */
2669               thickness = (font && font->underline_thickness > 0)
2670                 ? font->underline_thickness : 1;
2672               /* Determine the offset of underlining from the baseline. */
2673               if (x_underline_at_descent_line)
2674                 position = descent - thickness;
2675               else if (x_use_underline_position_properties
2676                        && font && font->underline_position >= 0)
2677                 position = font->underline_position;
2678               else if (font)
2679                 position = lround (font->descent / 2);
2680               else
2681                 position = underline_minimum_offset;
2683               position = max (position, underline_minimum_offset);
2685               /* Ensure underlining is not cropped. */
2686               if (descent <= position)
2687                 {
2688                   position = descent - 1;
2689                   thickness = 1;
2690                 }
2691               else if (descent < position + thickness)
2692                 thickness = 1;
2693             }
2695           s->underline_thickness = thickness;
2696           s->underline_position = position;
2698           r = NSMakeRect (x, s->ybase + position, width, thickness);
2700           if (face->underline_defaulted_p)
2701             [defaultCol set];
2702           else
2703             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2704           NSRectFill (r);
2705         }
2706     }
2707   /* Do overline. We follow other terms in using a thickness of 1
2708      and ignoring overline_margin. */
2709   if (face->overline_p)
2710     {
2711       NSRect r;
2712       r = NSMakeRect (x, s->y, width, 1);
2714       if (face->overline_color_defaulted_p)
2715         [defaultCol set];
2716       else
2717         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2718       NSRectFill (r);
2719     }
2721   /* Do strike-through.  We follow other terms for thickness and
2722      vertical position.*/
2723   if (face->strike_through_p)
2724     {
2725       NSRect r;
2726       unsigned long dy;
2728       dy = lrint ((s->height - 1) / 2);
2729       r = NSMakeRect (x, s->y + dy, width, 1);
2731       if (face->strike_through_color_defaulted_p)
2732         [defaultCol set];
2733       else
2734         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2735       NSRectFill (r);
2736     }
2739 static void
2740 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2741              char left_p, char right_p)
2742 /* --------------------------------------------------------------------------
2743     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2744     Note we can't just use an NSDrawRect command, because of the possibility
2745     of some sides not being drawn, and because the rect will be filled.
2746    -------------------------------------------------------------------------- */
2748   NSRect s = r;
2749   [col set];
2751   /* top, bottom */
2752   s.size.height = thickness;
2753   NSRectFill (s);
2754   s.origin.y += r.size.height - thickness;
2755   NSRectFill (s);
2757   s.size.height = r.size.height;
2758   s.origin.y = r.origin.y;
2760   /* left, right (optional) */
2761   s.size.width = thickness;
2762   if (left_p)
2763     NSRectFill (s);
2764   if (right_p)
2765     {
2766       s.origin.x += r.size.width - thickness;
2767       NSRectFill (s);
2768     }
2772 static void
2773 ns_draw_relief (NSRect r, int thickness, char raised_p,
2774                char top_p, char bottom_p, char left_p, char right_p,
2775                struct glyph_string *s)
2776 /* --------------------------------------------------------------------------
2777     Draw a relief rect inside r, optionally leaving some sides open.
2778     Note we can't just use an NSDrawBezel command, because of the possibility
2779     of some sides not being drawn, and because the rect will be filled.
2780    -------------------------------------------------------------------------- */
2782   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2783   NSColor *newBaseCol = nil;
2784   NSRect sr = r;
2786   NSTRACE (ns_draw_relief);
2788   /* set up colors */
2790   if (s->face->use_box_color_for_shadows_p)
2791     {
2792       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2793     }
2794 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2795            && s->img->pixmap
2796            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2797        {
2798          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2799        } */
2800   else
2801     {
2802       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2803     }
2805   if (newBaseCol == nil)
2806     newBaseCol = [NSColor grayColor];
2808   if (newBaseCol != baseCol)  /* TODO: better check */
2809     {
2810       [baseCol release];
2811       baseCol = [newBaseCol retain];
2812       [lightCol release];
2813       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2814       [darkCol release];
2815       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2816     }
2818   [(raised_p ? lightCol : darkCol) set];
2820   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2822   /* top */
2823   sr.size.height = thickness;
2824   if (top_p) NSRectFill (sr);
2826   /* left */
2827   sr.size.height = r.size.height;
2828   sr.size.width = thickness;
2829   if (left_p) NSRectFill (sr);
2831   [(raised_p ? darkCol : lightCol) set];
2833   /* bottom */
2834   sr.size.width = r.size.width;
2835   sr.size.height = thickness;
2836   sr.origin.y += r.size.height - thickness;
2837   if (bottom_p) NSRectFill (sr);
2839   /* right */
2840   sr.size.height = r.size.height;
2841   sr.origin.y = r.origin.y;
2842   sr.size.width = thickness;
2843   sr.origin.x += r.size.width - thickness;
2844   if (right_p) NSRectFill (sr);
2848 static void
2849 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2850 /* --------------------------------------------------------------------------
2851       Function modeled after x_draw_glyph_string_box ().
2852       Sets up parameters for drawing.
2853    -------------------------------------------------------------------------- */
2855   int right_x, last_x;
2856   char left_p, right_p;
2857   struct glyph *last_glyph;
2858   NSRect r;
2859   int thickness;
2860   struct face *face;
2862   if (s->hl == DRAW_MOUSE_FACE)
2863     {
2864       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2865       if (!face)
2866         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2867     }
2868   else
2869     face = s->face;
2871   thickness = face->box_line_width;
2873   NSTRACE (ns_dumpglyphs_box_or_relief);
2875   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2876             ? WINDOW_RIGHT_EDGE_X (s->w)
2877             : window_box_right (s->w, s->area));
2878   last_glyph = (s->cmp || s->img
2879                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2881   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2882               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2884   left_p = (s->first_glyph->left_box_line_p
2885             || (s->hl == DRAW_MOUSE_FACE
2886                 && (s->prev == NULL || s->prev->hl != s->hl)));
2887   right_p = (last_glyph->right_box_line_p
2888              || (s->hl == DRAW_MOUSE_FACE
2889                  && (s->next == NULL || s->next->hl != s->hl)));
2891   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2893   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2894   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2895     {
2896       ns_draw_box (r, abs (thickness),
2897                    ns_lookup_indexed_color (face->box_color, s->f),
2898                   left_p, right_p);
2899     }
2900   else
2901     {
2902       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2903                      1, 1, left_p, right_p, s);
2904     }
2908 static void
2909 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2910 /* --------------------------------------------------------------------------
2911       Modeled after x_draw_glyph_string_background, which draws BG in
2912       certain cases.  Others are left to the text rendering routine.
2913    -------------------------------------------------------------------------- */
2915   NSTRACE (ns_maybe_dumpglyphs_background);
2917   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2918     {
2919       int box_line_width = max (s->face->box_line_width, 0);
2920       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2921           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2922         {
2923           struct face *face;
2924           if (s->hl == DRAW_MOUSE_FACE)
2925             {
2926               face = FACE_FROM_ID (s->f,
2927                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2928               if (!face)
2929                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2930             }
2931           else
2932             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2933           if (!face->stipple)
2934             [(NS_FACE_BACKGROUND (face) != 0
2935               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2936               : FRAME_BACKGROUND_COLOR (s->f)) set];
2937           else
2938             {
2939               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
2940               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2941             }
2943           if (s->hl != DRAW_CURSOR)
2944             {
2945               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2946                                     s->background_width,
2947                                     s->height-2*box_line_width);
2948               NSRectFill (r);
2949             }
2951           s->background_filled_p = 1;
2952         }
2953     }
2957 static void
2958 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2959 /* --------------------------------------------------------------------------
2960       Renders an image and associated borders.
2961    -------------------------------------------------------------------------- */
2963   EmacsImage *img = s->img->pixmap;
2964   int box_line_vwidth = max (s->face->box_line_width, 0);
2965   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2966   int bg_x, bg_y, bg_height;
2967   int th;
2968   char raised_p;
2969   NSRect br;
2970   struct face *face;
2971   NSColor *tdCol;
2973   NSTRACE (ns_dumpglyphs_image);
2975   if (s->face->box != FACE_NO_BOX
2976       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2977     x += abs (s->face->box_line_width);
2979   bg_x = x;
2980   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2981   bg_height = s->height;
2982   /* other terms have this, but was causing problems w/tabbar mode */
2983   /* - 2 * box_line_vwidth; */
2985   if (s->slice.x == 0) x += s->img->hmargin;
2986   if (s->slice.y == 0) y += s->img->vmargin;
2988   /* Draw BG: if we need larger area than image itself cleared, do that,
2989      otherwise, since we composite the image under NS (instead of mucking
2990      with its background color), we must clear just the image area. */
2991   if (s->hl == DRAW_MOUSE_FACE)
2992     {
2993       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2994       if (!face)
2995        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2996     }
2997   else
2998     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3000   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3002   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3003       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3004     {
3005       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3006       s->background_filled_p = 1;
3007     }
3008   else
3009     {
3010       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3011     }
3013   NSRectFill (br);
3015   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3016   if (img != nil)
3017     {
3018 #ifdef NS_IMPL_COCOA
3019       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3020       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3021                               s->slice.width, s->slice.height);
3022       [img drawInRect: dr
3023              fromRect: ir
3024              operation: NSCompositeSourceOver
3025               fraction: 1.0
3026            respectFlipped: YES
3027                 hints: nil];
3028 #else
3029       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3030                   operation: NSCompositeSourceOver];
3031 #endif
3032     }
3034   if (s->hl == DRAW_CURSOR)
3035     {
3036     [FRAME_CURSOR_COLOR (s->f) set];
3037     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3038       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3039     else
3040       /* Currently on NS img->mask is always 0. Since
3041          get_window_cursor_type specifies a hollow box cursor when on
3042          a non-masked image we never reach this clause. But we put it
3043          in in anticipation of better support for image masks on
3044          NS. */
3045       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3046     }
3047   else
3048     {
3049       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3050     }
3052   /* Draw underline, overline, strike-through. */
3053   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3055   /* Draw relief, if requested */
3056   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3057     {
3058       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3059         {
3060           th = tool_bar_button_relief >= 0 ?
3061             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3062           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3063         }
3064       else
3065         {
3066           th = abs (s->img->relief);
3067           raised_p = (s->img->relief > 0);
3068         }
3070       r.origin.x = x - th;
3071       r.origin.y = y - th;
3072       r.size.width = s->slice.width + 2*th-1;
3073       r.size.height = s->slice.height + 2*th-1;
3074       ns_draw_relief (r, th, raised_p,
3075                       s->slice.y == 0,
3076                       s->slice.y + s->slice.height == s->img->height,
3077                       s->slice.x == 0,
3078                       s->slice.x + s->slice.width == s->img->width, s);
3079     }
3081   /* If there is no mask, the background won't be seen,
3082      so draw a rectangle on the image for the cursor.
3083      Do this for all images, getting transparency right is not reliable.  */
3084   if (s->hl == DRAW_CURSOR)
3085     {
3086       int thickness = abs (s->img->relief);
3087       if (thickness == 0) thickness = 1;
3088       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3089     }
3093 static void
3094 ns_dumpglyphs_stretch (struct glyph_string *s)
3096   NSRect r[2];
3097   int n, i;
3098   struct face *face;
3099   NSColor *fgCol, *bgCol;
3101   if (!s->background_filled_p)
3102     {
3103       n = ns_get_glyph_string_clip_rect (s, r);
3104       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3106       ns_focus (s->f, r, n);
3108       if (s->hl == DRAW_MOUSE_FACE)
3109        {
3110          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3111          if (!face)
3112            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3113        }
3114       else
3115        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3117       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3118       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3120       for (i = 0; i < n; ++i)
3121         {
3122           if (!s->row->full_width_p)
3123             {
3124               int overrun, leftoverrun;
3126               /* truncate to avoid overwriting fringe and/or scrollbar */
3127               overrun = max (0, (s->x + s->background_width)
3128                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3129                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3130               r[i].size.width -= overrun;
3132               /* truncate to avoid overwriting to left of the window box */
3133               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3134                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3136               if (leftoverrun > 0)
3137                 {
3138                   r[i].origin.x += leftoverrun;
3139                   r[i].size.width -= leftoverrun;
3140                 }
3142               /* XXX: Try to work between problem where a stretch glyph on
3143                  a partially-visible bottom row will clear part of the
3144                  modeline, and another where list-buffers headers and similar
3145                  rows erroneously have visible_height set to 0.  Not sure
3146                  where this is coming from as other terms seem not to show. */
3147               r[i].size.height = min (s->height, s->row->visible_height);
3148             }
3150           [bgCol set];
3152           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3153              overwriting cursor (usually when cursor on a tab) */
3154           if (s->hl == DRAW_CURSOR)
3155             {
3156               CGFloat x, width;
3158               x = r[i].origin.x;
3159               width = s->w->phys_cursor_width;
3160               r[i].size.width -= width;
3161               r[i].origin.x += width;
3163               NSRectFill (r[i]);
3165               /* Draw overlining, etc. on the cursor. */
3166               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3167                 ns_draw_text_decoration (s, face, bgCol, width, x);
3168               else
3169                 ns_draw_text_decoration (s, face, fgCol, width, x);
3170             }
3171           else
3172             {
3173               NSRectFill (r[i]);
3174             }
3176           /* Draw overlining, etc. on the stretch glyph (or the part
3177              of the stretch glyph after the cursor). */
3178           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3179                                    r[i].origin.x);
3180         }
3181       ns_unfocus (s->f);
3182       s->background_filled_p = 1;
3183     }
3187 static void
3188 ns_draw_glyph_string (struct glyph_string *s)
3189 /* --------------------------------------------------------------------------
3190       External (RIF): Main draw-text call.
3191    -------------------------------------------------------------------------- */
3193   /* TODO (optimize): focus for box and contents draw */
3194   NSRect r[2];
3195   int n, flags;
3196   char box_drawn_p = 0;
3197   struct font *font = s->face->font;
3198   if (! font) font = FRAME_FONT (s->f);
3200   NSTRACE (ns_draw_glyph_string);
3202   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3203     {
3204       int width;
3205       struct glyph_string *next;
3207       for (width = 0, next = s->next;
3208            next && width < s->right_overhang;
3209            width += next->width, next = next->next)
3210         if (next->first_glyph->type != IMAGE_GLYPH)
3211           {
3212             if (next->first_glyph->type != STRETCH_GLYPH)
3213               {
3214                 n = ns_get_glyph_string_clip_rect (s->next, r);
3215                 ns_focus (s->f, r, n);
3216                 ns_maybe_dumpglyphs_background (s->next, 1);
3217                 ns_unfocus (s->f);
3218               }
3219             else
3220               {
3221                 ns_dumpglyphs_stretch (s->next);
3222               }
3223             next->num_clips = 0;
3224           }
3225     }
3227   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3228         && (s->first_glyph->type == CHAR_GLYPH
3229             || s->first_glyph->type == COMPOSITE_GLYPH))
3230     {
3231       n = ns_get_glyph_string_clip_rect (s, r);
3232       ns_focus (s->f, r, n);
3233       ns_maybe_dumpglyphs_background (s, 1);
3234       ns_dumpglyphs_box_or_relief (s);
3235       ns_unfocus (s->f);
3236       box_drawn_p = 1;
3237     }
3239   switch (s->first_glyph->type)
3240     {
3242     case IMAGE_GLYPH:
3243       n = ns_get_glyph_string_clip_rect (s, r);
3244       ns_focus (s->f, r, n);
3245       ns_dumpglyphs_image (s, r[0]);
3246       ns_unfocus (s->f);
3247       break;
3249     case STRETCH_GLYPH:
3250       ns_dumpglyphs_stretch (s);
3251       break;
3253     case CHAR_GLYPH:
3254     case COMPOSITE_GLYPH:
3255       n = ns_get_glyph_string_clip_rect (s, r);
3256       ns_focus (s->f, r, n);
3258       if (s->for_overlaps || (s->cmp_from > 0
3259                               && ! s->first_glyph->u.cmp.automatic))
3260         s->background_filled_p = 1;
3261       else
3262         ns_maybe_dumpglyphs_background
3263           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3265       flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3266         (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3267          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3268           NS_DUMPGLYPH_NORMAL));
3270       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3271         {
3272           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3273           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3274           NS_FACE_FOREGROUND (s->face) = tmp;
3275         }
3277       {
3278         BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3279         int end = isComposite ? s->cmp_to : s->nchars;
3281         font->driver->draw
3282           (s, s->cmp_from, end, s->x, s->ybase,
3283            (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3284            || flags == NS_DUMPGLYPH_MOUSEFACE);
3286       }
3288       {
3289         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3290                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3291                                                    s->f)
3292                         : FRAME_FOREGROUND_COLOR (s->f));
3293         [col set];
3295         /* Draw underline, overline, strike-through. */
3296         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3297       }
3299       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3300         {
3301           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3302           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3303           NS_FACE_FOREGROUND (s->face) = tmp;
3304         }
3306       ns_unfocus (s->f);
3307       break;
3309     case GLYPHLESS_GLYPH:
3310       n = ns_get_glyph_string_clip_rect (s, r);
3311       ns_focus (s->f, r, n);
3313       if (s->for_overlaps || (s->cmp_from > 0
3314                               && ! s->first_glyph->u.cmp.automatic))
3315         s->background_filled_p = 1;
3316       else
3317         ns_maybe_dumpglyphs_background
3318           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3319       /* ... */
3320       /* Not yet implemented.  */
3321       /* ... */
3322       ns_unfocus (s->f);
3323       break;
3325     default:
3326       emacs_abort ();
3327     }
3329   /* Draw box if not done already. */
3330   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3331     {
3332       n = ns_get_glyph_string_clip_rect (s, r);
3333       ns_focus (s->f, r, n);
3334       ns_dumpglyphs_box_or_relief (s);
3335       ns_unfocus (s->f);
3336     }
3338   s->num_clips = 0;
3343 /* ==========================================================================
3345     Event loop
3347    ========================================================================== */
3350 static void
3351 ns_send_appdefined (int value)
3352 /* --------------------------------------------------------------------------
3353     Internal: post an appdefined event which EmacsApp-sendEvent will
3354               recognize and take as a command to halt the event loop.
3355    -------------------------------------------------------------------------- */
3357   /*NSTRACE (ns_send_appdefined); */
3359 #ifdef NS_IMPL_GNUSTEP
3360   // GNUstep needs postEvent to happen on the main thread.
3361   if (! [[NSThread currentThread] isMainThread])
3362     {
3363       EmacsApp *app = (EmacsApp *)NSApp;
3364       app->nextappdefined = value;
3365       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3366                             withObject:nil
3367                          waitUntilDone:YES];
3368       return;
3369     }
3370 #endif
3372   /* Only post this event if we haven't already posted one.  This will end
3373        the [NXApp run] main loop after having processed all events queued at
3374        this moment.  */
3376 #ifdef NS_IMPL_COCOA
3377   if (! send_appdefined)
3378     {
3379       /* OSX 10.10.1 swallows the AppDefined event we are sending ourselves
3380          in certain situations (rapid incoming events).
3381          So check if we have one, if not add one.  */
3382       NSEvent *appev = [NSApp nextEventMatchingMask:NSApplicationDefinedMask
3383                                           untilDate:[NSDate distantPast]
3384                                              inMode:NSDefaultRunLoopMode
3385                                             dequeue:NO];
3386       if (! appev) send_appdefined = YES;
3387     }
3388 #endif
3390   if (send_appdefined)
3391     {
3392       NSEvent *nxev;
3394       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3395       send_appdefined = NO;
3397       /* Don't need wakeup timer any more */
3398       if (timed_entry)
3399         {
3400           [timed_entry invalidate];
3401           [timed_entry release];
3402           timed_entry = nil;
3403         }
3405       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3406                                 location: NSMakePoint (0, 0)
3407                            modifierFlags: 0
3408                                timestamp: 0
3409                             windowNumber: [[NSApp mainWindow] windowNumber]
3410                                  context: [NSApp context]
3411                                  subtype: 0
3412                                    data1: value
3413                                    data2: 0];
3415       /* Post an application defined event on the event queue.  When this is
3416          received the [NXApp run] will return, thus having processed all
3417          events which are currently queued.  */
3418       [NSApp postEvent: nxev atStart: NO];
3419     }
3422 #ifdef HAVE_NATIVE_FS
3423 static void
3424 check_native_fs ()
3426   Lisp_Object frame, tail;
3428   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3429     return;
3431   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3433   FOR_EACH_FRAME (tail, frame)
3434     {
3435       struct frame *f = XFRAME (frame);
3436       if (FRAME_NS_P (f))
3437         {
3438           EmacsView *view = FRAME_NS_VIEW (f);
3439           [view updateCollectionBehavior];
3440         }
3441     }
3443 #endif
3445 /* GNUstep does not have cancelTracking.  */
3446 #ifdef NS_IMPL_COCOA
3447 /* Check if menu open should be canceled or continued as normal.  */
3448 void
3449 ns_check_menu_open (NSMenu *menu)
3451   /* Click in menu bar? */
3452   NSArray *a = [[NSApp mainMenu] itemArray];
3453   int i;
3454   BOOL found = NO;
3456   if (menu == nil) // Menu tracking ended.
3457     {
3458       if (menu_will_open_state == MENU_OPENING)
3459         menu_will_open_state = MENU_NONE;
3460       return;
3461     }
3463   for (i = 0; ! found && i < [a count]; i++)
3464     found = menu == [[a objectAtIndex:i] submenu];
3465   if (found)
3466     {
3467       if (menu_will_open_state == MENU_NONE && emacs_event)
3468         {
3469           NSEvent *theEvent = [NSApp currentEvent];
3470           struct frame *emacsframe = SELECTED_FRAME ();
3472           [menu cancelTracking];
3473           menu_will_open_state = MENU_PENDING;
3474           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3475           EV_TRAILER (theEvent);
3477           CGEventRef ourEvent = CGEventCreate (NULL);
3478           menu_mouse_point = CGEventGetLocation (ourEvent);
3479           CFRelease (ourEvent);
3480         }
3481       else if (menu_will_open_state == MENU_OPENING)
3482         {
3483           menu_will_open_state = MENU_NONE;
3484         }
3485     }
3488 /* Redo saved menu click if state is MENU_PENDING.  */
3489 void
3490 ns_check_pending_open_menu ()
3492   if (menu_will_open_state == MENU_PENDING)
3493     {
3494       CGEventSourceRef source
3495         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3497       CGEventRef event = CGEventCreateMouseEvent (source,
3498                                                   kCGEventLeftMouseDown,
3499                                                   menu_mouse_point,
3500                                                   kCGMouseButtonLeft);
3501       CGEventSetType (event, kCGEventLeftMouseDown);
3502       CGEventPost (kCGHIDEventTap, event);
3503       CFRelease (event);
3504       CFRelease (source);
3506       menu_will_open_state = MENU_OPENING;
3507     }
3509 #endif /* NS_IMPL_COCOA */
3511 static void
3512 unwind_apploopnr (Lisp_Object not_used)
3514   --apploopnr;
3515   n_emacs_events_pending = 0;
3516   ns_finish_events ();
3517   q_event_ptr = NULL;
3520 static int
3521 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3522 /* --------------------------------------------------------------------------
3523      External (hook): Post an event to ourself and keep reading events until
3524      we read it back again.  In effect process all events which were waiting.
3525      From 21+ we have to manage the event buffer ourselves.
3526    -------------------------------------------------------------------------- */
3528   struct input_event ev;
3529   int nevents;
3531 /* NSTRACE (ns_read_socket); */
3533 #ifdef HAVE_NATIVE_FS
3534   check_native_fs ();
3535 #endif
3537   if ([NSApp modalWindow] != nil)
3538     return -1;
3540   if (hold_event_q.nr > 0)
3541     {
3542       int i;
3543       for (i = 0; i < hold_event_q.nr; ++i)
3544         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3545       hold_event_q.nr = 0;
3546       return i;
3547     }
3549   block_input ();
3550   n_emacs_events_pending = 0;
3551   ns_init_events (&ev);
3552   q_event_ptr = hold_quit;
3554   /* we manage autorelease pools by allocate/reallocate each time around
3555      the loop; strict nesting is occasionally violated but seems not to
3556      matter.. earlier methods using full nesting caused major memory leaks */
3557   [outerpool release];
3558   outerpool = [[NSAutoreleasePool alloc] init];
3560   /* If have pending open-file requests, attend to the next one of those. */
3561   if (ns_pending_files && [ns_pending_files count] != 0
3562       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3563     {
3564       [ns_pending_files removeObjectAtIndex: 0];
3565     }
3566   /* Deal with pending service requests. */
3567   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3568     && [(EmacsApp *)
3569          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3570                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3571     {
3572       [ns_pending_service_names removeObjectAtIndex: 0];
3573       [ns_pending_service_args removeObjectAtIndex: 0];
3574     }
3575   else
3576     {
3577       ptrdiff_t specpdl_count = SPECPDL_INDEX ();
3578       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3579          to ourself, otherwise [NXApp run] will never exit.  */
3580       send_appdefined = YES;
3581       ns_send_appdefined (-1);
3583       if (++apploopnr != 1)
3584         {
3585           emacs_abort ();
3586         }
3587       record_unwind_protect (unwind_apploopnr, Qt);
3588       [NSApp run];
3589       unbind_to (specpdl_count, Qnil);  /* calls unwind_apploopnr */
3590     }
3592   nevents = n_emacs_events_pending;
3593   n_emacs_events_pending = 0;
3594   ns_finish_events ();
3595   q_event_ptr = NULL;
3596   unblock_input ();
3598   return nevents;
3603 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3604            fd_set *exceptfds, struct timespec const *timeout,
3605            sigset_t const *sigmask)
3606 /* --------------------------------------------------------------------------
3607      Replacement for select, checking for events
3608    -------------------------------------------------------------------------- */
3610   int result;
3611   int t, k, nr = 0;
3612   struct input_event event;
3613   char c;
3615 /*  NSTRACE (ns_select); */
3617 #ifdef HAVE_NATIVE_FS
3618   check_native_fs ();
3619 #endif
3621   if (hold_event_q.nr > 0)
3622     {
3623       /* We already have events pending. */
3624       raise (SIGIO);
3625       errno = EINTR;
3626       return -1;
3627     }
3629   for (k = 0; k < nfds+1; k++)
3630     {
3631       if (readfds && FD_ISSET(k, readfds)) ++nr;
3632       if (writefds && FD_ISSET(k, writefds)) ++nr;
3633     }
3635   if (NSApp == nil
3636       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3637     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3639   [outerpool release];
3640   outerpool = [[NSAutoreleasePool alloc] init];
3643   send_appdefined = YES;
3644   if (nr > 0)
3645     {
3646       pthread_mutex_lock (&select_mutex);
3647       select_nfds = nfds;
3648       select_valid = 0;
3649       if (readfds)
3650         {
3651           select_readfds = *readfds;
3652           select_valid += SELECT_HAVE_READ;
3653         }
3654       if (writefds)
3655         {
3656           select_writefds = *writefds;
3657           select_valid += SELECT_HAVE_WRITE;
3658         }
3660       if (timeout)
3661         {
3662           select_timeout = *timeout;
3663           select_valid += SELECT_HAVE_TMO;
3664         }
3666       pthread_mutex_unlock (&select_mutex);
3668       /* Inform fd_handler that select should be called */
3669       c = 'g';
3670       emacs_write_sig (selfds[1], &c, 1);
3671     }
3672   else if (nr == 0 && timeout)
3673     {
3674       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3675       double time = timespectod (*timeout);
3676       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3677                                                       target: NSApp
3678                                                     selector:
3679                                   @selector (timeout_handler:)
3680                                                     userInfo: 0
3681                                                      repeats: NO]
3682                       retain];
3683     }
3684   else /* No timeout and no file descriptors, can this happen?  */
3685     {
3686       /* Send appdefined so we exit from the loop */
3687       ns_send_appdefined (-1);
3688     }
3690   block_input ();
3691   ns_init_events (&event);
3692   if (++apploopnr != 1)
3693     {
3694       emacs_abort ();
3695     }
3697   {
3698     ptrdiff_t specpdl_count = SPECPDL_INDEX ();
3699     record_unwind_protect (unwind_apploopnr, Qt);
3700     [NSApp run];
3701     unbind_to (specpdl_count, Qnil);  /* calls unwind_apploopnr */
3702   }
3704   ns_finish_events ();
3705   if (nr > 0 && readfds)
3706     {
3707       c = 's';
3708       emacs_write_sig (selfds[1], &c, 1);
3709     }
3710   unblock_input ();
3712   t = last_appdefined_event_data;
3714   if (t != NO_APPDEFINED_DATA)
3715     {
3716       last_appdefined_event_data = NO_APPDEFINED_DATA;
3718       if (t == -2)
3719         {
3720           /* The NX_APPDEFINED event we received was a timeout. */
3721           result = 0;
3722         }
3723       else if (t == -1)
3724         {
3725           /* The NX_APPDEFINED event we received was the result of
3726              at least one real input event arriving.  */
3727           errno = EINTR;
3728           result = -1;
3729         }
3730       else
3731         {
3732           /* Received back from select () in fd_handler; copy the results */
3733           pthread_mutex_lock (&select_mutex);
3734           if (readfds) *readfds = select_readfds;
3735           if (writefds) *writefds = select_writefds;
3736           pthread_mutex_unlock (&select_mutex);
3737           result = t;
3738         }
3739     }
3740   else
3741     {
3742       errno = EINTR;
3743       result = -1;
3744     }
3746   return result;
3751 /* ==========================================================================
3753     Scrollbar handling
3755    ========================================================================== */
3758 static void
3759 ns_set_vertical_scroll_bar (struct window *window,
3760                            int portion, int whole, int position)
3761 /* --------------------------------------------------------------------------
3762       External (hook): Update or add scrollbar
3763    -------------------------------------------------------------------------- */
3765   Lisp_Object win;
3766   NSRect r, v;
3767   struct frame *f = XFRAME (WINDOW_FRAME (window));
3768   EmacsView *view = FRAME_NS_VIEW (f);
3769   EmacsScroller *bar;
3770   int window_y, window_height;
3771   int top, left, height, width;
3772   BOOL update_p = YES;
3774   /* optimization; display engine sends WAY too many of these.. */
3775   if (!NILP (window->vertical_scroll_bar))
3776     {
3777       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3778       if ([bar checkSamePosition: position portion: portion whole: whole])
3779         {
3780           if (view->scrollbarsNeedingUpdate == 0)
3781             {
3782               if (!windows_or_buffers_changed)
3783                   return;
3784             }
3785           else
3786             view->scrollbarsNeedingUpdate--;
3787           update_p = NO;
3788         }
3789     }
3791   NSTRACE (ns_set_vertical_scroll_bar);
3793   /* Get dimensions.  */
3794   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3795   top = window_y;
3796   height = window_height;
3797   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3798   left = WINDOW_SCROLL_BAR_AREA_X (window);
3800   r = NSMakeRect (left, top, width, height);
3801   /* the parent view is flipped, so we need to flip y value */
3802   v = [view frame];
3803   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3805   XSETWINDOW (win, window);
3806   block_input ();
3808   /* we want at least 5 lines to display a scrollbar */
3809   if (WINDOW_TOTAL_LINES (window) < 5)
3810     {
3811       if (!NILP (window->vertical_scroll_bar))
3812         {
3813           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3814           [bar removeFromSuperview];
3815           wset_vertical_scroll_bar (window, Qnil);
3816           [bar release];
3817         }
3818       ns_clear_frame_area (f, left, top, width, height);
3819       unblock_input ();
3820       return;
3821     }
3823   if (NILP (window->vertical_scroll_bar))
3824     {
3825       if (width > 0 && height > 0)
3826         ns_clear_frame_area (f, left, top, width, height);
3828       bar = [[EmacsScroller alloc] initFrame: r window: win];
3829       wset_vertical_scroll_bar (window, make_save_ptr (bar));
3830       update_p = YES;
3831     }
3832   else
3833     {
3834       NSRect oldRect;
3835       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3836       oldRect = [bar frame];
3837       r.size.width = oldRect.size.width;
3838       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3839         {
3840           if (oldRect.origin.x != r.origin.x)
3841               ns_clear_frame_area (f, left, top, width, height);
3842           [bar setFrame: r];
3843         }
3844     }
3846   if (update_p)
3847     [bar setPosition: position portion: portion whole: whole];
3848   unblock_input ();
3852 static void
3853 ns_set_horizontal_scroll_bar (struct window *window,
3854                               int portion, int whole, int position)
3855 /* --------------------------------------------------------------------------
3856       External (hook): Update or add scrollbar
3857    -------------------------------------------------------------------------- */
3859   Lisp_Object win;
3860   NSRect r, v;
3861   struct frame *f = XFRAME (WINDOW_FRAME (window));
3862   EmacsView *view = FRAME_NS_VIEW (f);
3863   EmacsScroller *bar;
3864   int top, height, left, width;
3865   int window_x, window_width;
3866   int pixel_width = WINDOW_PIXEL_WIDTH (window);
3867   BOOL update_p = YES;
3869   /* optimization; display engine sends WAY too many of these.. */
3870   if (!NILP (window->horizontal_scroll_bar))
3871     {
3872       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3873       if ([bar checkSamePosition: position portion: portion whole: whole])
3874         {
3875           if (view->scrollbarsNeedingUpdate == 0)
3876             {
3877               if (!windows_or_buffers_changed)
3878                   return;
3879             }
3880           else
3881             view->scrollbarsNeedingUpdate--;
3882           update_p = NO;
3883         }
3884     }
3886   NSTRACE (ns_set_horizontal_scroll_bar);
3888   /* Get dimensions.  */
3889   window_box (window, ANY_AREA, 0, &window_x, &window_width, 0);
3890   left = window_x;
3891   width = window_width;
3892   height = WINDOW_CONFIG_SCROLL_BAR_LINES (window) * FRAME_LINE_HEIGHT (f);
3893   top = WINDOW_SCROLL_BAR_AREA_Y (window);
3895   r = NSMakeRect (left, top, width, height);
3896   /* the parent view is flipped, so we need to flip y value */
3897   v = [view frame];
3898   /* ??????? PXW/scrollbars !!!!!!!!!!!!!!!!!!!! */
3899   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3901   XSETWINDOW (win, window);
3902   block_input ();
3904   if (WINDOW_TOTAL_COLS (window) < 5)
3905     {
3906       if (!NILP (window->horizontal_scroll_bar))
3907         {
3908           bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3909           [bar removeFromSuperview];
3910           wset_horizontal_scroll_bar (window, Qnil);
3911         }
3912       ns_clear_frame_area (f, left, top, width, height);
3913       unblock_input ();
3914       return;
3915     }
3917   if (NILP (window->horizontal_scroll_bar))
3918     {
3919       if (width > 0 && height > 0)
3920         ns_clear_frame_area (f, left, top, width, height);
3922       bar = [[EmacsScroller alloc] initFrame: r window: win];
3923       wset_horizontal_scroll_bar (window, make_save_ptr (bar));
3924       update_p = YES;
3925     }
3926   else
3927     {
3928       NSRect oldRect;
3929       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3930       oldRect = [bar frame];
3931       r.size.width = oldRect.size.width;
3932       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3933         {
3934           if (oldRect.origin.x != r.origin.x)
3935               ns_clear_frame_area (f, left, top, width, height);
3936           [bar setFrame: r];
3937           update_p = YES;
3938         }
3939     }
3941   if (update_p)
3942     [bar setPosition: position portion: portion whole: whole];
3943   unblock_input ();
3947 static void
3948 ns_condemn_scroll_bars (struct frame *f)
3949 /* --------------------------------------------------------------------------
3950      External (hook): arrange for all frame's scrollbars to be removed
3951      at next call to judge_scroll_bars, except for those redeemed.
3952    -------------------------------------------------------------------------- */
3954   int i;
3955   id view;
3956   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3958   NSTRACE (ns_condemn_scroll_bars);
3960   for (i =[subviews count]-1; i >= 0; i--)
3961     {
3962       view = [subviews objectAtIndex: i];
3963       if ([view isKindOfClass: [EmacsScroller class]])
3964         [view condemn];
3965     }
3969 static void
3970 ns_redeem_scroll_bar (struct window *window)
3971 /* --------------------------------------------------------------------------
3972      External (hook): arrange to spare this window's scrollbar
3973      at next call to judge_scroll_bars.
3974    -------------------------------------------------------------------------- */
3976   id bar;
3977   NSTRACE (ns_redeem_scroll_bar);
3978   if (!NILP (window->vertical_scroll_bar))
3979     {
3980       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3981       [bar reprieve];
3982     }
3984   if (!NILP (window->horizontal_scroll_bar))
3985     {
3986       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3987       [bar reprieve];
3988     }
3992 static void
3993 ns_judge_scroll_bars (struct frame *f)
3994 /* --------------------------------------------------------------------------
3995      External (hook): destroy all scrollbars on frame that weren't
3996      redeemed after call to condemn_scroll_bars.
3997    -------------------------------------------------------------------------- */
3999   int i;
4000   id view;
4001   EmacsView *eview = FRAME_NS_VIEW (f);
4002   NSArray *subviews = [[eview superview] subviews];
4003   BOOL removed = NO;
4005   NSTRACE (ns_judge_scroll_bars);
4006   for (i = [subviews count]-1; i >= 0; --i)
4007     {
4008       view = [subviews objectAtIndex: i];
4009       if (![view isKindOfClass: [EmacsScroller class]]) continue;
4010       if ([view judge])
4011         removed = YES;
4012     }
4014   if (removed)
4015     [eview updateFrameSize: NO];
4018 /* ==========================================================================
4020     Initialization
4022    ========================================================================== */
4025 x_display_pixel_height (struct ns_display_info *dpyinfo)
4027   NSArray *screens = [NSScreen screens];
4028   NSEnumerator *enumerator = [screens objectEnumerator];
4029   NSScreen *screen;
4030   NSRect frame;
4032   frame = NSZeroRect;
4033   while ((screen = [enumerator nextObject]) != nil)
4034     frame = NSUnionRect (frame, [screen frame]);
4036   return NSHeight (frame);
4040 x_display_pixel_width (struct ns_display_info *dpyinfo)
4042   NSArray *screens = [NSScreen screens];
4043   NSEnumerator *enumerator = [screens objectEnumerator];
4044   NSScreen *screen;
4045   NSRect frame;
4047   frame = NSZeroRect;
4048   while ((screen = [enumerator nextObject]) != nil)
4049     frame = NSUnionRect (frame, [screen frame]);
4051   return NSWidth (frame);
4055 static Lisp_Object ns_string_to_lispmod (const char *s)
4056 /* --------------------------------------------------------------------------
4057      Convert modifier name to lisp symbol
4058    -------------------------------------------------------------------------- */
4060   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4061     return Qmeta;
4062   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4063     return Qsuper;
4064   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4065     return Qcontrol;
4066   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4067     return Qalt;
4068   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4069     return Qhyper;
4070   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4071     return Qnone;
4072   else
4073     return Qnil;
4077 static void
4078 ns_default (const char *parameter, Lisp_Object *result,
4079            Lisp_Object yesval, Lisp_Object noval,
4080            BOOL is_float, BOOL is_modstring)
4081 /* --------------------------------------------------------------------------
4082       Check a parameter value in user's preferences
4083    -------------------------------------------------------------------------- */
4085   const char *value = ns_get_defaults_value (parameter);
4087   if (value)
4088     {
4089       double f;
4090       char *pos;
4091       if (c_strcasecmp (value, "YES") == 0)
4092         *result = yesval;
4093       else if (c_strcasecmp (value, "NO") == 0)
4094         *result = noval;
4095       else if (is_float && (f = strtod (value, &pos), pos != value))
4096         *result = make_float (f);
4097       else if (is_modstring && value)
4098         *result = ns_string_to_lispmod (value);
4099       else fprintf (stderr,
4100                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4101     }
4105 static void
4106 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4107 /* --------------------------------------------------------------------------
4108       Initialize global info and storage for display.
4109    -------------------------------------------------------------------------- */
4111     NSScreen *screen = [NSScreen mainScreen];
4112     NSWindowDepth depth = [screen depth];
4114     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4115     dpyinfo->resy = 72.27;
4116     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4117                                                   NSColorSpaceFromDepth (depth)]
4118                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4119                                                  NSColorSpaceFromDepth (depth)];
4120     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4121     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4122     dpyinfo->color_table->colors = NULL;
4123     dpyinfo->root_window = 42; /* a placeholder.. */
4124     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4125     dpyinfo->n_fonts = 0;
4126     dpyinfo->smallest_font_height = 1;
4127     dpyinfo->smallest_char_width = 1;
4129     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4133 /* This and next define (many of the) public functions in this file. */
4134 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4135          with using despite presence in the "system dependent" redisplay
4136          interface.  In addition, many of the ns_ methods have code that is
4137          shared with all terms, indicating need for further refactoring. */
4138 extern frame_parm_handler ns_frame_parm_handlers[];
4139 static struct redisplay_interface ns_redisplay_interface =
4141   ns_frame_parm_handlers,
4142   x_produce_glyphs,
4143   x_write_glyphs,
4144   x_insert_glyphs,
4145   x_clear_end_of_line,
4146   ns_scroll_run,
4147   ns_after_update_window_line,
4148   ns_update_window_begin,
4149   ns_update_window_end,
4150   0, /* flush_display */
4151   x_clear_window_mouse_face,
4152   x_get_glyph_overhangs,
4153   x_fix_overlapping_area,
4154   ns_draw_fringe_bitmap,
4155   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4156   0, /* destroy_fringe_bitmap */
4157   ns_compute_glyph_string_overhangs,
4158   ns_draw_glyph_string,
4159   ns_define_frame_cursor,
4160   ns_clear_frame_area,
4161   ns_draw_window_cursor,
4162   ns_draw_vertical_window_border,
4163   ns_draw_window_divider,
4164   ns_shift_glyphs_for_insert,
4165   ns_show_hourglass,
4166   ns_hide_hourglass
4170 static void
4171 ns_delete_display (struct ns_display_info *dpyinfo)
4173   /* TODO... */
4177 /* This function is called when the last frame on a display is deleted. */
4178 static void
4179 ns_delete_terminal (struct terminal *terminal)
4181   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4183   /* Protect against recursive calls.  delete_frame in
4184      delete_terminal calls us back when it deletes our last frame.  */
4185   if (!terminal->name)
4186     return;
4188   block_input ();
4190   x_destroy_all_bitmaps (dpyinfo);
4191   ns_delete_display (dpyinfo);
4192   unblock_input ();
4196 static struct terminal *
4197 ns_create_terminal (struct ns_display_info *dpyinfo)
4198 /* --------------------------------------------------------------------------
4199       Set up use of NS before we make the first connection.
4200    -------------------------------------------------------------------------- */
4202   struct terminal *terminal;
4204   NSTRACE (ns_create_terminal);
4206   terminal = create_terminal (output_ns, &ns_redisplay_interface);
4208   terminal->display_info.ns = dpyinfo;
4209   dpyinfo->terminal = terminal;
4211   terminal->clear_frame_hook = ns_clear_frame;
4212   terminal->ring_bell_hook = ns_ring_bell;
4213   terminal->update_begin_hook = ns_update_begin;
4214   terminal->update_end_hook = ns_update_end;
4215   terminal->read_socket_hook = ns_read_socket;
4216   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4217   terminal->mouse_position_hook = ns_mouse_position;
4218   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4219   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4220   terminal->fullscreen_hook = ns_fullscreen_hook;
4221   terminal->menu_show_hook = ns_menu_show;
4222   terminal->popup_dialog_hook = ns_popup_dialog;
4223   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4224   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4225   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4226   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4227   terminal->delete_frame_hook = x_destroy_window;
4228   terminal->delete_terminal_hook = ns_delete_terminal;
4229   /* Other hooks are NULL by default.  */
4231   return terminal;
4235 struct ns_display_info *
4236 ns_term_init (Lisp_Object display_name)
4237 /* --------------------------------------------------------------------------
4238      Start the Application and get things rolling.
4239    -------------------------------------------------------------------------- */
4241   struct terminal *terminal;
4242   struct ns_display_info *dpyinfo;
4243   static int ns_initialized = 0;
4244   Lisp_Object tmp;
4246   if (ns_initialized) return x_display_list;
4247   ns_initialized = 1;
4249   NSTRACE (ns_term_init);
4251   [outerpool release];
4252   outerpool = [[NSAutoreleasePool alloc] init];
4254   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4255   /*GSDebugAllocationActive (YES); */
4256   block_input ();
4258   baud_rate = 38400;
4259   Fset_input_interrupt_mode (Qnil);
4261   if (selfds[0] == -1)
4262     {
4263       if (emacs_pipe (selfds) != 0)
4264         {
4265           fprintf (stderr, "Failed to create pipe: %s\n",
4266                    emacs_strerror (errno));
4267           emacs_abort ();
4268         }
4270       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4271       FD_ZERO (&select_readfds);
4272       FD_ZERO (&select_writefds);
4273       pthread_mutex_init (&select_mutex, NULL);
4274     }
4276   ns_pending_files = [[NSMutableArray alloc] init];
4277   ns_pending_service_names = [[NSMutableArray alloc] init];
4278   ns_pending_service_args = [[NSMutableArray alloc] init];
4280 /* Start app and create the main menu, window, view.
4281      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4282      The view will then ask the NSApp to stop and return to Emacs. */
4283   [EmacsApp sharedApplication];
4284   if (NSApp == nil)
4285     return NULL;
4286   [NSApp setDelegate: NSApp];
4288   /* Start the select thread.  */
4289   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4290                            toTarget:NSApp
4291                          withObject:nil];
4293   /* debugging: log all notifications */
4294   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4295                                          selector: @selector (logNotification:)
4296                                              name: nil object: nil]; */
4298   dpyinfo = xzalloc (sizeof *dpyinfo);
4300   ns_initialize_display_info (dpyinfo);
4301   terminal = ns_create_terminal (dpyinfo);
4303   terminal->kboard = allocate_kboard (Qns);
4304   /* Don't let the initial kboard remain current longer than necessary.
4305      That would cause problems if a file loaded on startup tries to
4306      prompt in the mini-buffer.  */
4307   if (current_kboard == initial_kboard)
4308     current_kboard = terminal->kboard;
4309   terminal->kboard->reference_count++;
4311   dpyinfo->next = x_display_list;
4312   x_display_list = dpyinfo;
4314   dpyinfo->name_list_element = Fcons (display_name, Qnil);
4316   terminal->name = xstrdup (SSDATA (display_name));
4318   unblock_input ();
4320   if (!inhibit_x_resources)
4321     {
4322       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4323                  Qt, Qnil, NO, NO);
4324       tmp = Qnil;
4325       /* this is a standard variable */
4326       ns_default ("AppleAntiAliasingThreshold", &tmp,
4327                  make_float (10.0), make_float (6.0), YES, NO);
4328       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4329     }
4331   {
4332     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4334     if ( cl == nil )
4335       {
4336         Lisp_Object color_file, color_map, color;
4337         unsigned long c;
4338         char *name;
4340         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4341                          Fsymbol_value (intern ("data-directory")));
4343         color_map = Fx_load_color_file (color_file);
4344         if (NILP (color_map))
4345           fatal ("Could not read %s.\n", SDATA (color_file));
4347         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4348         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4349           {
4350             color = XCAR (color_map);
4351             name = SSDATA (XCAR (color));
4352             c = XINT (XCDR (color));
4353             [cl setColor:
4354                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4355                                       green: GREEN_FROM_ULONG (c) / 255.0
4356                                        blue: BLUE_FROM_ULONG (c) / 255.0
4357                                       alpha: 1.0]
4358                   forKey: [NSString stringWithUTF8String: name]];
4359           }
4360         [cl writeToFile: nil];
4361       }
4362   }
4364   {
4365 #ifdef NS_IMPL_GNUSTEP
4366     Vwindow_system_version = build_string (gnustep_base_version);
4367 #else
4368     /*PSnextrelease (128, c); */
4369     char c[DBL_BUFSIZE_BOUND];
4370     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4371     Vwindow_system_version = make_unibyte_string (c, len);
4372 #endif
4373   }
4375   delete_keyboard_wait_descriptor (0);
4377   ns_app_name = [[NSProcessInfo processInfo] processName];
4379 /* Set up OS X app menu */
4380 #ifdef NS_IMPL_COCOA
4381   {
4382     NSMenu *appMenu;
4383     NSMenuItem *item;
4384     /* set up the application menu */
4385     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4386     [svcsMenu setAutoenablesItems: NO];
4387     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4388     [appMenu setAutoenablesItems: NO];
4389     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4390     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4392     [appMenu insertItemWithTitle: @"About Emacs"
4393                           action: @selector (orderFrontStandardAboutPanel:)
4394                    keyEquivalent: @""
4395                          atIndex: 0];
4396     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4397     [appMenu insertItemWithTitle: @"Preferences..."
4398                           action: @selector (showPreferencesWindow:)
4399                    keyEquivalent: @","
4400                          atIndex: 2];
4401     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4402     item = [appMenu insertItemWithTitle: @"Services"
4403                                  action: @selector (menuDown:)
4404                           keyEquivalent: @""
4405                                 atIndex: 4];
4406     [appMenu setSubmenu: svcsMenu forItem: item];
4407     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4408     [appMenu insertItemWithTitle: @"Hide Emacs"
4409                           action: @selector (hide:)
4410                    keyEquivalent: @"h"
4411                          atIndex: 6];
4412     item =  [appMenu insertItemWithTitle: @"Hide Others"
4413                           action: @selector (hideOtherApplications:)
4414                    keyEquivalent: @"h"
4415                          atIndex: 7];
4416     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4417     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4418     [appMenu insertItemWithTitle: @"Quit Emacs"
4419                           action: @selector (terminate:)
4420                    keyEquivalent: @"q"
4421                          atIndex: 9];
4423     item = [mainMenu insertItemWithTitle: ns_app_name
4424                                   action: @selector (menuDown:)
4425                            keyEquivalent: @""
4426                                  atIndex: 0];
4427     [mainMenu setSubmenu: appMenu forItem: item];
4428     [dockMenu insertItemWithTitle: @"New Frame"
4429                            action: @selector (newFrame:)
4430                     keyEquivalent: @""
4431                           atIndex: 0];
4433     [NSApp setMainMenu: mainMenu];
4434     [NSApp setAppleMenu: appMenu];
4435     [NSApp setServicesMenu: svcsMenu];
4436     /* Needed at least on Cocoa, to get dock menu to show windows */
4437     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4439     [[NSNotificationCenter defaultCenter]
4440       addObserver: mainMenu
4441          selector: @selector (trackingNotification:)
4442              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4443     [[NSNotificationCenter defaultCenter]
4444       addObserver: mainMenu
4445          selector: @selector (trackingNotification:)
4446              name: NSMenuDidEndTrackingNotification object: mainMenu];
4447   }
4448 #endif /* MAC OS X menu setup */
4450   /* Register our external input/output types, used for determining
4451      applicable services and also drag/drop eligibility. */
4452   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4453   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4454                       retain];
4455   ns_drag_types = [[NSArray arrayWithObjects:
4456                             NSStringPboardType,
4457                             NSTabularTextPboardType,
4458                             NSFilenamesPboardType,
4459                             NSURLPboardType, nil] retain];
4461   /* If fullscreen is in init/default-frame-alist, focus isn't set
4462      right for fullscreen windows, so set this.  */
4463   [NSApp activateIgnoringOtherApps:YES];
4465   [NSApp run];
4466   ns_do_open_file = YES;
4468 #ifdef NS_IMPL_GNUSTEP
4469   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4470      We must re-catch it so subprocess works.  */
4471   catch_child_signal ();
4472 #endif
4473   return dpyinfo;
4477 void
4478 ns_term_shutdown (int sig)
4480   [[NSUserDefaults standardUserDefaults] synchronize];
4482   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4483   if (STRINGP (Vauto_save_list_file_name))
4484     unlink (SSDATA (Vauto_save_list_file_name));
4486   if (sig == 0 || sig == SIGTERM)
4487     {
4488       [NSApp terminate: NSApp];
4489     }
4490   else // force a stack trace to happen
4491     {
4492       emacs_abort ();
4493     }
4497 /* ==========================================================================
4499     EmacsApp implementation
4501    ========================================================================== */
4504 @implementation EmacsApp
4506 - (id)init
4508   if (self = [super init])
4509     {
4510 #ifdef NS_IMPL_COCOA
4511       self->isFirst = YES;
4512 #endif
4513 #ifdef NS_IMPL_GNUSTEP
4514       self->applicationDidFinishLaunchingCalled = NO;
4515 #endif
4516     }
4518   return self;
4521 #ifdef NS_IMPL_COCOA
4522 - (void)run
4524 #ifndef NSAppKitVersionNumber10_9
4525 #define NSAppKitVersionNumber10_9 1265
4526 #endif
4528     if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
4529       {
4530         [super run];
4531         return;
4532       }
4534   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4536   if (isFirst) [self finishLaunching];
4537   isFirst = NO;
4539   shouldKeepRunning = YES;
4540   do
4541     {
4542       [pool release];
4543       pool = [[NSAutoreleasePool alloc] init];
4545       NSEvent *event =
4546         [self nextEventMatchingMask:NSAnyEventMask
4547                           untilDate:[NSDate distantFuture]
4548                              inMode:NSDefaultRunLoopMode
4549                             dequeue:YES];
4551       [self sendEvent:event];
4552       [self updateWindows];
4553     } while (shouldKeepRunning);
4555   [pool release];
4558 - (void)stop: (id)sender
4560     shouldKeepRunning = NO;
4561     // Stop possible dialog also.  Noop if no dialog present.
4562     // The file dialog still leaks 7k - 10k on 10.9 though.
4563     [super stop:sender];
4565 #endif /* NS_IMPL_COCOA */
4567 - (void)logNotification: (NSNotification *)notification
4569   const char *name = [[notification name] UTF8String];
4570   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4571       && !strstr (name, "WindowNumber"))
4572     NSLog (@"notification: '%@'", [notification name]);
4576 - (void)sendEvent: (NSEvent *)theEvent
4577 /* --------------------------------------------------------------------------
4578      Called when NSApp is running for each event received.  Used to stop
4579      the loop when we choose, since there's no way to just run one iteration.
4580    -------------------------------------------------------------------------- */
4582   int type = [theEvent type];
4583   NSWindow *window = [theEvent window];
4585 /*  NSTRACE (sendEvent); */
4586 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4588 #ifdef NS_IMPL_GNUSTEP
4589   // Keyboard events aren't propagated to file dialogs for some reason.
4590   if ([NSApp modalWindow] != nil &&
4591       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4592     {
4593       [[NSApp modalWindow] sendEvent: theEvent];
4594       return;
4595     }
4596 #endif
4598   if (represented_filename != nil && represented_frame)
4599     {
4600       NSString *fstr = represented_filename;
4601       NSView *view = FRAME_NS_VIEW (represented_frame);
4602 #ifdef NS_IMPL_COCOA
4603       /* work around a bug observed on 10.3 and later where
4604          setTitleWithRepresentedFilename does not clear out previous state
4605          if given filename does not exist */
4606       if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
4607         [[view window] setRepresentedFilename: @""];
4608 #endif
4609       [[view window] setRepresentedFilename: fstr];
4610       [represented_filename release];
4611       represented_filename = nil;
4612       represented_frame = NULL;
4613     }
4615   if (type == NSApplicationDefined)
4616     {
4617       switch ([theEvent data2])
4618         {
4619 #ifdef NS_IMPL_COCOA
4620         case NSAPP_DATA2_RUNASSCRIPT:
4621           ns_run_ascript ();
4622           [self stop: self];
4623           return;
4624 #endif
4625         case NSAPP_DATA2_RUNFILEDIALOG:
4626           ns_run_file_dialog ();
4627           [self stop: self];
4628           return;
4629         }
4630     }
4632   if (type == NSCursorUpdate && window == nil)
4633     {
4634       fprintf (stderr, "Dropping external cursor update event.\n");
4635       return;
4636     }
4638   if (type == NSApplicationDefined)
4639     {
4640       /* Events posted by ns_send_appdefined interrupt the run loop here.
4641          But, if a modal window is up, an appdefined can still come through,
4642          (e.g., from a makeKeyWindow event) but stopping self also stops the
4643          modal loop. Just defer it until later. */
4644       if ([NSApp modalWindow] == nil)
4645         {
4646           last_appdefined_event_data = [theEvent data1];
4647           [self stop: self];
4648         }
4649       else
4650         {
4651           send_appdefined = YES;
4652         }
4653     }
4656 #ifdef NS_IMPL_COCOA
4657   /* If no dialog and none of our frames have focus and it is a move, skip it.
4658      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4659      such as Wifi, sound, date or similar.
4660      This prevents "spooky" highlighting in the frame under the menu.  */
4661   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4662     {
4663       struct ns_display_info *di;
4664       BOOL has_focus = NO;
4665       for (di = x_display_list; ! has_focus && di; di = di->next)
4666         has_focus = di->x_focus_frame != 0;
4667       if (! has_focus)
4668         return;
4669     }
4670 #endif
4672   [super sendEvent: theEvent];
4676 - (void)showPreferencesWindow: (id)sender
4678   struct frame *emacsframe = SELECTED_FRAME ();
4679   NSEvent *theEvent = [NSApp currentEvent];
4681   if (!emacs_event)
4682     return;
4683   emacs_event->kind = NS_NONKEY_EVENT;
4684   emacs_event->code = KEY_NS_SHOW_PREFS;
4685   emacs_event->modifiers = 0;
4686   EV_TRAILER (theEvent);
4690 - (void)newFrame: (id)sender
4692   struct frame *emacsframe = SELECTED_FRAME ();
4693   NSEvent *theEvent = [NSApp currentEvent];
4695   if (!emacs_event)
4696     return;
4697   emacs_event->kind = NS_NONKEY_EVENT;
4698   emacs_event->code = KEY_NS_NEW_FRAME;
4699   emacs_event->modifiers = 0;
4700   EV_TRAILER (theEvent);
4704 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4705 - (BOOL) openFile: (NSString *)fileName
4707   struct frame *emacsframe = SELECTED_FRAME ();
4708   NSEvent *theEvent = [NSApp currentEvent];
4710   if (!emacs_event)
4711     return NO;
4713   emacs_event->kind = NS_NONKEY_EVENT;
4714   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4715   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4716   ns_input_line = Qnil; /* can be start or cons start,end */
4717   emacs_event->modifiers =0;
4718   EV_TRAILER (theEvent);
4720   return YES;
4724 /* **************************************************************************
4726       EmacsApp delegate implementation
4728    ************************************************************************** */
4730 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4731 /* --------------------------------------------------------------------------
4732      When application is loaded, terminate event loop in ns_term_init
4733    -------------------------------------------------------------------------- */
4735   NSTRACE (applicationDidFinishLaunching);
4736 #ifdef NS_IMPL_GNUSTEP
4737   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
4738 #endif
4739   [NSApp setServicesProvider: NSApp];
4741   [self antialiasThresholdDidChange:nil];
4742 #ifdef NS_IMPL_COCOA
4743   [[NSNotificationCenter defaultCenter]
4744     addObserver:self
4745        selector:@selector(antialiasThresholdDidChange:)
4746            name:NSAntialiasThresholdChangedNotification
4747          object:nil];
4748 #endif
4750   ns_send_appdefined (-2);
4753 - (void)antialiasThresholdDidChange:(NSNotification *)notification
4755 #ifdef NS_IMPL_COCOA
4756   macfont_update_antialias_threshold ();
4757 #endif
4761 /* Termination sequences:
4762     C-x C-c:
4763     Cmd-Q:
4764     MenuBar | File | Exit:
4765     Select Quit from App menubar:
4766         -terminate
4767         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4768         ns_term_shutdown()
4770     Select Quit from Dock menu:
4771     Logout attempt:
4772         -appShouldTerminate
4773           Cancel -> Nothing else
4774           Accept ->
4776           -terminate
4777           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4778           ns_term_shutdown()
4782 - (void) terminate: (id)sender
4784   struct frame *emacsframe = SELECTED_FRAME ();
4786   if (!emacs_event)
4787     return;
4789   emacs_event->kind = NS_NONKEY_EVENT;
4790   emacs_event->code = KEY_NS_POWER_OFF;
4791   emacs_event->arg = Qt; /* mark as non-key event */
4792   EV_TRAILER ((id)nil);
4796 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4798   int ret;
4800   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4801     return NSTerminateNow;
4803     ret = NSRunAlertPanel(ns_app_name,
4804                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4805                           @"Save Buffers and Exit", @"Cancel", nil);
4807     if (ret == NSAlertDefaultReturn)
4808         return NSTerminateNow;
4809     else if (ret == NSAlertAlternateReturn)
4810         return NSTerminateCancel;
4811     return NSTerminateNow;  /* just in case */
4814 static int
4815 not_in_argv (NSString *arg)
4817   int k;
4818   const char *a = [arg UTF8String];
4819   for (k = 1; k < initial_argc; ++k)
4820     if (strcmp (a, initial_argv[k]) == 0) return 0;
4821   return 1;
4824 /*   Notification from the Workspace to open a file */
4825 - (BOOL)application: sender openFile: (NSString *)file
4827   if (ns_do_open_file || not_in_argv (file))
4828     [ns_pending_files addObject: file];
4829   return YES;
4833 /*   Open a file as a temporary file */
4834 - (BOOL)application: sender openTempFile: (NSString *)file
4836   if (ns_do_open_file || not_in_argv (file))
4837     [ns_pending_files addObject: file];
4838   return YES;
4842 /*   Notification from the Workspace to open a file noninteractively (?) */
4843 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4845   if (ns_do_open_file || not_in_argv (file))
4846     [ns_pending_files addObject: file];
4847   return YES;
4850 /*   Notification from the Workspace to open multiple files */
4851 - (void)application: sender openFiles: (NSArray *)fileList
4853   NSEnumerator *files = [fileList objectEnumerator];
4854   NSString *file;
4855   /* Don't open files from the command line unconditionally,
4856      Cocoa parses the command line wrong, --option value tries to open value
4857      if --option is the last option.  */
4858   while ((file = [files nextObject]) != nil)
4859     if (ns_do_open_file || not_in_argv (file))
4860       [ns_pending_files addObject: file];
4862   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4867 /* Handle dock menu requests.  */
4868 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4870   return dockMenu;
4874 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4875 - (void)applicationWillBecomeActive: (NSNotification *)notification
4877   //ns_app_active=YES;
4879 - (void)applicationDidBecomeActive: (NSNotification *)notification
4881   NSTRACE (applicationDidBecomeActive);
4883 #ifdef NS_IMPL_GNUSTEP
4884   if (! applicationDidFinishLaunchingCalled)
4885     [self applicationDidFinishLaunching:notification];
4886 #endif
4887   //ns_app_active=YES;
4889   ns_update_auto_hide_menu_bar ();
4890   // No constraining takes place when the application is not active.
4891   ns_constrain_all_frames ();
4893 - (void)applicationDidResignActive: (NSNotification *)notification
4895   //ns_app_active=NO;
4896   ns_send_appdefined (-1);
4901 /* ==========================================================================
4903     EmacsApp aux handlers for managing event loop
4905    ========================================================================== */
4908 - (void)timeout_handler: (NSTimer *)timedEntry
4909 /* --------------------------------------------------------------------------
4910      The timeout specified to ns_select has passed.
4911    -------------------------------------------------------------------------- */
4913   /*NSTRACE (timeout_handler); */
4914   ns_send_appdefined (-2);
4917 #ifdef NS_IMPL_GNUSTEP
4918 - (void)sendFromMainThread:(id)unused
4920   ns_send_appdefined (nextappdefined);
4922 #endif
4924 - (void)fd_handler:(id)unused
4925 /* --------------------------------------------------------------------------
4926      Check data waiting on file descriptors and terminate if so
4927    -------------------------------------------------------------------------- */
4929   int result;
4930   int waiting = 1, nfds;
4931   char c;
4933   fd_set readfds, writefds, *wfds;
4934   struct timespec timeout, *tmo;
4935   NSAutoreleasePool *pool = nil;
4937   /* NSTRACE (fd_handler); */
4939   for (;;)
4940     {
4941       [pool release];
4942       pool = [[NSAutoreleasePool alloc] init];
4944       if (waiting)
4945         {
4946           fd_set fds;
4947           FD_ZERO (&fds);
4948           FD_SET (selfds[0], &fds);
4949           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4950           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4951             waiting = 0;
4952         }
4953       else
4954         {
4955           pthread_mutex_lock (&select_mutex);
4956           nfds = select_nfds;
4958           if (select_valid & SELECT_HAVE_READ)
4959             readfds = select_readfds;
4960           else
4961             FD_ZERO (&readfds);
4963           if (select_valid & SELECT_HAVE_WRITE)
4964             {
4965               writefds = select_writefds;
4966               wfds = &writefds;
4967             }
4968           else
4969             wfds = NULL;
4970           if (select_valid & SELECT_HAVE_TMO)
4971             {
4972               timeout = select_timeout;
4973               tmo = &timeout;
4974             }
4975           else
4976             tmo = NULL;
4978           pthread_mutex_unlock (&select_mutex);
4980           FD_SET (selfds[0], &readfds);
4981           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4983           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4985           if (result == 0)
4986             ns_send_appdefined (-2);
4987           else if (result > 0)
4988             {
4989               if (FD_ISSET (selfds[0], &readfds))
4990                 {
4991                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4992                     waiting = 1;
4993                 }
4994               else
4995                 {
4996                   pthread_mutex_lock (&select_mutex);
4997                   if (select_valid & SELECT_HAVE_READ)
4998                     select_readfds = readfds;
4999                   if (select_valid & SELECT_HAVE_WRITE)
5000                     select_writefds = writefds;
5001                   if (select_valid & SELECT_HAVE_TMO)
5002                     select_timeout = timeout;
5003                   pthread_mutex_unlock (&select_mutex);
5005                   ns_send_appdefined (result);
5006                 }
5007             }
5008           waiting = 1;
5009         }
5010     }
5015 /* ==========================================================================
5017     Service provision
5019    ========================================================================== */
5021 /* called from system: queue for next pass through event loop */
5022 - (void)requestService: (NSPasteboard *)pboard
5023               userData: (NSString *)userData
5024                  error: (NSString **)error
5026   [ns_pending_service_names addObject: userData];
5027   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5028       SSDATA (ns_string_from_pasteboard (pboard))]];
5032 /* called from ns_read_socket to clear queue */
5033 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5035   struct frame *emacsframe = SELECTED_FRAME ();
5036   NSEvent *theEvent = [NSApp currentEvent];
5038   if (!emacs_event)
5039     return NO;
5041   emacs_event->kind = NS_NONKEY_EVENT;
5042   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5043   ns_input_spi_name = build_string ([name UTF8String]);
5044   ns_input_spi_arg = build_string ([arg UTF8String]);
5045   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5046   EV_TRAILER (theEvent);
5048   return YES;
5052 @end  /* EmacsApp */
5056 /* ==========================================================================
5058     EmacsView implementation
5060    ========================================================================== */
5063 @implementation EmacsView
5065 /* needed to inform when window closed from LISP */
5066 - (void) setWindowClosing: (BOOL)closing
5068   windowClosing = closing;
5072 - (void)dealloc
5074   NSTRACE (EmacsView_dealloc);
5075   [toolbar release];
5076   if (fs_state == FULLSCREEN_BOTH)
5077     [nonfs_window release];
5078   [super dealloc];
5082 /* called on font panel selection */
5083 - (void)changeFont: (id)sender
5085   NSEvent *e = [[self window] currentEvent];
5086   struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5087   struct font *font = face->font;
5088   id newFont;
5089   CGFloat size;
5090   NSFont *nsfont;
5092   NSTRACE (changeFont);
5094   if (!emacs_event)
5095     return;
5097 #ifdef NS_IMPL_GNUSTEP
5098   nsfont = ((struct nsfont_info *)font)->nsfont;
5099 #endif
5100 #ifdef NS_IMPL_COCOA
5101   nsfont = (NSFont *) macfont_get_nsctfont (font);
5102 #endif
5104   if ((newFont = [sender convertFont: nsfont]))
5105     {
5106       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5108       emacs_event->kind = NS_NONKEY_EVENT;
5109       emacs_event->modifiers = 0;
5110       emacs_event->code = KEY_NS_CHANGE_FONT;
5112       size = [newFont pointSize];
5113       ns_input_fontsize = make_number (lrint (size));
5114       ns_input_font = build_string ([[newFont familyName] UTF8String]);
5115       EV_TRAILER (e);
5116     }
5120 - (BOOL)acceptsFirstResponder
5122   NSTRACE (acceptsFirstResponder);
5123   return YES;
5127 - (void)resetCursorRects
5129   NSRect visible = [self visibleRect];
5130   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5131   NSTRACE (resetCursorRects);
5133   if (currentCursor == nil)
5134     currentCursor = [NSCursor arrowCursor];
5136   if (!NSIsEmptyRect (visible))
5137     [self addCursorRect: visible cursor: currentCursor];
5138   [currentCursor setOnMouseEntered: YES];
5143 /*****************************************************************************/
5144 /* Keyboard handling. */
5145 #define NS_KEYLOG 0
5147 - (void)keyDown: (NSEvent *)theEvent
5149   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5150   int code;
5151   unsigned fnKeysym = 0;
5152   static NSMutableArray *nsEvArray;
5153 #ifdef NS_IMPL_GNUSTEP
5154   static BOOL firstTime = YES;
5155 #endif
5156   int left_is_none;
5157   unsigned int flags = [theEvent modifierFlags];
5159   NSTRACE (keyDown);
5161   /* Rhapsody and OS X give up and down events for the arrow keys */
5162   if (ns_fake_keydown == YES)
5163     ns_fake_keydown = NO;
5164   else if ([theEvent type] != NSKeyDown)
5165     return;
5167   if (!emacs_event)
5168     return;
5170  if (![[self window] isKeyWindow]
5171      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5172      /* we must avoid an infinite loop here. */
5173      && (EmacsView *)[[theEvent window] delegate] != self)
5174    {
5175      /* XXX: There is an occasional condition in which, when Emacs display
5176          updates a different frame from the current one, and temporarily
5177          selects it, then processes some interrupt-driven input
5178          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5179          for some reason that window has its first responder set to the NSView
5180          most recently updated (I guess), which is not the correct one. */
5181      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5182      return;
5183    }
5185   if (nsEvArray == nil)
5186     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5188   [NSCursor setHiddenUntilMouseMoves: YES];
5190   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5191     {
5192       clear_mouse_face (hlinfo);
5193       hlinfo->mouse_face_hidden = 1;
5194     }
5196   if (!processingCompose)
5197     {
5198       /* When using screen sharing, no left or right information is sent,
5199          so use Left key in those cases.  */
5200       int is_left_key, is_right_key;
5202       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5203         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5205       /* (Carbon way: [theEvent keyCode]) */
5207       /* is it a "function key"? */
5208       /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5209          flag set (this is probably a bug in the OS).
5210       */
5211       if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5212         {
5213           fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5214         }
5215       if (fnKeysym == 0)
5216         {
5217           fnKeysym = ns_convert_key (code);
5218         }
5220       if (fnKeysym)
5221         {
5222           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5223              because Emacs treats Delete and KP-Delete same (in simple.el). */
5224           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5225 #ifdef NS_IMPL_GNUSTEP
5226               /*  GNUstep uses incompatible keycodes, even for those that are
5227                   supposed to be hardware independent.  Just check for delete.
5228                   Keypad delete does not have keysym 0xFFFF.
5229                   See http://savannah.gnu.org/bugs/?25395
5230               */
5231               || (fnKeysym == 0xFFFF && code == 127)
5232 #endif
5233             )
5234             code = 0xFF08; /* backspace */
5235           else
5236             code = fnKeysym;
5237         }
5239       /* are there modifiers? */
5240       emacs_event->modifiers = 0;
5242       if (flags & NSHelpKeyMask)
5243           emacs_event->modifiers |= hyper_modifier;
5245       if (flags & NSShiftKeyMask)
5246         emacs_event->modifiers |= shift_modifier;
5248       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5249       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5250         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5252       if (is_right_key)
5253         emacs_event->modifiers |= parse_solitary_modifier
5254           (EQ (ns_right_command_modifier, Qleft)
5255            ? ns_command_modifier
5256            : ns_right_command_modifier);
5258       if (is_left_key)
5259         {
5260           emacs_event->modifiers |= parse_solitary_modifier
5261             (ns_command_modifier);
5263           /* if super (default), take input manager's word so things like
5264              dvorak / qwerty layout work */
5265           if (EQ (ns_command_modifier, Qsuper)
5266               && !fnKeysym
5267               && [[theEvent characters] length] != 0)
5268             {
5269               /* XXX: the code we get will be unshifted, so if we have
5270                  a shift modifier, must convert ourselves */
5271               if (!(flags & NSShiftKeyMask))
5272                 code = [[theEvent characters] characterAtIndex: 0];
5273 #if 0
5274               /* this is ugly and also requires linking w/Carbon framework
5275                  (for LMGetKbdType) so for now leave this rare (?) case
5276                  undealt with.. in future look into CGEvent methods */
5277               else
5278                 {
5279                   long smv = GetScriptManagerVariable (smKeyScript);
5280                   Handle uchrHandle = GetResource
5281                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5282                   UInt32 dummy = 0;
5283                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5284                                  [[theEvent characters] characterAtIndex: 0],
5285                                  kUCKeyActionDisplay,
5286                                  (flags & ~NSCommandKeyMask) >> 8,
5287                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5288                                  &dummy, 1, &dummy, &code);
5289                   code &= 0xFF;
5290                 }
5291 #endif
5292             }
5293         }
5295       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5296       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5297         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5299       if (is_right_key)
5300           emacs_event->modifiers |= parse_solitary_modifier
5301               (EQ (ns_right_control_modifier, Qleft)
5302                ? ns_control_modifier
5303                : ns_right_control_modifier);
5305       if (is_left_key)
5306         emacs_event->modifiers |= parse_solitary_modifier
5307           (ns_control_modifier);
5309       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5310           emacs_event->modifiers |=
5311             parse_solitary_modifier (ns_function_modifier);
5313       left_is_none = NILP (ns_alternate_modifier)
5314         || EQ (ns_alternate_modifier, Qnone);
5316       is_right_key = (flags & NSRightAlternateKeyMask)
5317         == NSRightAlternateKeyMask;
5318       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5319         || (! is_right_key
5320             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5322       if (is_right_key)
5323         {
5324           if ((NILP (ns_right_alternate_modifier)
5325                || EQ (ns_right_alternate_modifier, Qnone)
5326                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5327               && !fnKeysym)
5328             {   /* accept pre-interp alt comb */
5329               if ([[theEvent characters] length] > 0)
5330                 code = [[theEvent characters] characterAtIndex: 0];
5331               /*HACK: clear lone shift modifier to stop next if from firing */
5332               if (emacs_event->modifiers == shift_modifier)
5333                 emacs_event->modifiers = 0;
5334             }
5335           else
5336             emacs_event->modifiers |= parse_solitary_modifier
5337               (EQ (ns_right_alternate_modifier, Qleft)
5338                ? ns_alternate_modifier
5339                : ns_right_alternate_modifier);
5340         }
5342       if (is_left_key) /* default = meta */
5343         {
5344           if (left_is_none && !fnKeysym)
5345             {   /* accept pre-interp alt comb */
5346               if ([[theEvent characters] length] > 0)
5347                 code = [[theEvent characters] characterAtIndex: 0];
5348               /*HACK: clear lone shift modifier to stop next if from firing */
5349               if (emacs_event->modifiers == shift_modifier)
5350                 emacs_event->modifiers = 0;
5351             }
5352           else
5353               emacs_event->modifiers |=
5354                 parse_solitary_modifier (ns_alternate_modifier);
5355         }
5357   if (NS_KEYLOG)
5358     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5359              code, fnKeysym, flags, emacs_event->modifiers);
5361       /* if it was a function key or had modifiers, pass it directly to emacs */
5362       if (fnKeysym || (emacs_event->modifiers
5363                        && (emacs_event->modifiers != shift_modifier)
5364                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5365 /*[[theEvent characters] length] */
5366         {
5367           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5368           if (code < 0x20)
5369             code |= (1<<28)|(3<<16);
5370           else if (code == 0x7f)
5371             code |= (1<<28)|(3<<16);
5372           else if (!fnKeysym)
5373             emacs_event->kind = code > 0xFF
5374               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5376           emacs_event->code = code;
5377           EV_TRAILER (theEvent);
5378           processingCompose = NO;
5379           return;
5380         }
5381     }
5384 #ifdef NS_IMPL_GNUSTEP
5385   /* if we get here we should send the key for input manager processing */
5386   /* Disable warning, there is nothing a user can do about it anyway, and
5387      it does not seem to matter.  */
5388 #if 0
5389   if (firstTime && [[NSInputManager currentInputManager]
5390                      wantsToDelayTextChangeNotifications] == NO)
5391     fprintf (stderr,
5392           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5393 #endif
5394   firstTime = NO;
5395 #endif
5396   if (NS_KEYLOG && !processingCompose)
5397     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5399   processingCompose = YES;
5400   [nsEvArray addObject: theEvent];
5401   [self interpretKeyEvents: nsEvArray];
5402   [nsEvArray removeObject: theEvent];
5406 #ifdef NS_IMPL_COCOA
5407 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5408    decided not to send key-down for.
5409    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5410    This only applies on Tiger and earlier.
5411    If it matches one of these, send it on to keyDown. */
5412 -(void)keyUp: (NSEvent *)theEvent
5414   int flags = [theEvent modifierFlags];
5415   int code = [theEvent keyCode];
5416   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5417       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5418     {
5419       if (NS_KEYLOG)
5420         fprintf (stderr, "keyUp: passed test");
5421       ns_fake_keydown = YES;
5422       [self keyDown: theEvent];
5423     }
5425 #endif
5428 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5431 /* <NSTextInput>: called when done composing;
5432    NOTE: also called when we delete over working text, followed immed.
5433          by doCommandBySelector: deleteBackward: */
5434 - (void)insertText: (id)aString
5436   int code;
5437   int len = [(NSString *)aString length];
5438   int i;
5440   if (NS_KEYLOG)
5441     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5442   processingCompose = NO;
5444   if (!emacs_event)
5445     return;
5447   /* first, clear any working text */
5448   if (workingText != nil)
5449     [self deleteWorkingText];
5451   /* now insert the string as keystrokes */
5452   for (i =0; i<len; i++)
5453     {
5454       code = [aString characterAtIndex: i];
5455       /* TODO: still need this? */
5456       if (code == 0x2DC)
5457         code = '~'; /* 0x7E */
5458       if (code != 32) /* Space */
5459         emacs_event->modifiers = 0;
5460       emacs_event->kind
5461         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5462       emacs_event->code = code;
5463       EV_TRAILER ((id)nil);
5464     }
5468 /* <NSTextInput>: inserts display of composing characters */
5469 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5471   NSString *str = [aString respondsToSelector: @selector (string)] ?
5472     [aString string] : aString;
5473   if (NS_KEYLOG)
5474     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5475            str, (unsigned long)[str length],
5476            (unsigned long)selRange.length,
5477            (unsigned long)selRange.location);
5479   if (workingText != nil)
5480     [self deleteWorkingText];
5481   if ([str length] == 0)
5482     return;
5484   if (!emacs_event)
5485     return;
5487   processingCompose = YES;
5488   workingText = [str copy];
5489   ns_working_text = build_string ([workingText UTF8String]);
5491   emacs_event->kind = NS_TEXT_EVENT;
5492   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5493   EV_TRAILER ((id)nil);
5497 /* delete display of composing characters [not in <NSTextInput>] */
5498 - (void)deleteWorkingText
5500   if (workingText == nil)
5501     return;
5502   if (NS_KEYLOG)
5503     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5504   [workingText release];
5505   workingText = nil;
5506   processingCompose = NO;
5508   if (!emacs_event)
5509     return;
5511   emacs_event->kind = NS_TEXT_EVENT;
5512   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5513   EV_TRAILER ((id)nil);
5517 - (BOOL)hasMarkedText
5519   return workingText != nil;
5523 - (NSRange)markedRange
5525   NSRange rng = workingText != nil
5526     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5527   if (NS_KEYLOG)
5528     NSLog (@"markedRange request");
5529   return rng;
5533 - (void)unmarkText
5535   if (NS_KEYLOG)
5536     NSLog (@"unmark (accept) text");
5537   [self deleteWorkingText];
5538   processingCompose = NO;
5542 /* used to position char selection windows, etc. */
5543 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5545   NSRect rect;
5546   NSPoint pt;
5547   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5548   if (NS_KEYLOG)
5549     NSLog (@"firstRectForCharRange request");
5551   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5552   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5553   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5554   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5555                                        +FRAME_LINE_HEIGHT (emacsframe));
5557   pt = [self convertPoint: pt toView: nil];
5558   pt = [[self window] convertBaseToScreen: pt];
5559   rect.origin = pt;
5560   return rect;
5564 - (NSInteger)conversationIdentifier
5566   return (NSInteger)self;
5570 - (void)doCommandBySelector: (SEL)aSelector
5572   if (NS_KEYLOG)
5573     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5575   processingCompose = NO;
5576   if (aSelector == @selector (deleteBackward:))
5577     {
5578       /* happens when user backspaces over an ongoing composition:
5579          throw a 'delete' into the event queue */
5580       if (!emacs_event)
5581         return;
5582       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5583       emacs_event->code = 0xFF08;
5584       EV_TRAILER ((id)nil);
5585     }
5588 - (NSArray *)validAttributesForMarkedText
5590   static NSArray *arr = nil;
5591   if (arr == nil) arr = [NSArray new];
5592  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5593   return arr;
5596 - (NSRange)selectedRange
5598   if (NS_KEYLOG)
5599     NSLog (@"selectedRange request");
5600   return NSMakeRange (NSNotFound, 0);
5603 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5604     GNUSTEP_GUI_MINOR_VERSION > 22
5605 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5606 #else
5607 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5608 #endif
5610   if (NS_KEYLOG)
5611     NSLog (@"characterIndexForPoint request");
5612   return 0;
5615 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5617   static NSAttributedString *str = nil;
5618   if (str == nil) str = [NSAttributedString new];
5619   if (NS_KEYLOG)
5620     NSLog (@"attributedSubstringFromRange request");
5621   return str;
5624 /* End <NSTextInput> impl. */
5625 /*****************************************************************************/
5628 /* This is what happens when the user presses a mouse button.  */
5629 - (void)mouseDown: (NSEvent *)theEvent
5631   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5632   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5634   NSTRACE (mouseDown);
5636   [self deleteWorkingText];
5638   if (!emacs_event)
5639     return;
5641   dpyinfo->last_mouse_frame = emacsframe;
5642   /* appears to be needed to prevent spurious movement events generated on
5643      button clicks */
5644   emacsframe->mouse_moved = 0;
5646   if ([theEvent type] == NSScrollWheel)
5647     {
5648       CGFloat delta = [theEvent deltaY];
5649       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5650       if (delta == 0)
5651         {
5652           delta = [theEvent deltaX];
5653           if (delta == 0)
5654             {
5655               NSTRACE (deltaIsZero);
5656               return;
5657             }
5658           emacs_event->kind = HORIZ_WHEEL_EVENT;
5659         }
5660       else
5661         emacs_event->kind = WHEEL_EVENT;
5663       emacs_event->code = 0;
5664       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5665         ((delta > 0) ? up_modifier : down_modifier);
5666     }
5667   else
5668     {
5669       emacs_event->kind = MOUSE_CLICK_EVENT;
5670       emacs_event->code = EV_BUTTON (theEvent);
5671       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5672                              | EV_UDMODIFIERS (theEvent);
5673     }
5674   XSETINT (emacs_event->x, lrint (p.x));
5675   XSETINT (emacs_event->y, lrint (p.y));
5676   EV_TRAILER (theEvent);
5680 - (void)rightMouseDown: (NSEvent *)theEvent
5682   NSTRACE (rightMouseDown);
5683   [self mouseDown: theEvent];
5687 - (void)otherMouseDown: (NSEvent *)theEvent
5689   NSTRACE (otherMouseDown);
5690   [self mouseDown: theEvent];
5694 - (void)mouseUp: (NSEvent *)theEvent
5696   NSTRACE (mouseUp);
5697   [self mouseDown: theEvent];
5701 - (void)rightMouseUp: (NSEvent *)theEvent
5703   NSTRACE (rightMouseUp);
5704   [self mouseDown: theEvent];
5708 - (void)otherMouseUp: (NSEvent *)theEvent
5710   NSTRACE (otherMouseUp);
5711   [self mouseDown: theEvent];
5715 - (void) scrollWheel: (NSEvent *)theEvent
5717   NSTRACE (scrollWheel);
5718   [self mouseDown: theEvent];
5722 /* Tell emacs the mouse has moved. */
5723 - (void)mouseMoved: (NSEvent *)e
5725   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5726   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5727   Lisp_Object frame;
5728   NSPoint pt;
5730 //  NSTRACE (mouseMoved);
5732   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
5733   pt = [self convertPoint: [e locationInWindow] fromView: nil];
5734   dpyinfo->last_mouse_motion_x = pt.x;
5735   dpyinfo->last_mouse_motion_y = pt.y;
5737   /* update any mouse face */
5738   if (hlinfo->mouse_face_hidden)
5739     {
5740       hlinfo->mouse_face_hidden = 0;
5741       clear_mouse_face (hlinfo);
5742     }
5744   /* tooltip handling */
5745   previous_help_echo_string = help_echo_string;
5746   help_echo_string = Qnil;
5748   if (!NILP (Vmouse_autoselect_window))
5749     {
5750       NSTRACE (mouse_autoselect_window);
5751       static Lisp_Object last_mouse_window;
5752       Lisp_Object window
5753         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
5755       if (WINDOWP (window)
5756           && !EQ (window, last_mouse_window)
5757           && !EQ (window, selected_window)
5758           && (focus_follows_mouse
5759               || (EQ (XWINDOW (window)->frame,
5760                       XWINDOW (selected_window)->frame))))
5761         {
5762           NSTRACE (in_window);
5763           emacs_event->kind = SELECT_WINDOW_EVENT;
5764           emacs_event->frame_or_window = window;
5765           EV_TRAILER2 (e);
5766         }
5767       /* Remember the last window where we saw the mouse.  */
5768       last_mouse_window = window;
5769     }
5771   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
5772     help_echo_string = previous_help_echo_string;
5774   XSETFRAME (frame, emacsframe);
5775   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5776     {
5777       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5778          (note_mouse_highlight), which is called through the
5779          note_mouse_movement () call above */
5780       any_help_event_p = YES;
5781       gen_help_event (help_echo_string, frame, help_echo_window,
5782                       help_echo_object, help_echo_pos);
5783     }
5785   if (emacsframe->mouse_moved && send_appdefined)
5786     ns_send_appdefined (-1);
5790 - (void)mouseDragged: (NSEvent *)e
5792   NSTRACE (mouseDragged);
5793   [self mouseMoved: e];
5797 - (void)rightMouseDragged: (NSEvent *)e
5799   NSTRACE (rightMouseDragged);
5800   [self mouseMoved: e];
5804 - (void)otherMouseDragged: (NSEvent *)e
5806   NSTRACE (otherMouseDragged);
5807   [self mouseMoved: e];
5811 - (BOOL)windowShouldClose: (id)sender
5813   NSEvent *e =[[self window] currentEvent];
5815   NSTRACE (windowShouldClose);
5816   windowClosing = YES;
5817   if (!emacs_event)
5818     return NO;
5819   emacs_event->kind = DELETE_WINDOW_EVENT;
5820   emacs_event->modifiers = 0;
5821   emacs_event->code = 0;
5822   EV_TRAILER (e);
5823   /* Don't close this window, let this be done from lisp code.  */
5824   return NO;
5827 - (void) updateFrameSize: (BOOL) delay;
5829   NSWindow *window = [self window];
5830   NSRect wr = [window frame];
5831   int extra = 0;
5832   int oldc = cols, oldr = rows;
5833   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
5834   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5835   int neww, newh;
5837   NSTRACE (updateFrameSize);
5838   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
5840   if (! [self isFullscreen])
5841     {
5842 #ifdef NS_IMPL_GNUSTEP
5843       // GNUstep does not always update the tool bar height.  Force it.
5844       if (toolbar && [toolbar isVisible])
5845           update_frame_tool_bar (emacsframe);
5846 #endif
5848       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5849         + FRAME_TOOLBAR_HEIGHT (emacsframe);
5850     }
5852   if (wait_for_tool_bar)
5853     {
5854       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
5855         return;
5856       wait_for_tool_bar = NO;
5857     }
5859   neww = (int)wr.size.width - emacsframe->border_width;
5860   newh = (int)wr.size.height - extra;
5862   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
5863   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
5865   if (cols < MINWIDTH)
5866     cols = MINWIDTH;
5868   if (rows < MINHEIGHT)
5869     rows = MINHEIGHT;
5871   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5872     {
5873       NSView *view = FRAME_NS_VIEW (emacsframe);
5874       NSWindow *win = [view window];
5875       NSSize sz = [win resizeIncrements];
5877       change_frame_size (emacsframe,
5878                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
5879                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
5880                          0, delay, 0, 1);
5881       SET_FRAME_GARBAGED (emacsframe);
5882       cancel_mouse_face (emacsframe);
5884       // Did resize increments change because of a font change?
5885       if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5886           sz.height != FRAME_LINE_HEIGHT (emacsframe) ||
5887           (frame_resize_pixelwise && sz.width != 1))
5888         {
5889           sz.width = frame_resize_pixelwise
5890             ? 1 : FRAME_COLUMN_WIDTH (emacsframe);
5891           sz.height = frame_resize_pixelwise
5892             ? 1 : FRAME_LINE_HEIGHT (emacsframe);
5893           [win setResizeIncrements: sz];
5895           NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
5896         }
5898       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5899       [self windowDidMove:nil];   // Update top/left.
5900     }
5903 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5904 /* normalize frame to gridded text size */
5906   int extra = 0;
5908   NSTRACE (windowWillResize);
5909   NSTRACE_SIZE ("Original size", frameSize);
5910 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5912   if (fs_state == FULLSCREEN_MAXIMIZED
5913       && (maximized_width != (int)frameSize.width
5914           || maximized_height != (int)frameSize.height))
5915     [self setFSValue: FULLSCREEN_NONE];
5916   else if (fs_state == FULLSCREEN_WIDTH
5917            && maximized_width != (int)frameSize.width)
5918     [self setFSValue: FULLSCREEN_NONE];
5919   else if (fs_state == FULLSCREEN_HEIGHT
5920            && maximized_height != (int)frameSize.height)
5921     [self setFSValue: FULLSCREEN_NONE];
5922   if (fs_state == FULLSCREEN_NONE)
5923     maximized_width = maximized_height = -1;
5925   if (! [self isFullscreen])
5926     {
5927       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5928         + FRAME_TOOLBAR_HEIGHT (emacsframe);
5929     }
5931   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
5932   if (cols < MINWIDTH)
5933     cols = MINWIDTH;
5935   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5936                                            frameSize.height - extra);
5937   if (rows < MINHEIGHT)
5938     rows = MINHEIGHT;
5939 #ifdef NS_IMPL_COCOA
5940   {
5941     /* this sets window title to have size in it; the wm does this under GS */
5942     NSRect r = [[self window] frame];
5943     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5944       {
5945         if (old_title != 0)
5946           {
5947             xfree (old_title);
5948             old_title = 0;
5949           }
5950       }
5951     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5952       {
5953         char *size_title;
5954         NSWindow *window = [self window];
5955         if (old_title == 0)
5956           {
5957             char *t = strdup ([[[self window] title] UTF8String]);
5958             char *pos = strstr (t, "  â€”  ");
5959             if (pos)
5960               *pos = '\0';
5961             old_title = t;
5962           }
5963         size_title = xmalloc (strlen (old_title) + 40);
5964         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5965         [window setTitle: [NSString stringWithUTF8String: size_title]];
5966         [window display];
5967         xfree (size_title);
5968       }
5969   }
5970 #endif /* NS_IMPL_COCOA */
5971 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5973   return frameSize;
5977 - (void)windowDidResize: (NSNotification *)notification
5979   if (! [self fsIsNative])
5980     {
5981       NSWindow *theWindow = [notification object];
5982       /* We can get notification on the non-FS window when in
5983          fullscreen mode.  */
5984       if ([self window] != theWindow) return;
5985     }
5987 #ifdef NS_IMPL_GNUSTEP
5988   NSWindow *theWindow = [notification object];
5990    /* In GNUstep, at least currently, it's possible to get a didResize
5991       without getting a willResize.. therefore we need to act as if we got
5992       the willResize now */
5993   NSSize sz = [theWindow frame].size;
5994   sz = [self windowWillResize: theWindow toSize: sz];
5995 #endif /* NS_IMPL_GNUSTEP */
5997   NSTRACE (windowDidResize);
5998 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
6000 if (cols > 0 && rows > 0)
6001     {
6002       [self updateFrameSize: YES];
6003     }
6005   ns_send_appdefined (-1);
6008 #ifdef NS_IMPL_COCOA
6009 - (void)viewDidEndLiveResize
6011   [super viewDidEndLiveResize];
6012   if (old_title != 0)
6013     {
6014       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6015       xfree (old_title);
6016       old_title = 0;
6017     }
6018   maximizing_resize = NO;
6020 #endif /* NS_IMPL_COCOA */
6023 - (void)windowDidBecomeKey: (NSNotification *)notification
6024 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6026   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6027   struct frame *old_focus = dpyinfo->x_focus_frame;
6029   NSTRACE (windowDidBecomeKey);
6031   if (emacsframe != old_focus)
6032     dpyinfo->x_focus_frame = emacsframe;
6034   ns_frame_rehighlight (emacsframe);
6036   if (emacs_event)
6037     {
6038       emacs_event->kind = FOCUS_IN_EVENT;
6039       EV_TRAILER ((id)nil);
6040     }
6044 - (void)windowDidResignKey: (NSNotification *)notification
6045 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6047   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6048   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6049   NSTRACE (windowDidResignKey);
6051   if (is_focus_frame)
6052     dpyinfo->x_focus_frame = 0;
6054   emacsframe->mouse_moved = 0;
6055   ns_frame_rehighlight (emacsframe);
6057   /* FIXME: for some reason needed on second and subsequent clicks away
6058             from sole-frame Emacs to get hollow box to show */
6059   if (!windowClosing && [[self window] isVisible] == YES)
6060     {
6061       x_update_cursor (emacsframe, 1);
6062       x_set_frame_alpha (emacsframe);
6063     }
6065   if (any_help_event_p)
6066     {
6067       Lisp_Object frame;
6068       XSETFRAME (frame, emacsframe);
6069       help_echo_string = Qnil;
6070       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6071     }
6073   if (emacs_event && is_focus_frame)
6074     {
6075       [self deleteWorkingText];
6076       emacs_event->kind = FOCUS_OUT_EVENT;
6077       EV_TRAILER ((id)nil);
6078     }
6082 - (void)windowWillMiniaturize: sender
6084   NSTRACE (windowWillMiniaturize);
6088 - (BOOL)isFlipped
6090   return YES;
6094 - (BOOL)isOpaque
6096   return NO;
6100 - initFrameFromEmacs: (struct frame *)f
6102   NSRect r, wr;
6103   Lisp_Object tem;
6104   NSWindow *win;
6105   NSSize sz;
6106   NSColor *col;
6107   NSString *name;
6109   NSTRACE (initFrameFromEmacs);
6111   windowClosing = NO;
6112   processingCompose = NO;
6113   scrollbarsNeedingUpdate = 0;
6114   fs_state = FULLSCREEN_NONE;
6115   fs_before_fs = next_maximized = -1;
6116 #ifdef HAVE_NATIVE_FS
6117   fs_is_native = ns_use_native_fullscreen;
6118 #else
6119   fs_is_native = NO;
6120 #endif
6121   maximized_width = maximized_height = -1;
6122   nonfs_window = nil;
6124 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
6126   ns_userRect = NSMakeRect (0, 0, 0, 0);
6127   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6128                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6129   [self initWithFrame: r];
6130   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6132   FRAME_NS_VIEW (f) = self;
6133   emacsframe = f;
6134 #ifdef NS_IMPL_COCOA
6135   old_title = 0;
6136   maximizing_resize = NO;
6137 #endif
6139   win = [[EmacsWindow alloc]
6140             initWithContentRect: r
6141                       styleMask: (NSResizableWindowMask |
6142 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6143                                   NSTitledWindowMask |
6144 #endif
6145                                   NSMiniaturizableWindowMask |
6146                                   NSClosableWindowMask)
6147                         backing: NSBackingStoreBuffered
6148                           defer: YES];
6150 #ifdef HAVE_NATIVE_FS
6151     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6152 #endif
6154   wr = [win frame];
6155   bwidth = f->border_width = wr.size.width - r.size.width;
6156   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6158   [win setAcceptsMouseMovedEvents: YES];
6159   [win setDelegate: self];
6160   [win useOptimizedDrawing: YES];
6162   sz.width = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
6163   sz.height = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
6164   [win setResizeIncrements: sz];
6166   [[win contentView] addSubview: self];
6168   if (ns_drag_types)
6169     [self registerForDraggedTypes: ns_drag_types];
6171   tem = f->name;
6172   name = [NSString stringWithUTF8String:
6173                    NILP (tem) ? "Emacs" : SSDATA (tem)];
6174   [win setTitle: name];
6176   /* toolbar support */
6177   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6178                          [NSString stringWithFormat: @"Emacs Frame %d",
6179                                    ns_window_num]];
6180   [win setToolbar: toolbar];
6181   [toolbar setVisible: NO];
6183   /* Don't set frame garbaged until tool bar is up to date?
6184      This avoids an extra clear and redraw (flicker) at frame creation.  */
6185   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6186   else wait_for_tool_bar = NO;
6189 #ifdef NS_IMPL_COCOA
6190   {
6191     NSButton *toggleButton;
6192   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6193   [toggleButton setTarget: self];
6194   [toggleButton setAction: @selector (toggleToolbar: )];
6195   }
6196 #endif
6197   FRAME_TOOLBAR_HEIGHT (f) = 0;
6199   tem = f->icon_name;
6200   if (!NILP (tem))
6201     [win setMiniwindowTitle:
6202            [NSString stringWithUTF8String: SSDATA (tem)]];
6204   {
6205     NSScreen *screen = [win screen];
6207     if (screen != 0)
6208       [win setFrameTopLeftPoint: NSMakePoint
6209            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6210             IN_BOUND (-SCREENMAX,
6211                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
6212   }
6214   [win makeFirstResponder: self];
6216   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6217                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6218   [win setBackgroundColor: col];
6219   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6220     [win setOpaque: NO];
6222   [self allocateGState];
6224   [NSApp registerServicesMenuSendTypes: ns_send_types
6225                            returnTypes: nil];
6227   ns_window_num++;
6228   return self;
6232 - (void)windowDidMove: sender
6234   NSWindow *win = [self window];
6235   NSRect r = [win frame];
6236   NSArray *screens = [NSScreen screens];
6237   NSScreen *screen = [screens objectAtIndex: 0];
6239   NSTRACE (windowDidMove);
6241   if (!emacsframe->output_data.ns)
6242     return;
6243   if (screen != nil)
6244     {
6245       emacsframe->left_pos = r.origin.x;
6246       emacsframe->top_pos =
6247         [screen frame].size.height - (r.origin.y + r.size.height);
6248     }
6252 /* Called AFTER method below, but before our windowWillResize call there leads
6253    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
6254    location so set_window_size moves the frame. */
6255 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6257   emacsframe->output_data.ns->zooming = 1;
6258   return YES;
6262 /* Override to do something slightly nonstandard, but nice.  First click on
6263    zoom button will zoom vertically.  Second will zoom completely.  Third
6264    returns to original. */
6265 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6266                         defaultFrame:(NSRect)defaultFrame
6268   NSRect result = [sender frame];
6270   NSTRACE (windowWillUseStandardFrame);
6272   if (fs_before_fs != -1) /* Entering fullscreen */
6273       {
6274         result = defaultFrame;
6275       }
6276   else if (next_maximized == FULLSCREEN_HEIGHT
6277       || (next_maximized == -1
6278           && abs (defaultFrame.size.height - result.size.height)
6279           > FRAME_LINE_HEIGHT (emacsframe)))
6280     {
6281       /* first click */
6282       ns_userRect = result;
6283       maximized_height = result.size.height = defaultFrame.size.height;
6284       maximized_width = -1;
6285       result.origin.y = defaultFrame.origin.y;
6286       [self setFSValue: FULLSCREEN_HEIGHT];
6287 #ifdef NS_IMPL_COCOA
6288       maximizing_resize = YES;
6289 #endif
6290     }
6291   else if (next_maximized == FULLSCREEN_WIDTH)
6292     {
6293       ns_userRect = result;
6294       maximized_width = result.size.width = defaultFrame.size.width;
6295       maximized_height = -1;
6296       result.origin.x = defaultFrame.origin.x;
6297       [self setFSValue: FULLSCREEN_WIDTH];
6298     }
6299   else if (next_maximized == FULLSCREEN_MAXIMIZED
6300            || (next_maximized == -1
6301                && abs (defaultFrame.size.width - result.size.width)
6302                > FRAME_COLUMN_WIDTH (emacsframe)))
6303     {
6304       result = defaultFrame;  /* second click */
6305       maximized_width = result.size.width;
6306       maximized_height = result.size.height;
6307       [self setFSValue: FULLSCREEN_MAXIMIZED];
6308 #ifdef NS_IMPL_COCOA
6309       maximizing_resize = YES;
6310 #endif
6311     }
6312   else
6313     {
6314       /* restore */
6315       result = ns_userRect.size.height ? ns_userRect : result;
6316       ns_userRect = NSMakeRect (0, 0, 0, 0);
6317 #ifdef NS_IMPL_COCOA
6318       maximizing_resize = fs_state != FULLSCREEN_NONE;
6319 #endif
6320       [self setFSValue: FULLSCREEN_NONE];
6321       maximized_width = maximized_height = -1;
6322     }
6324   if (fs_before_fs == -1) next_maximized = -1;
6325   [self windowWillResize: sender toSize: result.size];
6326   return result;
6330 - (void)windowDidDeminiaturize: sender
6332   NSTRACE (windowDidDeminiaturize);
6333   if (!emacsframe->output_data.ns)
6334     return;
6336   SET_FRAME_ICONIFIED (emacsframe, 0);
6337   SET_FRAME_VISIBLE (emacsframe, 1);
6338   windows_or_buffers_changed = 63;
6340   if (emacs_event)
6341     {
6342       emacs_event->kind = DEICONIFY_EVENT;
6343       EV_TRAILER ((id)nil);
6344     }
6348 - (void)windowDidExpose: sender
6350   NSTRACE (windowDidExpose);
6351   if (!emacsframe->output_data.ns)
6352     return;
6354   SET_FRAME_VISIBLE (emacsframe, 1);
6355   SET_FRAME_GARBAGED (emacsframe);
6357   if (send_appdefined)
6358     ns_send_appdefined (-1);
6362 - (void)windowDidMiniaturize: sender
6364   NSTRACE (windowDidMiniaturize);
6365   if (!emacsframe->output_data.ns)
6366     return;
6368   SET_FRAME_ICONIFIED (emacsframe, 1);
6369   SET_FRAME_VISIBLE (emacsframe, 0);
6371   if (emacs_event)
6372     {
6373       emacs_event->kind = ICONIFY_EVENT;
6374       EV_TRAILER ((id)nil);
6375     }
6378 #ifdef HAVE_NATIVE_FS
6379 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6380       willUseFullScreenPresentationOptions:
6381   (NSApplicationPresentationOptions)proposedOptions
6383   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6385 #endif
6387 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6389   fs_before_fs = fs_state;
6392 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6394   [self setFSValue: FULLSCREEN_BOTH];
6395   if (! [self fsIsNative])
6396     {
6397       [self windowDidBecomeKey:notification];
6398       [nonfs_window orderOut:self];
6399     }
6400   else
6401     {
6402       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
6403 #ifdef NS_IMPL_COCOA
6404 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6405       unsigned val = (unsigned)[NSApp presentationOptions];
6407       // OSX 10.7 bug fix, the menu won't appear without this.
6408       // val is non-zero on other OSX versions.
6409       if (val == 0)
6410         {
6411           NSApplicationPresentationOptions options
6412             = NSApplicationPresentationAutoHideDock
6413             | NSApplicationPresentationAutoHideMenuBar
6414             | NSApplicationPresentationFullScreen
6415             | NSApplicationPresentationAutoHideToolbar;
6417           [NSApp setPresentationOptions: options];
6418         }
6419 #endif
6420 #endif
6421       [toolbar setVisible:tbar_visible];
6422     }
6425 - (void)windowWillExitFullScreen:(NSNotification *)notification
6427   if (next_maximized != -1)
6428     fs_before_fs = next_maximized;
6431 - (void)windowDidExitFullScreen:(NSNotification *)notification
6433   [self setFSValue: fs_before_fs];
6434   fs_before_fs = -1;
6435 #ifdef HAVE_NATIVE_FS
6436   [self updateCollectionBehavior];
6437 #endif
6438   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6439     {
6440       [toolbar setVisible:YES];
6441       update_frame_tool_bar (emacsframe);
6442       [self updateFrameSize:YES];
6443       [[self window] display];
6444     }
6445   else
6446     [toolbar setVisible:NO];
6448   if (next_maximized != -1)
6449     [[self window] performZoom:self];
6452 - (BOOL)fsIsNative
6454   return fs_is_native;
6457 - (BOOL)isFullscreen
6459   if (! fs_is_native) return nonfs_window != nil;
6460 #ifdef HAVE_NATIVE_FS
6461   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6462 #else
6463   return NO;
6464 #endif
6467 #ifdef HAVE_NATIVE_FS
6468 - (void)updateCollectionBehavior
6470   if (! [self isFullscreen])
6471     {
6472       NSWindow *win = [self window];
6473       NSWindowCollectionBehavior b = [win collectionBehavior];
6474       if (ns_use_native_fullscreen)
6475         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6476       else
6477         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6479       [win setCollectionBehavior: b];
6480       fs_is_native = ns_use_native_fullscreen;
6481     }
6483 #endif
6485 - (void)toggleFullScreen: (id)sender
6487   NSWindow *w, *fw;
6488   BOOL onFirstScreen;
6489   struct frame *f;
6490   NSSize sz;
6491   NSRect r, wr;
6492   NSColor *col;
6494   if (fs_is_native)
6495     {
6496 #ifdef HAVE_NATIVE_FS
6497       [[self window] toggleFullScreen:sender];
6498 #endif
6499       return;
6500     }
6502   w = [self window];
6503   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6504   f = emacsframe;
6505   wr = [w frame];
6506   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6507                                  (FRAME_DEFAULT_FACE (f)),
6508                                  f);
6510   sz.width = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
6511   sz.height = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
6513   if (fs_state != FULLSCREEN_BOTH)
6514     {
6515       NSScreen *screen = [w screen];
6517 #if defined (NS_IMPL_COCOA) && \
6518   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
6519       /* Hide ghost menu bar on secondary monitor? */
6520       if (! onFirstScreen)
6521         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
6522 #endif
6523       /* Hide dock and menubar if we are on the primary screen.  */
6524       if (onFirstScreen)
6525         {
6526 #ifdef NS_IMPL_COCOA
6527           NSApplicationPresentationOptions options
6528             = NSApplicationPresentationAutoHideDock
6529             | NSApplicationPresentationAutoHideMenuBar;
6531           [NSApp setPresentationOptions: options];
6532 #else
6533           [NSMenu setMenuBarVisible:NO];
6534 #endif
6535         }
6537       fw = [[EmacsFSWindow alloc]
6538                        initWithContentRect:[w contentRectForFrameRect:wr]
6539                                  styleMask:NSBorderlessWindowMask
6540                                    backing:NSBackingStoreBuffered
6541                                      defer:YES
6542                                     screen:screen];
6544       [fw setContentView:[w contentView]];
6545       [fw setTitle:[w title]];
6546       [fw setDelegate:self];
6547       [fw setAcceptsMouseMovedEvents: YES];
6548       [fw useOptimizedDrawing: YES];
6549       [fw setResizeIncrements: sz];
6550       [fw setBackgroundColor: col];
6551       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6552         [fw setOpaque: NO];
6554       f->border_width = 0;
6555       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6556       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6557       FRAME_TOOLBAR_HEIGHT (f) = 0;
6559       nonfs_window = w;
6561       [self windowWillEnterFullScreen:nil];
6562       [fw makeKeyAndOrderFront:NSApp];
6563       [fw makeFirstResponder:self];
6564       [w orderOut:self];
6565       r = [fw frameRectForContentRect:[screen frame]];
6566       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
6567       [self windowDidEnterFullScreen:nil];
6568       [fw display];
6569     }
6570   else
6571     {
6572       fw = w;
6573       w = nonfs_window;
6574       nonfs_window = nil;
6576       if (onFirstScreen)
6577         {
6578 #ifdef NS_IMPL_COCOA
6579           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6580 #else
6581           [NSMenu setMenuBarVisible:YES];
6582 #endif
6583         }
6585       [w setContentView:[fw contentView]];
6586       [w setResizeIncrements: sz];
6587       [w setBackgroundColor: col];
6588       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6589         [w setOpaque: NO];
6591       f->border_width = bwidth;
6592       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6593       if (FRAME_EXTERNAL_TOOL_BAR (f))
6594         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6596       [self windowWillExitFullScreen:nil];
6597       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
6598       [fw close];
6599       [w makeKeyAndOrderFront:NSApp];
6600       [self windowDidExitFullScreen:nil];
6601       [self updateFrameSize:YES];
6602     }
6605 - (void)handleFS
6607   if (fs_state != emacsframe->want_fullscreen)
6608     {
6609       if (fs_state == FULLSCREEN_BOTH)
6610         {
6611           [self toggleFullScreen:self];
6612         }
6614       switch (emacsframe->want_fullscreen)
6615         {
6616         case FULLSCREEN_BOTH:
6617           [self toggleFullScreen:self];
6618           break;
6619         case FULLSCREEN_WIDTH:
6620           next_maximized = FULLSCREEN_WIDTH;
6621           if (fs_state != FULLSCREEN_BOTH)
6622             [[self window] performZoom:self];
6623           break;
6624         case FULLSCREEN_HEIGHT:
6625           next_maximized = FULLSCREEN_HEIGHT;
6626           if (fs_state != FULLSCREEN_BOTH)
6627             [[self window] performZoom:self];
6628           break;
6629         case FULLSCREEN_MAXIMIZED:
6630           next_maximized = FULLSCREEN_MAXIMIZED;
6631           if (fs_state != FULLSCREEN_BOTH)
6632             [[self window] performZoom:self];
6633           break;
6634         case FULLSCREEN_NONE:
6635           if (fs_state != FULLSCREEN_BOTH)
6636             {
6637               next_maximized = FULLSCREEN_NONE;
6638               [[self window] performZoom:self];
6639             }
6640           break;
6641         }
6643       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6644     }
6648 - (void) setFSValue: (int)value
6650   Lisp_Object lval = Qnil;
6651   switch (value)
6652     {
6653     case FULLSCREEN_BOTH:
6654       lval = Qfullboth;
6655       break;
6656     case FULLSCREEN_WIDTH:
6657       lval = Qfullwidth;
6658       break;
6659     case FULLSCREEN_HEIGHT:
6660       lval = Qfullheight;
6661       break;
6662     case FULLSCREEN_MAXIMIZED:
6663       lval = Qmaximized;
6664       break;
6665     }
6666   store_frame_param (emacsframe, Qfullscreen, lval);
6667   fs_state = value;
6670 - (void)mouseEntered: (NSEvent *)theEvent
6672   NSTRACE (mouseEntered);
6673   if (emacsframe)
6674     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6675       = EV_TIMESTAMP (theEvent);
6679 - (void)mouseExited: (NSEvent *)theEvent
6681   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6683   NSTRACE (mouseExited);
6685   if (!hlinfo)
6686     return;
6688   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6689     = EV_TIMESTAMP (theEvent);
6691   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6692     {
6693       clear_mouse_face (hlinfo);
6694       hlinfo->mouse_face_mouse_frame = 0;
6695     }
6699 - menuDown: sender
6701   NSTRACE (menuDown);
6702   if (context_menu_value == -1)
6703     context_menu_value = [sender tag];
6704   else
6705     {
6706       NSInteger tag = [sender tag];
6707       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6708                                     emacsframe->menu_bar_vector,
6709                                     (void *)tag);
6710     }
6712   ns_send_appdefined (-1);
6713   return self;
6717 - (EmacsToolbar *)toolbar
6719   return toolbar;
6723 /* this gets called on toolbar button click */
6724 - toolbarClicked: (id)item
6726   NSEvent *theEvent;
6727   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6729   NSTRACE (toolbarClicked);
6731   if (!emacs_event)
6732     return self;
6734   /* send first event (for some reason two needed) */
6735   theEvent = [[self window] currentEvent];
6736   emacs_event->kind = TOOL_BAR_EVENT;
6737   XSETFRAME (emacs_event->arg, emacsframe);
6738   EV_TRAILER (theEvent);
6740   emacs_event->kind = TOOL_BAR_EVENT;
6741 /*   XSETINT (emacs_event->code, 0); */
6742   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6743                            idx + TOOL_BAR_ITEM_KEY);
6744   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6745   EV_TRAILER (theEvent);
6746   return self;
6750 - toggleToolbar: (id)sender
6752   if (!emacs_event)
6753     return self;
6755   emacs_event->kind = NS_NONKEY_EVENT;
6756   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6757   EV_TRAILER ((id)nil);
6758   return self;
6762 - (void)drawRect: (NSRect)rect
6764   int x = NSMinX (rect), y = NSMinY (rect);
6765   int width = NSWidth (rect), height = NSHeight (rect);
6767   NSTRACE (drawRect);
6769   if (!emacsframe || !emacsframe->output_data.ns)
6770     return;
6772   ns_clear_frame_area (emacsframe, x, y, width, height);
6773   expose_frame (emacsframe, x, y, width, height);
6775   /*
6776     drawRect: may be called (at least in OS X 10.5) for invisible
6777     views as well for some reason.  Thus, do not infer visibility
6778     here.
6780     emacsframe->async_visible = 1;
6781     emacsframe->async_iconified = 0;
6782   */
6786 /* NSDraggingDestination protocol methods.  Actually this is not really a
6787    protocol, but a category of Object.  O well...  */
6789 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6791   NSTRACE (draggingEntered);
6792   return NSDragOperationGeneric;
6796 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6798   return YES;
6802 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6804   id pb;
6805   int x, y;
6806   NSString *type;
6807   NSEvent *theEvent = [[self window] currentEvent];
6808   NSPoint position;
6809   NSDragOperation op = [sender draggingSourceOperationMask];
6810   int modifiers = 0;
6812   NSTRACE (performDragOperation);
6814   if (!emacs_event)
6815     return NO;
6817   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6818   x = lrint (position.x);  y = lrint (position.y);
6820   pb = [sender draggingPasteboard];
6821   type = [pb availableTypeFromArray: ns_drag_types];
6823   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
6824       // URL drags contain all operations (0xf), don't allow all to be set.
6825       (op & 0xf) != 0xf)
6826     {
6827       if (op & NSDragOperationLink)
6828         modifiers |= NSControlKeyMask;
6829       if (op & NSDragOperationCopy)
6830         modifiers |= NSAlternateKeyMask;
6831       if (op & NSDragOperationGeneric)
6832         modifiers |= NSCommandKeyMask;
6833     }
6835   modifiers = EV_MODIFIERS2 (modifiers);
6836   if (type == 0)
6837     {
6838       return NO;
6839     }
6840   else if ([type isEqualToString: NSFilenamesPboardType])
6841     {
6842       NSArray *files;
6843       NSEnumerator *fenum;
6844       NSString *file;
6846       if (!(files = [pb propertyListForType: type]))
6847         return NO;
6849       fenum = [files objectEnumerator];
6850       while ( (file = [fenum nextObject]) )
6851         {
6852           emacs_event->kind = DRAG_N_DROP_EVENT;
6853           XSETINT (emacs_event->x, x);
6854           XSETINT (emacs_event->y, y);
6855           ns_input_file = append2 (ns_input_file,
6856                                    build_string ([file UTF8String]));
6857           emacs_event->modifiers = modifiers;
6858           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
6859           EV_TRAILER (theEvent);
6860         }
6861       return YES;
6862     }
6863   else if ([type isEqualToString: NSURLPboardType])
6864     {
6865       NSURL *url = [NSURL URLFromPasteboard: pb];
6866       if (url == nil) return NO;
6868       emacs_event->kind = DRAG_N_DROP_EVENT;
6869       XSETINT (emacs_event->x, x);
6870       XSETINT (emacs_event->y, y);
6871       emacs_event->modifiers = modifiers;
6872       emacs_event->arg =  list2 (Qurl,
6873                                  build_string ([[url absoluteString]
6874                                                  UTF8String]));
6875       EV_TRAILER (theEvent);
6877       if ([url isFileURL] != NO)
6878         {
6879           NSString *file = [url path];
6880           ns_input_file = append2 (ns_input_file,
6881                                    build_string ([file UTF8String]));
6882         }
6883       return YES;
6884     }
6885   else if ([type isEqualToString: NSStringPboardType]
6886            || [type isEqualToString: NSTabularTextPboardType])
6887     {
6888       NSString *data;
6890       if (! (data = [pb stringForType: type]))
6891         return NO;
6893       emacs_event->kind = DRAG_N_DROP_EVENT;
6894       XSETINT (emacs_event->x, x);
6895       XSETINT (emacs_event->y, y);
6896       emacs_event->modifiers = modifiers;
6897       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
6898       EV_TRAILER (theEvent);
6899       return YES;
6900     }
6901   else
6902     {
6903       fprintf (stderr, "Invalid data type in dragging pasteboard");
6904       return NO;
6905     }
6909 - (id) validRequestorForSendType: (NSString *)typeSent
6910                       returnType: (NSString *)typeReturned
6912   NSTRACE (validRequestorForSendType);
6913   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6914       && typeReturned == nil)
6915     {
6916       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6917         return self;
6918     }
6920   return [super validRequestorForSendType: typeSent
6921                                returnType: typeReturned];
6925 /* The next two methods are part of NSServicesRequests informal protocol,
6926    supposedly called when a services menu item is chosen from this app.
6927    But this should not happen because we override the services menu with our
6928    own entries which call ns-perform-service.
6929    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6930    So let's at least stub them out until further investigation can be done. */
6932 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6934   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6935      be written into the buffer in place of the existing selection..
6936      ordinary service calls go through functions defined in ns-win.el */
6937   return NO;
6940 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6942   NSArray *typesDeclared;
6943   Lisp_Object val;
6945   /* We only support NSStringPboardType */
6946   if ([types containsObject:NSStringPboardType] == NO) {
6947     return NO;
6948   }
6950   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6951   if (CONSP (val) && SYMBOLP (XCAR (val)))
6952     {
6953       val = XCDR (val);
6954       if (CONSP (val) && NILP (XCDR (val)))
6955         val = XCAR (val);
6956     }
6957   if (! STRINGP (val))
6958     return NO;
6960   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6961   [pb declareTypes:typesDeclared owner:nil];
6962   ns_string_to_pasteboard (pb, val);
6963   return YES;
6967 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6968    (gives a miniaturized version of the window); currently we use the latter for
6969    frames whose active buffer doesn't correspond to any file
6970    (e.g., '*scratch*') */
6971 - setMiniwindowImage: (BOOL) setMini
6973   id image = [[self window] miniwindowImage];
6974   NSTRACE (setMiniwindowImage);
6976   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6977      about "AppleDockIconEnabled" notwithstanding, however the set message
6978      below has its effect nonetheless. */
6979   if (image != emacsframe->output_data.ns->miniimage)
6980     {
6981       if (image && [image isKindOfClass: [EmacsImage class]])
6982         [image release];
6983       [[self window] setMiniwindowImage:
6984                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6985     }
6987   return self;
6991 - (void) setRows: (int) r andColumns: (int) c
6993   rows = r;
6994   cols = c;
6997 @end  /* EmacsView */
7001 /* ==========================================================================
7003     EmacsWindow implementation
7005    ========================================================================== */
7007 @implementation EmacsWindow
7009 #ifdef NS_IMPL_COCOA
7010 - (id)accessibilityAttributeValue:(NSString *)attribute
7012   Lisp_Object str = Qnil;
7013   struct frame *f = SELECTED_FRAME ();
7014   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7016   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7017     return NSAccessibilityTextFieldRole;
7019   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7020       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7021     {
7022       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7023     }
7024   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7025     {
7026       if (! NILP (BVAR (curbuf, mark_active)))
7027           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7029       if (NILP (str))
7030         {
7031           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7032           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7033           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7035           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7036             str = make_uninit_multibyte_string (range, byte_range);
7037           else
7038             str = make_uninit_string (range);
7039           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7040              Is this a problem?  */
7041           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7042         }
7043     }
7046   if (! NILP (str))
7047     {
7048       if (CONSP (str) && SYMBOLP (XCAR (str)))
7049         {
7050           str = XCDR (str);
7051           if (CONSP (str) && NILP (XCDR (str)))
7052             str = XCAR (str);
7053         }
7054       if (STRINGP (str))
7055         {
7056           const char *utfStr = SSDATA (str);
7057           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7058           return nsStr;
7059         }
7060     }
7062   return [super accessibilityAttributeValue:attribute];
7064 #endif /* NS_IMPL_COCOA */
7066 /* If we have multiple monitors, one above the other, we don't want to
7067    restrict the height to just one monitor.  So we override this.  */
7068 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7070   /* When making the frame visible for the first time or if there is just
7071      one screen, we want to constrain.  Other times not.  */
7072   NSArray *screens = [NSScreen screens];
7073   NSUInteger nr_screens = [screens count], nr_eff_screens = 0, i;
7074   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
7075   NSTRACE (constrainFrameRect);
7076   NSTRACE_RECT ("input", frameRect);
7078   if (ns_menu_bar_should_be_hidden ())
7079     return frameRect;
7081   if (nr_screens == 1)
7082     return [super constrainFrameRect:frameRect toScreen:screen];
7084 #ifdef NS_IMPL_COCOA
7085 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7086   // If separate spaces is on, it is like each screen is independent.  There is
7087   // no spanning of frames across screens.
7088   if ([NSScreen screensHaveSeparateSpaces])
7089     return [super constrainFrameRect:frameRect toScreen:screen];
7090 #endif
7091 #endif
7093   for (i = 0; i < nr_screens; ++i)
7094     {
7095       NSScreen *s = [screens objectAtIndex: i];
7096       NSRect scrrect = [s frame];
7097       NSRect intersect = NSIntersectionRect (frameRect, scrrect);
7099       if (intersect.size.width > 0 || intersect.size.height > 0)
7100         ++nr_eff_screens;
7101     }
7103   if (nr_eff_screens == 1)
7104     return [super constrainFrameRect:frameRect toScreen:screen];
7106   /* The default implementation does two things 1) ensure that the top
7107      of the rectangle is below the menu bar (or below the top of the
7108      screen) and 2) resizes windows larger than the screen. As we
7109      don't want the latter, a smaller rectangle is used. */
7110 #define FAKE_HEIGHT 64
7111   float old_top = frameRect.origin.y + frameRect.size.height;
7112   NSRect r;
7113   r.size.height = FAKE_HEIGHT;
7114   r.size.width = frameRect.size.width;
7115   r.origin.x = frameRect.origin.x;
7116   r.origin.y = old_top - FAKE_HEIGHT;
7118   NSTRACE_RECT ("input to super", r);
7120   r = [super constrainFrameRect:r toScreen:screen];
7122   NSTRACE_RECT ("output from super", r);
7124   float new_top = r.origin.y + FAKE_HEIGHT;
7125   if (new_top < old_top)
7126   {
7127     frameRect.origin.y = new_top - frameRect.size.height;
7128   }
7130   NSTRACE_RECT ("output", frameRect);
7132   return frameRect;
7133 #undef FAKE_HEIGHT
7136 @end /* EmacsWindow */
7139 @implementation EmacsFSWindow
7141 - (BOOL)canBecomeKeyWindow
7143   return YES;
7146 - (BOOL)canBecomeMainWindow
7148   return YES;
7151 @end
7153 /* ==========================================================================
7155     EmacsScroller implementation
7157    ========================================================================== */
7160 @implementation EmacsScroller
7162 /* for repeat button push */
7163 #define SCROLL_BAR_FIRST_DELAY 0.5
7164 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
7166 + (CGFloat) scrollerWidth
7168   /* TODO: if we want to allow variable widths, this is the place to do it,
7169            however neither GNUstep nor Cocoa support it very well */
7170   return [NSScroller scrollerWidth];
7174 - initFrame: (NSRect )r window: (Lisp_Object)nwin
7176   NSTRACE (EmacsScroller_initFrame);
7178   r.size.width = [EmacsScroller scrollerWidth];
7179   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
7180   [self setContinuous: YES];
7181   [self setEnabled: YES];
7183   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
7184      locked against the top and bottom edges, and right edge on OS X, where
7185      scrollers are on right. */
7186 #ifdef NS_IMPL_GNUSTEP
7187   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
7188 #else
7189   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
7190 #endif
7192   window = XWINDOW (nwin);
7193   condemned = NO;
7194   pixel_height = NSHeight (r);
7195   if (pixel_height == 0) pixel_height = 1;
7196   min_portion = 20 / pixel_height;
7198   frame = XFRAME (window->frame);
7199   if (FRAME_LIVE_P (frame))
7200     {
7201       int i;
7202       EmacsView *view = FRAME_NS_VIEW (frame);
7203       NSView *sview = [[view window] contentView];
7204       NSArray *subs = [sview subviews];
7206       /* disable optimization stopping redraw of other scrollbars */
7207       view->scrollbarsNeedingUpdate = 0;
7208       for (i =[subs count]-1; i >= 0; i--)
7209         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
7210           view->scrollbarsNeedingUpdate++;
7211       [sview addSubview: self];
7212     }
7214 /*  [self setFrame: r]; */
7216   return self;
7220 - (void)setFrame: (NSRect)newRect
7222   NSTRACE (EmacsScroller_setFrame);
7223 /*  block_input (); */
7224   pixel_height = NSHeight (newRect);
7225   if (pixel_height == 0) pixel_height = 1;
7226   min_portion = 20 / pixel_height;
7227   [super setFrame: newRect];
7228 /*  unblock_input (); */
7232 - (void)dealloc
7234   NSTRACE (EmacsScroller_dealloc);
7235   if (window)
7236     wset_vertical_scroll_bar (window, Qnil);
7237   window = 0;
7238   [super dealloc];
7242 - condemn
7244   NSTRACE (condemn);
7245   condemned =YES;
7246   return self;
7250 - reprieve
7252   NSTRACE (reprieve);
7253   condemned =NO;
7254   return self;
7258 -(bool)judge
7260   NSTRACE (judge);
7261   bool ret = condemned;
7262   if (condemned)
7263     {
7264       EmacsView *view;
7265       block_input ();
7266       /* ensure other scrollbar updates after deletion */
7267       view = (EmacsView *)FRAME_NS_VIEW (frame);
7268       if (view != nil)
7269         view->scrollbarsNeedingUpdate++;
7270       if (window)
7271         wset_vertical_scroll_bar (window, Qnil);
7272       window = 0;
7273       [self removeFromSuperview];
7274       [self release];
7275       unblock_input ();
7276     }
7277   return ret;
7281 - (void)resetCursorRects
7283   NSRect visible = [self visibleRect];
7284   NSTRACE (resetCursorRects);
7286   if (!NSIsEmptyRect (visible))
7287     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
7288   [[NSCursor arrowCursor] setOnMouseEntered: YES];
7292 - (int) checkSamePosition: (int) position portion: (int) portion
7293                     whole: (int) whole
7295   return em_position ==position && em_portion ==portion && em_whole ==whole
7296     && portion != whole; /* needed for resize empty buf */
7300 - setPosition: (int)position portion: (int)portion whole: (int)whole
7302   NSTRACE (setPosition);
7304   em_position = position;
7305   em_portion = portion;
7306   em_whole = whole;
7308   if (portion >= whole)
7309     {
7310 #ifdef NS_IMPL_COCOA
7311       [self setKnobProportion: 1.0];
7312       [self setDoubleValue: 1.0];
7313 #else
7314       [self setFloatValue: 0.0 knobProportion: 1.0];
7315 #endif
7316     }
7317   else
7318     {
7319       float pos;
7320       CGFloat por;
7321       portion = max ((float)whole*min_portion/pixel_height, portion);
7322       pos = (float)position / (whole - portion);
7323       por = (CGFloat)portion/whole;
7324 #ifdef NS_IMPL_COCOA
7325       [self setKnobProportion: por];
7326       [self setDoubleValue: pos];
7327 #else
7328       [self setFloatValue: pos knobProportion: por];
7329 #endif
7330     }
7332   return self;
7335 /* set up emacs_event */
7336 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
7338   Lisp_Object win;
7339   if (!emacs_event)
7340     return;
7342   emacs_event->part = last_hit_part;
7343   emacs_event->code = 0;
7344   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
7345   XSETWINDOW (win, window);
7346   emacs_event->frame_or_window = win;
7347   emacs_event->timestamp = EV_TIMESTAMP (e);
7348   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
7349   emacs_event->arg = Qnil;
7350   XSETINT (emacs_event->x, loc * pixel_height);
7351   XSETINT (emacs_event->y, pixel_height-20);
7353   if (q_event_ptr)
7354     {
7355       n_emacs_events_pending++;
7356       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7357     }
7358   else
7359     hold_event (emacs_event);
7360   EVENT_INIT (*emacs_event);
7361   ns_send_appdefined (-1);
7365 /* called manually thru timer to implement repeated button action w/hold-down */
7366 - repeatScroll: (NSTimer *)scrollEntry
7368   NSEvent *e = [[self window] currentEvent];
7369   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
7370   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7372   /* clear timer if need be */
7373   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7374     {
7375         [scroll_repeat_entry invalidate];
7376         [scroll_repeat_entry release];
7377         scroll_repeat_entry = nil;
7379         if (inKnob)
7380           return self;
7382         scroll_repeat_entry
7383           = [[NSTimer scheduledTimerWithTimeInterval:
7384                         SCROLL_BAR_CONTINUOUS_DELAY
7385                                             target: self
7386                                           selector: @selector (repeatScroll:)
7387                                           userInfo: 0
7388                                            repeats: YES]
7389               retain];
7390     }
7392   [self sendScrollEventAtLoc: 0 fromEvent: e];
7393   return self;
7397 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
7398    mouseDragged events without going into a modal loop. */
7399 - (void)mouseDown: (NSEvent *)e
7401   NSRect sr, kr;
7402   /* hitPart is only updated AFTER event is passed on */
7403   NSScrollerPart part = [self testPart: [e locationInWindow]];
7404   CGFloat inc = 0.0, loc, kloc, pos;
7405   int edge = 0;
7407   NSTRACE (EmacsScroller_mouseDown);
7409   switch (part)
7410     {
7411     case NSScrollerDecrementPage:
7412         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7413     case NSScrollerIncrementPage:
7414         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7415     case NSScrollerDecrementLine:
7416       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7417     case NSScrollerIncrementLine:
7418       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7419     case NSScrollerKnob:
7420       last_hit_part = scroll_bar_handle; break;
7421     case NSScrollerKnobSlot:  /* GNUstep-only */
7422       last_hit_part = scroll_bar_move_ratio; break;
7423     default:  /* NSScrollerNoPart? */
7424       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7425                (long) part);
7426       return;
7427     }
7429   if (inc != 0.0)
7430     {
7431       pos = 0;      /* ignored */
7433       /* set a timer to repeat, as we can't let superclass do this modally */
7434       scroll_repeat_entry
7435         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7436                                             target: self
7437                                           selector: @selector (repeatScroll:)
7438                                           userInfo: 0
7439                                            repeats: YES]
7440             retain];
7441     }
7442   else
7443     {
7444       /* handle, or on GNUstep possibly slot */
7445       NSEvent *fake_event;
7447       /* compute float loc in slot and mouse offset on knob */
7448       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7449                       toView: nil];
7450       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7451       if (loc <= 0.0)
7452         {
7453           loc = 0.0;
7454           edge = -1;
7455         }
7456       else if (loc >= NSHeight (sr))
7457         {
7458           loc = NSHeight (sr);
7459           edge = 1;
7460         }
7462       if (edge)
7463         kloc = 0.5 * edge;
7464       else
7465         {
7466           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7467                           toView: nil];
7468           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7469         }
7470       last_mouse_offset = kloc;
7472       /* if knob, tell emacs a location offset by knob pos
7473          (to indicate top of handle) */
7474       if (part == NSScrollerKnob)
7475           pos = (loc - last_mouse_offset) / NSHeight (sr);
7476       else
7477         /* else this is a slot click on GNUstep: go straight there */
7478         pos = loc / NSHeight (sr);
7480       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7481       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7482                                       location: [e locationInWindow]
7483                                  modifierFlags: [e modifierFlags]
7484                                      timestamp: [e timestamp]
7485                                   windowNumber: [e windowNumber]
7486                                        context: [e context]
7487                                    eventNumber: [e eventNumber]
7488                                     clickCount: [e clickCount]
7489                                       pressure: [e pressure]];
7490       [super mouseUp: fake_event];
7491     }
7493   if (part != NSScrollerKnob)
7494     [self sendScrollEventAtLoc: pos fromEvent: e];
7498 /* Called as we manually track scroller drags, rather than superclass. */
7499 - (void)mouseDragged: (NSEvent *)e
7501     NSRect sr;
7502     double loc, pos;
7504     NSTRACE (EmacsScroller_mouseDragged);
7506       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7507                       toView: nil];
7508       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7510       if (loc <= 0.0)
7511         {
7512           loc = 0.0;
7513         }
7514       else if (loc >= NSHeight (sr) + last_mouse_offset)
7515         {
7516           loc = NSHeight (sr) + last_mouse_offset;
7517         }
7519       pos = (loc - last_mouse_offset) / NSHeight (sr);
7520       [self sendScrollEventAtLoc: pos fromEvent: e];
7524 - (void)mouseUp: (NSEvent *)e
7526   if (scroll_repeat_entry)
7527     {
7528       [scroll_repeat_entry invalidate];
7529       [scroll_repeat_entry release];
7530       scroll_repeat_entry = nil;
7531     }
7532   last_hit_part = scroll_bar_above_handle;
7536 /* treat scrollwheel events in the bar as though they were in the main window */
7537 - (void) scrollWheel: (NSEvent *)theEvent
7539   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7540   [view mouseDown: theEvent];
7543 @end  /* EmacsScroller */
7546 #ifdef NS_IMPL_GNUSTEP
7547 /* Dummy class to get rid of startup warnings.  */
7548 @implementation EmacsDocument
7550 @end
7551 #endif
7554 /* ==========================================================================
7556    Font-related functions; these used to be in nsfaces.m
7558    ========================================================================== */
7561 Lisp_Object
7562 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7564   struct font *font = XFONT_OBJECT (font_object);
7565   EmacsView *view = FRAME_NS_VIEW (f);
7567   if (fontset < 0)
7568     fontset = fontset_from_font (font_object);
7569   FRAME_FONTSET (f) = fontset;
7571   if (FRAME_FONT (f) == font)
7572     /* This font is already set in frame F.  There's nothing more to
7573        do.  */
7574     return font_object;
7576   FRAME_FONT (f) = font;
7578   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7579   FRAME_COLUMN_WIDTH (f) = font->average_width;
7580   FRAME_LINE_HEIGHT (f) = font->height;
7582   /* Compute the scroll bar width in character columns.  */
7583   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7584     {
7585       int wid = FRAME_COLUMN_WIDTH (f);
7586       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7587         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7588     }
7589   else
7590     {
7591       int wid = FRAME_COLUMN_WIDTH (f);
7592       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7593     }
7595   /* Compute the scroll bar height in character lines.  */
7596   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
7597     {
7598       int height = FRAME_LINE_HEIGHT (f);
7599       FRAME_CONFIG_SCROLL_BAR_LINES (f)
7600         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
7601     }
7602   else
7603     {
7604       int height = FRAME_LINE_HEIGHT (f);
7605       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
7606     }
7608   /* Now make the frame display the given font.  */
7609   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
7610     x_set_window_size (f, false, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
7611                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), true);
7613   return font_object;
7617 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7618 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7619          in 1.43. */
7621 const char *
7622 ns_xlfd_to_fontname (const char *xlfd)
7623 /* --------------------------------------------------------------------------
7624     Convert an X font name (XLFD) to an NS font name.
7625     Only family is used.
7626     The string returned is temporarily allocated.
7627    -------------------------------------------------------------------------- */
7629   char *name = xmalloc (180);
7630   int i, len;
7631   const char *ret;
7633   if (!strncmp (xlfd, "--", 2))
7634     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7635   else
7636     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7638   /* stopgap for malformed XLFD input */
7639   if (strlen (name) == 0)
7640     strcpy (name, "Monaco");
7642   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7643      also uppercase after '-' or ' ' */
7644   name[0] = c_toupper (name[0]);
7645   for (len =strlen (name), i =0; i<len; i++)
7646     {
7647       if (name[i] == '$')
7648         {
7649           name[i] = '-';
7650           if (i+1<len)
7651             name[i+1] = c_toupper (name[i+1]);
7652         }
7653       else if (name[i] == '_')
7654         {
7655           name[i] = ' ';
7656           if (i+1<len)
7657             name[i+1] = c_toupper (name[i+1]);
7658         }
7659     }
7660 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7661   ret = [[NSString stringWithUTF8String: name] UTF8String];
7662   xfree (name);
7663   return ret;
7667 void
7668 syms_of_nsterm (void)
7670   NSTRACE (syms_of_nsterm);
7672   ns_antialias_threshold = 10.0;
7674   /* from 23+ we need to tell emacs what modifiers there are.. */
7675   DEFSYM (Qmodifier_value, "modifier-value");
7676   DEFSYM (Qalt, "alt");
7677   DEFSYM (Qhyper, "hyper");
7678   DEFSYM (Qmeta, "meta");
7679   DEFSYM (Qsuper, "super");
7680   DEFSYM (Qcontrol, "control");
7681   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7683   DEFSYM (Qfile, "file");
7684   DEFSYM (Qurl, "url");
7686   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7687   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7688   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7689   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7690   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7692   DEFVAR_LISP ("ns-input-file", ns_input_file,
7693               "The file specified in the last NS event.");
7694   ns_input_file =Qnil;
7696   DEFVAR_LISP ("ns-working-text", ns_working_text,
7697               "String for visualizing working composition sequence.");
7698   ns_working_text =Qnil;
7700   DEFVAR_LISP ("ns-input-font", ns_input_font,
7701               "The font specified in the last NS event.");
7702   ns_input_font =Qnil;
7704   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7705               "The fontsize specified in the last NS event.");
7706   ns_input_fontsize =Qnil;
7708   DEFVAR_LISP ("ns-input-line", ns_input_line,
7709                "The line specified in the last NS event.");
7710   ns_input_line =Qnil;
7712   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7713                "The service name specified in the last NS event.");
7714   ns_input_spi_name =Qnil;
7716   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7717                "The service argument specified in the last NS event.");
7718   ns_input_spi_arg =Qnil;
7720   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7721                "This variable describes the behavior of the alternate or option key.\n\
7722 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7723 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7724 at all, allowing it to be used at a lower level for accented character entry.");
7725   ns_alternate_modifier = Qmeta;
7727   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7728                "This variable describes the behavior of the right alternate or option key.\n\
7729 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7730 Set to left means be the same key as `ns-alternate-modifier'.\n\
7731 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7732 at all, allowing it to be used at a lower level for accented character entry.");
7733   ns_right_alternate_modifier = Qleft;
7735   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7736                "This variable describes the behavior of the command key.\n\
7737 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7738   ns_command_modifier = Qsuper;
7740   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7741                "This variable describes the behavior of the right command key.\n\
7742 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7743 Set to left means be the same key as `ns-command-modifier'.\n\
7744 Set to none means that the command / option key is not interpreted by Emacs\n\
7745 at all, allowing it to be used at a lower level for accented character entry.");
7746   ns_right_command_modifier = Qleft;
7748   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7749                "This variable describes the behavior of the control key.\n\
7750 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7751   ns_control_modifier = Qcontrol;
7753   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7754                "This variable describes the behavior of the right control key.\n\
7755 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7756 Set to left means be the same key as `ns-control-modifier'.\n\
7757 Set to none means that the control / option key is not interpreted by Emacs\n\
7758 at all, allowing it to be used at a lower level for accented character entry.");
7759   ns_right_control_modifier = Qleft;
7761   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7762                "This variable describes the behavior of the function key (on laptops).\n\
7763 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7764 Set to none means that the function key is not interpreted by Emacs at all,\n\
7765 allowing it to be used at a lower level for accented character entry.");
7766   ns_function_modifier = Qnone;
7768   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7769                "Non-nil (the default) means to render text antialiased.");
7770   ns_antialias_text = Qt;
7772   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7773                "Whether to confirm application quit using dialog.");
7774   ns_confirm_quit = Qnil;
7776   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7777                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7778 Only works on OSX 10.6 or later.  */);
7779   ns_auto_hide_menu_bar = Qnil;
7781   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7782      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7783 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7784 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7785 Default is t for OSX >= 10.7, nil otherwise.  */);
7786 #ifdef HAVE_NATIVE_FS
7787   ns_use_native_fullscreen = YES;
7788 #else
7789   ns_use_native_fullscreen = NO;
7790 #endif
7791   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7793   DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
7794      doc: /*Non-nil means use animation on non-native fullscreen.
7795 For native fullscreen, this does nothing.
7796 Default is nil.  */);
7797   ns_use_fullscreen_animation = NO;
7799   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
7800      doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
7801 Note that this does not apply to images.
7802 This variable is ignored on OSX < 10.7 and GNUstep.  */);
7803   ns_use_srgb_colorspace = YES;
7805   /* TODO: move to common code */
7806   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7807                doc: /* Which toolkit scroll bars Emacs uses, if any.
7808 A value of nil means Emacs doesn't use toolkit scroll bars.
7809 With the X Window system, the value is a symbol describing the
7810 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7811 With MS Windows or Nextstep, the value is t.  */);
7812   Vx_toolkit_scroll_bars = Qt;
7814   DEFVAR_BOOL ("x-use-underline-position-properties",
7815                x_use_underline_position_properties,
7816      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7817 A value of nil means ignore them.  If you encounter fonts with bogus
7818 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7819 to 4.1, set this to nil. */);
7820   x_use_underline_position_properties = 0;
7822   DEFVAR_BOOL ("x-underline-at-descent-line",
7823                x_underline_at_descent_line,
7824      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7825 A value of nil means to draw the underline according to the value of the
7826 variable `x-use-underline-position-properties', which is usually at the
7827 baseline level.  The default value is nil.  */);
7828   x_underline_at_descent_line = 0;
7830   /* Tell Emacs about this window system.  */
7831   Fprovide (Qns, Qnil);
7833   DEFSYM (Qcocoa, "cocoa");
7834   DEFSYM (Qgnustep, "gnustep");
7836 #ifdef NS_IMPL_COCOA
7837   Fprovide (Qcocoa, Qnil);
7838   syms_of_macfont ();
7839 #else
7840   Fprovide (Qgnustep, Qnil);
7841   syms_of_nsfont ();
7842 #endif