Implement inhibit-bidi-mirroring; improve biditest.el.
[emacs.git] / src / nsterm.m
blob47ad28aaa617660f09f657a7b2a07909e40c2e10
1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2014 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 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
69 #include "macfont.h"
70 #endif
71 #endif
73 /* call tracing */
74 #if 0
75 int term_trace_num = 0;
76 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
77                                 __FILE__, __LINE__, ++term_trace_num)
78 #else
79 #define NSTRACE(x)
80 #endif
82 /* Detailed tracing. "S" means "size" and "LL" stands for "lower left". */
83 #if 0
84 int term_trace_num = 0;
85 #define NSTRACE_SIZE(str,size) fprintf (stderr,                         \
86                                    "%s:%d: [%d]   " str                 \
87                                    " (S:%.0f x %.0f)\n", \
88                                    __FILE__, __LINE__, ++term_trace_num,\
89                                    size.height,                       \
90                                    size.width)
91 #define NSTRACE_RECT(s,r) fprintf (stderr,                              \
92                                    "%s:%d: [%d]   " s                   \
93                                    " (LL:%.0f x %.0f -> S:%.0f x %.0f)\n", \
94                                    __FILE__, __LINE__, ++term_trace_num,\
95                                    r.origin.x,                          \
96                                    r.origin.y,                          \
97                                    r.size.height,                       \
98                                    r.size.width)
99 #else
100 #define NSTRACE_SIZE(str,size)
101 #define NSTRACE_RECT(s,r)
102 #endif
104 extern NSString *NSMenuDidBeginTrackingNotification;
106 /* ==========================================================================
108    NSColor, EmacsColor category.
110    ========================================================================== */
111 @implementation NSColor (EmacsColor)
112 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
113                          blue:(CGFloat)blue alpha:(CGFloat)alpha
115 #ifdef NS_IMPL_COCOA
116 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
117   if (ns_use_srgb_colorspace)
118       return [NSColor colorWithSRGBRed: red
119                                  green: green
120                                   blue: blue
121                                  alpha: alpha];
122 #endif
123 #endif
124   return [NSColor colorWithCalibratedRed: red
125                                    green: green
126                                     blue: blue
127                                    alpha: alpha];
130 - (NSColor *)colorUsingDefaultColorSpace
132 #ifdef NS_IMPL_COCOA
133 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
134   if (ns_use_srgb_colorspace)
135     return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
136 #endif
137 #endif
138   return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
141 @end
143 /* ==========================================================================
145     Local declarations
147    ========================================================================== */
149 /* Convert a symbol indexed with an NSxxx value to a value as defined
150    in keyboard.c (lispy_function_key). I hope this is a correct way
151    of doing things... */
152 static unsigned convert_ns_to_X_keysym[] =
154   NSHomeFunctionKey,            0x50,
155   NSLeftArrowFunctionKey,       0x51,
156   NSUpArrowFunctionKey,         0x52,
157   NSRightArrowFunctionKey,      0x53,
158   NSDownArrowFunctionKey,       0x54,
159   NSPageUpFunctionKey,          0x55,
160   NSPageDownFunctionKey,        0x56,
161   NSEndFunctionKey,             0x57,
162   NSBeginFunctionKey,           0x58,
163   NSSelectFunctionKey,          0x60,
164   NSPrintFunctionKey,           0x61,
165   NSClearLineFunctionKey,       0x0B,
166   NSExecuteFunctionKey,         0x62,
167   NSInsertFunctionKey,          0x63,
168   NSUndoFunctionKey,            0x65,
169   NSRedoFunctionKey,            0x66,
170   NSMenuFunctionKey,            0x67,
171   NSFindFunctionKey,            0x68,
172   NSHelpFunctionKey,            0x6A,
173   NSBreakFunctionKey,           0x6B,
175   NSF1FunctionKey,              0xBE,
176   NSF2FunctionKey,              0xBF,
177   NSF3FunctionKey,              0xC0,
178   NSF4FunctionKey,              0xC1,
179   NSF5FunctionKey,              0xC2,
180   NSF6FunctionKey,              0xC3,
181   NSF7FunctionKey,              0xC4,
182   NSF8FunctionKey,              0xC5,
183   NSF9FunctionKey,              0xC6,
184   NSF10FunctionKey,             0xC7,
185   NSF11FunctionKey,             0xC8,
186   NSF12FunctionKey,             0xC9,
187   NSF13FunctionKey,             0xCA,
188   NSF14FunctionKey,             0xCB,
189   NSF15FunctionKey,             0xCC,
190   NSF16FunctionKey,             0xCD,
191   NSF17FunctionKey,             0xCE,
192   NSF18FunctionKey,             0xCF,
193   NSF19FunctionKey,             0xD0,
194   NSF20FunctionKey,             0xD1,
195   NSF21FunctionKey,             0xD2,
196   NSF22FunctionKey,             0xD3,
197   NSF23FunctionKey,             0xD4,
198   NSF24FunctionKey,             0xD5,
200   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
201   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
202   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
204   NSTabCharacter,               0x09,
205   0x19,                         0x09,  /* left tab->regular since pass shift */
206   NSCarriageReturnCharacter,    0x0D,
207   NSNewlineCharacter,           0x0D,
208   NSEnterCharacter,             0x8D,
210   0x41|NSNumericPadKeyMask,     0xAE,  /* KP_Decimal */
211   0x43|NSNumericPadKeyMask,     0xAA,  /* KP_Multiply */
212   0x45|NSNumericPadKeyMask,     0xAB,  /* KP_Add */
213   0x4B|NSNumericPadKeyMask,     0xAF,  /* KP_Divide */
214   0x4E|NSNumericPadKeyMask,     0xAD,  /* KP_Subtract */
215   0x51|NSNumericPadKeyMask,     0xBD,  /* KP_Equal */
216   0x52|NSNumericPadKeyMask,     0xB0,  /* KP_0 */
217   0x53|NSNumericPadKeyMask,     0xB1,  /* KP_1 */
218   0x54|NSNumericPadKeyMask,     0xB2,  /* KP_2 */
219   0x55|NSNumericPadKeyMask,     0xB3,  /* KP_3 */
220   0x56|NSNumericPadKeyMask,     0xB4,  /* KP_4 */
221   0x57|NSNumericPadKeyMask,     0xB5,  /* KP_5 */
222   0x58|NSNumericPadKeyMask,     0xB6,  /* KP_6 */
223   0x59|NSNumericPadKeyMask,     0xB7,  /* KP_7 */
224   0x5B|NSNumericPadKeyMask,     0xB8,  /* KP_8 */
225   0x5C|NSNumericPadKeyMask,     0xB9,  /* KP_9 */
227   0x1B,                         0x1B   /* escape */
230 static Lisp_Object Qmodifier_value;
231 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
232 extern Lisp_Object Qcursor_color, Qcursor_type, Qns;
234 static Lisp_Object QUTF8_STRING;
235 static Lisp_Object Qcocoa, Qgnustep;
236 static Lisp_Object Qfile, Qurl;
238 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
239    the maximum font size to NOT antialias.  On GNUstep there is currently
240    no way to control this behavior. */
241 float ns_antialias_threshold;
243 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
244 NSString *ns_app_name = @"Emacs";  /* default changed later */
246 /* Display variables */
247 struct ns_display_info *x_display_list; /* Chain of existing displays */
248 long context_menu_value = 0;
250 /* display update */
251 static struct frame *ns_updating_frame;
252 static NSView *focus_view = NULL;
253 static int ns_window_num = 0;
254 #ifdef NS_IMPL_GNUSTEP
255 static NSRect uRect;
256 #endif
257 static BOOL gsaved = NO;
258 static BOOL ns_fake_keydown = NO;
259 #ifdef NS_IMPL_COCOA
260 static BOOL ns_menu_bar_is_hidden = NO;
261 #endif
262 /*static int debug_lock = 0; */
264 /* event loop */
265 static BOOL send_appdefined = YES;
266 #define NO_APPDEFINED_DATA (-8)
267 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
268 static NSTimer *timed_entry = 0;
269 static NSTimer *scroll_repeat_entry = nil;
270 static fd_set select_readfds, select_writefds;
271 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
272 static int select_nfds = 0, select_valid = 0;
273 static struct timespec select_timeout = { 0, 0 };
274 static int selfds[2] = { -1, -1 };
275 static pthread_mutex_t select_mutex;
276 static int apploopnr = 0;
277 static NSAutoreleasePool *outerpool;
278 static struct input_event *emacs_event = NULL;
279 static struct input_event *q_event_ptr = NULL;
280 static int n_emacs_events_pending = 0;
281 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
282   *ns_pending_service_args;
283 static BOOL ns_do_open_file = NO;
284 static BOOL ns_last_use_native_fullscreen;
286 /* Non-zero means that a HELP_EVENT has been generated since Emacs
287    start.  */
289 static BOOL any_help_event_p = NO;
291 static struct {
292   struct input_event *q;
293   int nr, cap;
294 } hold_event_q = {
295   NULL, 0, 0
298 #ifdef NS_IMPL_COCOA
300  * State for pending menu activation:
301  * MENU_NONE     Normal state
302  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
303  *               run lisp to update the menu.
304  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
305  *               will open.
306  */
307 #define MENU_NONE 0
308 #define MENU_PENDING 1
309 #define MENU_OPENING 2
310 static int menu_will_open_state = MENU_NONE;
312 /* Saved position for menu click.  */
313 static CGPoint menu_mouse_point;
314 #endif
316 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
317 #define NS_FUNCTION_KEY_MASK 0x800000
318 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
319 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
320 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
321 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
322 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
323 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
324 #define EV_MODIFIERS2(flags)                          \
325     (((flags & NSHelpKeyMask) ?           \
326            hyper_modifier : 0)                        \
327      | (!EQ (ns_right_alternate_modifier, Qleft) && \
328         ((flags & NSRightAlternateKeyMask) \
329          == NSRightAlternateKeyMask) ? \
330            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
331      | ((flags & NSAlternateKeyMask) ?                 \
332            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
333      | ((flags & NSShiftKeyMask) ?     \
334            shift_modifier : 0)                        \
335      | (!EQ (ns_right_control_modifier, Qleft) && \
336         ((flags & NSRightControlKeyMask) \
337          == NSRightControlKeyMask) ? \
338            parse_solitary_modifier (ns_right_control_modifier) : 0) \
339      | ((flags & NSControlKeyMask) ?      \
340            parse_solitary_modifier (ns_control_modifier) : 0)     \
341      | ((flags & NS_FUNCTION_KEY_MASK) ?  \
342            parse_solitary_modifier (ns_function_modifier) : 0)    \
343      | (!EQ (ns_right_command_modifier, Qleft) && \
344         ((flags & NSRightCommandKeyMask) \
345          == NSRightCommandKeyMask) ? \
346            parse_solitary_modifier (ns_right_command_modifier) : 0) \
347      | ((flags & NSCommandKeyMask) ?      \
348            parse_solitary_modifier (ns_command_modifier):0))
349 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
351 #define EV_UDMODIFIERS(e)                                      \
352     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
353      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
354      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
355      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
356      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
357      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
358      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
359      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
360      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
362 #define EV_BUTTON(e)                                                         \
363     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
364       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
365      [e buttonNumber] - 1)
367 /* Convert the time field to a timestamp in milliseconds. */
368 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
370 /* This is a piece of code which is common to all the event handling
371    methods.  Maybe it should even be a function.  */
372 #define EV_TRAILER(e)                                                   \
373   {                                                                     \
374     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
375     EV_TRAILER2 (e);                                                    \
376   }
378 #define EV_TRAILER2(e)                                                  \
379   {                                                                     \
380       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
381       if (q_event_ptr)                                                  \
382         {                                                               \
383           n_emacs_events_pending++;                                     \
384           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
385         }                                                               \
386       else                                                              \
387         hold_event (emacs_event);                                       \
388       EVENT_INIT (*emacs_event);                                        \
389       ns_send_appdefined (-1);                                          \
390     }
392 /* TODO: get rid of need for these forward declarations */
393 static void ns_condemn_scroll_bars (struct frame *f);
394 static void ns_judge_scroll_bars (struct frame *f);
395 void x_set_frame_alpha (struct frame *f);
398 /* ==========================================================================
400     Utilities
402    ========================================================================== */
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 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
710   block_input ();
712   NSTRACE (ns_update_auto_hide_menu_bar);
714   if (NSApp != nil && [NSApp isActive])
715     {
716       // Note, "setPresentationOptions" triggers an error unless the
717       // application is active.
718       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
720       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
721         {
722           NSApplicationPresentationOptions options
723             = NSApplicationPresentationDefault;
725           if (menu_bar_should_be_hidden)
726             options |= NSApplicationPresentationAutoHideMenuBar
727               | NSApplicationPresentationAutoHideDock;
729           [NSApp setPresentationOptions: options];
731           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
733           if (!ns_menu_bar_is_hidden)
734             {
735               ns_constrain_all_frames ();
736             }
737         }
738     }
740   unblock_input ();
741 #endif
742 #endif
746 static void
747 ns_update_begin (struct frame *f)
748 /* --------------------------------------------------------------------------
749    Prepare for a grouped sequence of drawing calls
750    external (RIF) call; whole frame, called before update_window_begin
751    -------------------------------------------------------------------------- */
753   EmacsView *view = FRAME_NS_VIEW (f);
754   NSTRACE (ns_update_begin);
756   ns_update_auto_hide_menu_bar ();
758 #ifdef NS_IMPL_COCOA
759   if ([view isFullscreen] && [view fsIsNative])
760   {
761     // Fix reappearing tool bar in fullscreen for OSX 10.7
762     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
763     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
764     if (! tbar_visible != ! [toolbar isVisible])
765       [toolbar setVisible: tbar_visible];
766   }
767 #endif
769   ns_updating_frame = f;
770   [view lockFocus];
772   /* drawRect may have been called for say the minibuffer, and then clip path
773      is for the minibuffer.  But the display engine may draw more because
774      we have set the frame as garbaged.  So reset clip path to the whole
775      view.  */
776 #ifdef NS_IMPL_COCOA
777   {
778     NSBezierPath *bp;
779     NSRect r = [view frame];
780     NSRect cr = [[view window] frame];
781     /* If a large frame size is set, r may be larger than the window frame
782        before constrained.  In that case don't change the clip path, as we
783        will clear in to the tool bar and title bar.  */
784     if (r.size.height
785         + FRAME_NS_TITLEBAR_HEIGHT (f)
786         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
787       {
788         bp = [[NSBezierPath bezierPathWithRect: r] retain];
789         [bp setClip];
790         [bp release];
791       }
792   }
793 #endif
795 #ifdef NS_IMPL_GNUSTEP
796   uRect = NSMakeRect (0, 0, 0, 0);
797 #endif
801 static void
802 ns_update_window_begin (struct window *w)
803 /* --------------------------------------------------------------------------
804    Prepare for a grouped sequence of drawing calls
805    external (RIF) call; for one window, called after update_begin
806    -------------------------------------------------------------------------- */
808   struct frame *f = XFRAME (WINDOW_FRAME (w));
809   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
811   NSTRACE (ns_update_window_begin);
812   w->output_cursor = w->cursor;
814   block_input ();
816   if (f == hlinfo->mouse_face_mouse_frame)
817     {
818       /* Don't do highlighting for mouse motion during the update.  */
819       hlinfo->mouse_face_defer = 1;
821         /* If the frame needs to be redrawn,
822            simply forget about any prior mouse highlighting.  */
823       if (FRAME_GARBAGED_P (f))
824         hlinfo->mouse_face_window = Qnil;
826       /* (further code for mouse faces ifdef'd out in other terms elided) */
827     }
829   unblock_input ();
833 static void
834 ns_update_window_end (struct window *w, bool cursor_on_p,
835                       bool mouse_face_overwritten_p)
836 /* --------------------------------------------------------------------------
837    Finished a grouped sequence of drawing calls
838    external (RIF) call; for one window called before update_end
839    -------------------------------------------------------------------------- */
841   /* note: this fn is nearly identical in all terms */
842   if (!w->pseudo_window_p)
843     {
844       block_input ();
846       if (cursor_on_p)
847         display_and_set_cursor (w, 1,
848                                 w->output_cursor.hpos, w->output_cursor.vpos,
849                                 w->output_cursor.x, w->output_cursor.y);
851       if (draw_window_fringes (w, 1))
852         {
853           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
854             x_draw_right_divider (w);
855           else
856             x_draw_vertical_border (w);
857         }
859       unblock_input ();
860     }
862   /* If a row with mouse-face was overwritten, arrange for
863      frame_up_to_date to redisplay the mouse highlight.  */
864   if (mouse_face_overwritten_p)
865     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
867   NSTRACE (update_window_end);
871 static void
872 ns_update_end (struct frame *f)
873 /* --------------------------------------------------------------------------
874    Finished a grouped sequence of drawing calls
875    external (RIF) call; for whole frame, called after update_window_end
876    -------------------------------------------------------------------------- */
878   EmacsView *view = FRAME_NS_VIEW (f);
880 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
881   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
883   block_input ();
885   [view unlockFocus];
886   [[view window] flushWindow];
888   unblock_input ();
889   ns_updating_frame = NULL;
890   NSTRACE (ns_update_end);
893 static void
894 ns_focus (struct frame *f, NSRect *r, int n)
895 /* --------------------------------------------------------------------------
896    Internal: Focus on given frame.  During small local updates this is used to
897      draw, however during large updates, ns_update_begin and ns_update_end are
898      called to wrap the whole thing, in which case these calls are stubbed out.
899      Except, on GNUstep, we accumulate the rectangle being drawn into, because
900      the back end won't do this automatically, and will just end up flushing
901      the entire window.
902    -------------------------------------------------------------------------- */
904 //  NSTRACE (ns_focus);
905 /* static int c =0;
906    fprintf (stderr, "focus: %d", c++);
907    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
908    fprintf (stderr, "\n"); */
910   if (f != ns_updating_frame)
911     {
912       NSView *view = FRAME_NS_VIEW (f);
913       if (view != focus_view)
914         {
915           if (focus_view != NULL)
916             {
917               [focus_view unlockFocus];
918               [[focus_view window] flushWindow];
919 /*debug_lock--; */
920             }
922           if (view)
923             [view lockFocus];
924           focus_view = view;
925 /*if (view) debug_lock++; */
926         }
927     }
929   /* clipping */
930   if (r)
931     {
932       [[NSGraphicsContext currentContext] saveGraphicsState];
933       if (n == 2)
934         NSRectClipList (r, 2);
935       else
936         NSRectClip (*r);
937       gsaved = YES;
938     }
942 static void
943 ns_unfocus (struct frame *f)
944 /* --------------------------------------------------------------------------
945      Internal: Remove focus on given frame
946    -------------------------------------------------------------------------- */
948 //  NSTRACE (ns_unfocus);
950   if (gsaved)
951     {
952       [[NSGraphicsContext currentContext] restoreGraphicsState];
953       gsaved = NO;
954     }
956   if (f != ns_updating_frame)
957     {
958       if (focus_view != NULL)
959         {
960           [focus_view unlockFocus];
961           [[focus_view window] flushWindow];
962           focus_view = NULL;
963 /*debug_lock--; */
964         }
965     }
969 static void
970 ns_clip_to_row (struct window *w, struct glyph_row *row,
971                 enum glyph_row_area area, BOOL gc)
972 /* --------------------------------------------------------------------------
973      Internal (but parallels other terms): Focus drawing on given row
974    -------------------------------------------------------------------------- */
976   struct frame *f = XFRAME (WINDOW_FRAME (w));
977   NSRect clip_rect;
978   int window_x, window_y, window_width;
980   window_box (w, area, &window_x, &window_y, &window_width, 0);
982   clip_rect.origin.x = window_x;
983   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
984   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
985   clip_rect.size.width = window_width;
986   clip_rect.size.height = row->visible_height;
988   ns_focus (f, &clip_rect, 1);
992 static void
993 ns_ring_bell (struct frame *f)
994 /* --------------------------------------------------------------------------
995      "Beep" routine
996    -------------------------------------------------------------------------- */
998   NSTRACE (ns_ring_bell);
999   if (visible_bell)
1000     {
1001       NSAutoreleasePool *pool;
1002       struct frame *frame = SELECTED_FRAME ();
1003       NSView *view;
1005       block_input ();
1006       pool = [[NSAutoreleasePool alloc] init];
1008       view = FRAME_NS_VIEW (frame);
1009       if (view != nil)
1010         {
1011           NSRect r, surr;
1012           NSPoint dim = NSMakePoint (128, 128);
1014           r = [view bounds];
1015           r.origin.x += (r.size.width - dim.x) / 2;
1016           r.origin.y += (r.size.height - dim.y) / 2;
1017           r.size.width = dim.x;
1018           r.size.height = dim.y;
1019           surr = NSInsetRect (r, -2, -2);
1020           ns_focus (frame, &surr, 1);
1021           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
1022           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
1023                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
1024           NSRectFill (r);
1025           [[view window] flushWindow];
1026           ns_timeout (150000);
1027           [[view window] restoreCachedImage];
1028           [[view window] flushWindow];
1029           ns_unfocus (frame);
1030         }
1031       [pool release];
1032       unblock_input ();
1033     }
1034   else
1035     {
1036       NSBeep ();
1037     }
1040 /* ==========================================================================
1042     Frame / window manager related functions
1044    ========================================================================== */
1047 static void
1048 ns_raise_frame (struct frame *f)
1049 /* --------------------------------------------------------------------------
1050      Bring window to foreground and make it active
1051    -------------------------------------------------------------------------- */
1053   NSView *view;
1054   check_window_system (f);
1055   view = FRAME_NS_VIEW (f);
1056   block_input ();
1057   if (FRAME_VISIBLE_P (f))
1058     [[view window] makeKeyAndOrderFront: NSApp];
1059   unblock_input ();
1063 static void
1064 ns_lower_frame (struct frame *f)
1065 /* --------------------------------------------------------------------------
1066      Send window to back
1067    -------------------------------------------------------------------------- */
1069   NSView *view;
1070   check_window_system (f);
1071   view = FRAME_NS_VIEW (f);
1072   block_input ();
1073   [[view window] orderBack: NSApp];
1074   unblock_input ();
1078 static void
1079 ns_frame_raise_lower (struct frame *f, int raise)
1080 /* --------------------------------------------------------------------------
1081      External (hook)
1082    -------------------------------------------------------------------------- */
1084   NSTRACE (ns_frame_raise_lower);
1086   if (raise)
1087     ns_raise_frame (f);
1088   else
1089     ns_lower_frame (f);
1093 static void
1094 ns_frame_rehighlight (struct frame *frame)
1095 /* --------------------------------------------------------------------------
1096      External (hook): called on things like window switching within frame
1097    -------------------------------------------------------------------------- */
1099   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1100   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1102   NSTRACE (ns_frame_rehighlight);
1103   if (dpyinfo->x_focus_frame)
1104     {
1105       dpyinfo->x_highlight_frame
1106         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1107            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1108            : dpyinfo->x_focus_frame);
1109       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1110         {
1111           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1112           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1113         }
1114     }
1115   else
1116       dpyinfo->x_highlight_frame = 0;
1118   if (dpyinfo->x_highlight_frame &&
1119          dpyinfo->x_highlight_frame != old_highlight)
1120     {
1121       if (old_highlight)
1122         {
1123           x_update_cursor (old_highlight, 1);
1124           x_set_frame_alpha (old_highlight);
1125         }
1126       if (dpyinfo->x_highlight_frame)
1127         {
1128           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1129           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1130         }
1131     }
1135 void
1136 x_make_frame_visible (struct frame *f)
1137 /* --------------------------------------------------------------------------
1138      External: Show the window (X11 semantics)
1139    -------------------------------------------------------------------------- */
1141   NSTRACE (x_make_frame_visible);
1142   /* XXX: at some points in past this was not needed, as the only place that
1143      called this (frame.c:Fraise_frame ()) also called raise_lower;
1144      if this ends up the case again, comment this out again. */
1145   if (!FRAME_VISIBLE_P (f))
1146     {
1147       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1149       SET_FRAME_VISIBLE (f, 1);
1150       ns_raise_frame (f);
1152       /* Making a new frame from a fullscreen frame will make the new frame
1153          fullscreen also.  So skip handleFS as this will print an error.  */
1154       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1155           && [view isFullscreen])
1156         return;
1158       if (f->want_fullscreen != FULLSCREEN_NONE)
1159         {
1160           block_input ();
1161           [view handleFS];
1162           unblock_input ();
1163         }
1164     }
1168 void
1169 x_make_frame_invisible (struct frame *f)
1170 /* --------------------------------------------------------------------------
1171      External: Hide the window (X11 semantics)
1172    -------------------------------------------------------------------------- */
1174   NSView *view;
1175   NSTRACE (x_make_frame_invisible);
1176   check_window_system (f);
1177   view = FRAME_NS_VIEW (f);
1178   [[view window] orderOut: NSApp];
1179   SET_FRAME_VISIBLE (f, 0);
1180   SET_FRAME_ICONIFIED (f, 0);
1184 void
1185 x_iconify_frame (struct frame *f)
1186 /* --------------------------------------------------------------------------
1187      External: Iconify window
1188    -------------------------------------------------------------------------- */
1190   NSView *view;
1191   struct ns_display_info *dpyinfo;
1193   NSTRACE (x_iconify_frame);
1194   check_window_system (f);
1195   view = FRAME_NS_VIEW (f);
1196   dpyinfo = FRAME_DISPLAY_INFO (f);
1198   if (dpyinfo->x_highlight_frame == f)
1199     dpyinfo->x_highlight_frame = 0;
1201   if ([[view window] windowNumber] <= 0)
1202     {
1203       /* the window is still deferred.  Make it very small, bring it
1204          on screen and order it out. */
1205       NSRect s = { { 100, 100}, {0, 0} };
1206       NSRect t;
1207       t = [[view window] frame];
1208       [[view window] setFrame: s display: NO];
1209       [[view window] orderBack: NSApp];
1210       [[view window] orderOut: NSApp];
1211       [[view window] setFrame: t display: NO];
1212     }
1213   [[view window] miniaturize: NSApp];
1216 /* Free X resources of frame F.  */
1218 void
1219 x_free_frame_resources (struct frame *f)
1221   NSView *view;
1222   struct ns_display_info *dpyinfo;
1223   Mouse_HLInfo *hlinfo;
1225   NSTRACE (x_free_frame_resources);
1226   check_window_system (f);
1227   view = FRAME_NS_VIEW (f);
1228   dpyinfo = FRAME_DISPLAY_INFO (f);
1229   hlinfo = MOUSE_HL_INFO (f);
1231   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1233   block_input ();
1235   free_frame_menubar (f);
1236   free_frame_faces (f);
1238   if (f == dpyinfo->x_focus_frame)
1239     dpyinfo->x_focus_frame = 0;
1240   if (f == dpyinfo->x_highlight_frame)
1241     dpyinfo->x_highlight_frame = 0;
1242   if (f == hlinfo->mouse_face_mouse_frame)
1243     reset_mouse_highlight (hlinfo);
1245   if (f->output_data.ns->miniimage != nil)
1246     [f->output_data.ns->miniimage release];
1248   [[view window] close];
1249   [view release];
1251   xfree (f->output_data.ns);
1253   unblock_input ();
1256 void
1257 x_destroy_window (struct frame *f)
1258 /* --------------------------------------------------------------------------
1259      External: Delete the window
1260    -------------------------------------------------------------------------- */
1262   NSTRACE (x_destroy_window);
1263   check_window_system (f);
1264   x_free_frame_resources (f);
1265   ns_window_num--;
1269 void
1270 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1271 /* --------------------------------------------------------------------------
1272      External: Position the window
1273    -------------------------------------------------------------------------- */
1275   NSView *view = FRAME_NS_VIEW (f);
1276   NSArray *screens = [NSScreen screens];
1277   NSScreen *fscreen = [screens objectAtIndex: 0];
1278   NSScreen *screen = [[view window] screen];
1280   NSTRACE (x_set_offset);
1282   block_input ();
1284   f->left_pos = xoff;
1285   f->top_pos = yoff;
1287   if (view != nil && screen && fscreen)
1288     {
1289       f->left_pos = f->size_hint_flags & XNegative
1290         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1291         : f->left_pos;
1292       /* We use visibleFrame here to take menu bar into account.
1293          Ideally we should also adjust left/top with visibleFrame.origin.  */
1295       f->top_pos = f->size_hint_flags & YNegative
1296         ? ([screen visibleFrame].size.height + f->top_pos
1297            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1298            - FRAME_TOOLBAR_HEIGHT (f))
1299         : f->top_pos;
1300 #ifdef NS_IMPL_GNUSTEP
1301       if (f->left_pos < 100)
1302         f->left_pos = 100;  /* don't overlap menu */
1303 #endif
1304       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1305          menu bar.  */
1306       [[view window] setFrameTopLeftPoint:
1307                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1308                                     SCREENMAXBOUND ([fscreen frame].size.height
1309                                                     - NS_TOP_POS (f)))];
1310       f->size_hint_flags &= ~(XNegative|YNegative);
1311     }
1313   unblock_input ();
1317 void
1318 x_set_window_size (struct frame *f,
1319                    int change_grav,
1320                    int width,
1321                    int height,
1322                    bool pixelwise)
1323 /* --------------------------------------------------------------------------
1324      Adjust window pixel size based on given character grid size
1325      Impl is a bit more complex than other terms, need to do some
1326      internal clipping.
1327    -------------------------------------------------------------------------- */
1329   EmacsView *view = FRAME_NS_VIEW (f);
1330   NSWindow *window = [view window];
1331   NSRect wr = [window frame];
1332   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1333   int pixelwidth, pixelheight;
1334   int rows, cols;
1336   NSTRACE (x_set_window_size);
1338   if (view == nil)
1339     return;
1341 /*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));*/
1343   block_input ();
1345   if (pixelwise)
1346     {
1347       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1348       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1349       cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
1350       rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
1351     }
1352   else
1353     {
1354       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1355       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1356       cols = width;
1357       rows = height;
1358     }
1360   /* If we have a toolbar, take its height into account. */
1361   if (tb && ! [view isFullscreen])
1362     {
1363     /* NOTE: previously this would generate wrong result if toolbar not
1364              yet displayed and fixing toolbar_height=32 helped, but
1365              now (200903) seems no longer needed */
1366     FRAME_TOOLBAR_HEIGHT (f) =
1367       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1368         - FRAME_NS_TITLEBAR_HEIGHT (f);
1369 #ifdef NS_IMPL_GNUSTEP
1370       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1371 #endif
1372     }
1373   else
1374     FRAME_TOOLBAR_HEIGHT (f) = 0;
1376   wr.size.width = pixelwidth + f->border_width;
1377   wr.size.height = pixelheight;
1378   if (! [view isFullscreen])
1379     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1380       + FRAME_TOOLBAR_HEIGHT (f);
1382   /* Do not try to constrain to this screen.  We may have multiple
1383      screens, and want Emacs to span those.  Constraining to screen
1384      prevents that, and that is not nice to the user.  */
1385  if (f->output_data.ns->zooming)
1386    f->output_data.ns->zooming = 0;
1387  else
1388    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1390   [view setRows: rows andColumns: cols];
1391   [window setFrame: wr display: YES];
1393   /* This is a trick to compensate for Emacs' managing the scrollbar area
1394      as a fixed number of standard character columns.  Instead of leaving
1395      blank space for the extra, we chopped it off above.  Now for
1396      left-hand scrollbars, we shift all rendering to the left by the
1397      difference between the real width and Emacs' imagined one.  For
1398      right-hand bars, don't worry about it since the extra is never used.
1399      (Obviously doesn't work for vertically split windows tho..) */
1400   {
1401     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1402       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1403                      - NS_SCROLL_BAR_WIDTH (f), 0)
1404       : NSMakePoint (0, 0);
1405     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1406     [view setBoundsOrigin: origin];
1407   }
1409   change_frame_size (f, width, height, 0, 1, 0, pixelwise);
1410 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1412   mark_window_cursors_off (XWINDOW (f->root_window));
1413   cancel_mouse_face (f);
1415   unblock_input ();
1417   do_pending_window_change (0);
1421 static void
1422 ns_fullscreen_hook (struct frame *f)
1424   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1426   if (!FRAME_VISIBLE_P (f))
1427     return;
1429    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1430     {
1431       /* Old style fs don't initiate correctly if created from
1432          init/default-frame alist, so use a timer (not nice...).
1433       */
1434       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1435                                      selector: @selector (handleFS)
1436                                      userInfo: nil repeats: NO];
1437       return;
1438     }
1440   block_input ();
1441   [view handleFS];
1442   unblock_input ();
1445 /* ==========================================================================
1447     Color management
1449    ========================================================================== */
1452 NSColor *
1453 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1455   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1456   if (idx < 1 || idx >= color_table->avail)
1457     return nil;
1458   return color_table->colors[idx];
1462 unsigned long
1463 ns_index_color (NSColor *color, struct frame *f)
1465   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1466   ptrdiff_t idx;
1467   ptrdiff_t i;
1469   if (!color_table->colors)
1470     {
1471       color_table->size = NS_COLOR_CAPACITY;
1472       color_table->avail = 1; /* skip idx=0 as marker */
1473       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1474       color_table->colors[0] = nil;
1475       color_table->empty_indices = [[NSMutableSet alloc] init];
1476     }
1478   /* Do we already have this color?  */
1479   for (i = 1; i < color_table->avail; i++)
1480     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1481       return i;
1483   if ([color_table->empty_indices count] > 0)
1484     {
1485       NSNumber *index = [color_table->empty_indices anyObject];
1486       [color_table->empty_indices removeObject: index];
1487       idx = [index unsignedLongValue];
1488     }
1489   else
1490     {
1491       if (color_table->avail == color_table->size)
1492         color_table->colors =
1493           xpalloc (color_table->colors, &color_table->size, 1,
1494                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1495       idx = color_table->avail++;
1496     }
1498   color_table->colors[idx] = color;
1499   [color retain];
1500 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1501   return idx;
1505 void
1506 ns_free_indexed_color (unsigned long idx, struct frame *f)
1508   struct ns_color_table *color_table;
1509   NSColor *color;
1510   NSNumber *index;
1512   if (!f)
1513     return;
1515   color_table = FRAME_DISPLAY_INFO (f)->color_table;
1517   if (idx <= 0 || idx >= color_table->size) {
1518     message1 ("ns_free_indexed_color: Color index out of range.\n");
1519     return;
1520   }
1522   index = [NSNumber numberWithUnsignedInt: idx];
1523   if ([color_table->empty_indices containsObject: index]) {
1524     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1525     return;
1526   }
1528   color = color_table->colors[idx];
1529   [color release];
1530   color_table->colors[idx] = nil;
1531   [color_table->empty_indices addObject: index];
1532 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1536 static int
1537 ns_get_color (const char *name, NSColor **col)
1538 /* --------------------------------------------------------------------------
1539      Parse a color name
1540    -------------------------------------------------------------------------- */
1541 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1542    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1543    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1545   NSColor *new = nil;
1546   static char hex[20];
1547   int scaling;
1548   float r = -1.0, g, b;
1549   NSString *nsname = [NSString stringWithUTF8String: name];
1551 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1552   block_input ();
1554   if ([nsname isEqualToString: @"ns_selection_bg_color"])
1555     {
1556 #ifdef NS_IMPL_COCOA
1557       NSString *defname = [[NSUserDefaults standardUserDefaults]
1558                             stringForKey: @"AppleHighlightColor"];
1559       if (defname != nil)
1560         nsname = defname;
1561       else
1562 #endif
1563       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1564         {
1565           *col = [new colorUsingDefaultColorSpace];
1566           unblock_input ();
1567           return 0;
1568         }
1569       else
1570         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1572       name = [nsname UTF8String];
1573     }
1574   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1575     {
1576       /* NOTE: OSX applications normally don't set foreground selection, but
1577          text may be unreadable if we don't.
1578       */
1579       if ((new = [NSColor selectedTextColor]) != nil)
1580         {
1581           *col = [new colorUsingDefaultColorSpace];
1582           unblock_input ();
1583           return 0;
1584         }
1586       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1587       name = [nsname UTF8String];
1588     }
1590   /* First, check for some sort of numeric specification. */
1591   hex[0] = '\0';
1593   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1594     {
1595       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1596       [scanner scanFloat: &r];
1597       [scanner scanFloat: &g];
1598       [scanner scanFloat: &b];
1599     }
1600   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1601     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1602   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1603     {
1604       int len = (strlen(name) - 1);
1605       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1606       int i;
1607       scaling = strlen(name+start) / 3;
1608       for (i = 0; i < 3; i++)
1609         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1610                  name + start + i * scaling);
1611       hex[3 * (scaling + 1) - 1] = '\0';
1612     }
1614   if (hex[0])
1615     {
1616       int rr, gg, bb;
1617       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1618       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1619         {
1620           r = rr / fscale;
1621           g = gg / fscale;
1622           b = bb / fscale;
1623         }
1624     }
1626   if (r >= 0.0F)
1627     {
1628       *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
1629       unblock_input ();
1630       return 0;
1631     }
1633   /* Otherwise, color is expected to be from a list */
1634   {
1635     NSEnumerator *lenum, *cenum;
1636     NSString *name;
1637     NSColorList *clist;
1639 #ifdef NS_IMPL_GNUSTEP
1640     /* XXX: who is wrong, the requestor or the implementation? */
1641     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1642         == NSOrderedSame)
1643       nsname = @"highlightColor";
1644 #endif
1646     lenum = [[NSColorList availableColorLists] objectEnumerator];
1647     while ( (clist = [lenum nextObject]) && new == nil)
1648       {
1649         cenum = [[clist allKeys] objectEnumerator];
1650         while ( (name = [cenum nextObject]) && new == nil )
1651           {
1652             if ([name compare: nsname
1653                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1654               new = [clist colorWithKey: name];
1655           }
1656       }
1657   }
1659   if (new)
1660     *col = [new colorUsingDefaultColorSpace];
1661   unblock_input ();
1662   return new ? 0 : 1;
1667 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1668 /* --------------------------------------------------------------------------
1669      Convert a Lisp string object to a NS color
1670    -------------------------------------------------------------------------- */
1672   NSTRACE (ns_lisp_to_color);
1673   if (STRINGP (color))
1674     return ns_get_color (SSDATA (color), col);
1675   else if (SYMBOLP (color))
1676     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1677   return 1;
1681 Lisp_Object
1682 ns_color_to_lisp (NSColor *col)
1683 /* --------------------------------------------------------------------------
1684      Convert a color to a lisp string with the RGB equivalent
1685    -------------------------------------------------------------------------- */
1687   EmacsCGFloat red, green, blue, alpha, gray;
1688   char buf[1024];
1689   const char *str;
1690   NSTRACE (ns_color_to_lisp);
1692   block_input ();
1693   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1695       if ((str =[[col colorNameComponent] UTF8String]))
1696         {
1697           unblock_input ();
1698           return build_string ((char *)str);
1699         }
1701     [[col colorUsingDefaultColorSpace]
1702         getRed: &red green: &green blue: &blue alpha: &alpha];
1703   if (red == green && red == blue)
1704     {
1705       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1706             getWhite: &gray alpha: &alpha];
1707       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1708                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1709       unblock_input ();
1710       return build_string (buf);
1711     }
1713   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1714             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1716   unblock_input ();
1717   return build_string (buf);
1721 void
1722 ns_query_color(void *col, XColor *color_def, int setPixel)
1723 /* --------------------------------------------------------------------------
1724          Get ARGB values out of NSColor col and put them into color_def.
1725          If setPixel, set the pixel to a concatenated version.
1726          and set color_def pixel to the resulting index.
1727    -------------------------------------------------------------------------- */
1729   EmacsCGFloat r, g, b, a;
1731   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1732   color_def->red   = r * 65535;
1733   color_def->green = g * 65535;
1734   color_def->blue  = b * 65535;
1736   if (setPixel == YES)
1737     color_def->pixel
1738       = ARGB_TO_ULONG((int)(a*255),
1739                       (int)(r*255), (int)(g*255), (int)(b*255));
1743 bool
1744 ns_defined_color (struct frame *f,
1745                   const char *name,
1746                   XColor *color_def,
1747                   bool alloc,
1748                   bool makeIndex)
1749 /* --------------------------------------------------------------------------
1750          Return true if named color found, and set color_def rgb accordingly.
1751          If makeIndex and alloc are nonzero put the color in the color_table,
1752          and set color_def pixel to the resulting index.
1753          If makeIndex is zero, set color_def pixel to ARGB.
1754          Return false if not found
1755    -------------------------------------------------------------------------- */
1757   NSColor *col;
1758   NSTRACE (ns_defined_color);
1760   block_input ();
1761   if (ns_get_color (name, &col) != 0) /* Color not found  */
1762     {
1763       unblock_input ();
1764       return 0;
1765     }
1766   if (makeIndex && alloc)
1767     color_def->pixel = ns_index_color (col, f);
1768   ns_query_color (col, color_def, !makeIndex);
1769   unblock_input ();
1770   return 1;
1774 void
1775 x_set_frame_alpha (struct frame *f)
1776 /* --------------------------------------------------------------------------
1777      change the entire-frame transparency
1778    -------------------------------------------------------------------------- */
1780   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1781   double alpha = 1.0;
1782   double alpha_min = 1.0;
1784   if (dpyinfo->x_highlight_frame == f)
1785     alpha = f->alpha[0];
1786   else
1787     alpha = f->alpha[1];
1789   if (FLOATP (Vframe_alpha_lower_limit))
1790     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1791   else if (INTEGERP (Vframe_alpha_lower_limit))
1792     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1794   if (alpha < 0.0)
1795     return;
1796   else if (1.0 < alpha)
1797     alpha = 1.0;
1798   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1799     alpha = alpha_min;
1801 #ifdef NS_IMPL_COCOA
1802   {
1803     EmacsView *view = FRAME_NS_VIEW (f);
1804   [[view window] setAlphaValue: alpha];
1805   }
1806 #endif
1810 /* ==========================================================================
1812     Mouse handling
1814    ========================================================================== */
1817 void
1818 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1819 /* --------------------------------------------------------------------------
1820      Programmatically reposition mouse pointer in pixel coordinates
1821    -------------------------------------------------------------------------- */
1823   NSTRACE (frame_set_mouse_pixel_position);
1824   ns_raise_frame (f);
1825 #if 0
1826   /* FIXME: this does not work, and what about GNUstep? */
1827 #ifdef NS_IMPL_COCOA
1828   [FRAME_NS_VIEW (f) lockFocus];
1829   PSsetmouse ((float)pix_x, (float)pix_y);
1830   [FRAME_NS_VIEW (f) unlockFocus];
1831 #endif
1832 #endif
1835 static int
1836 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1837 /*   ------------------------------------------------------------------------
1838      Called by EmacsView on mouseMovement events.  Passes on
1839      to emacs mainstream code if we moved off of a rect of interest
1840      known as last_mouse_glyph.
1841      ------------------------------------------------------------------------ */
1843   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1844   NSRect *r;
1846 //  NSTRACE (note_mouse_movement);
1848   dpyinfo->last_mouse_motion_frame = frame;
1849   r = &dpyinfo->last_mouse_glyph;
1851   /* Note, this doesn't get called for enter/leave, since we don't have a
1852      position.  Those are taken care of in the corresponding NSView methods. */
1854   /* has movement gone beyond last rect we were tracking? */
1855   if (x < r->origin.x || x >= r->origin.x + r->size.width
1856       || y < r->origin.y || y >= r->origin.y + r->size.height)
1857     {
1858       ns_update_begin (frame);
1859       frame->mouse_moved = 1;
1860       note_mouse_highlight (frame, x, y);
1861       remember_mouse_glyph (frame, x, y, r);
1862       ns_update_end (frame);
1863       return 1;
1864     }
1866   return 0;
1870 static void
1871 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1872                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1873                    Time *time)
1874 /* --------------------------------------------------------------------------
1875     External (hook): inform emacs about mouse position and hit parts.
1876     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1877     x & y should be position in the scrollbar (the whole bar, not the handle)
1878     and length of scrollbar respectively
1879    -------------------------------------------------------------------------- */
1881   id view;
1882   NSPoint position;
1883   Lisp_Object frame, tail;
1884   struct frame *f;
1885   struct ns_display_info *dpyinfo;
1887   NSTRACE (ns_mouse_position);
1889   if (*fp == NULL)
1890     {
1891       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1892       return;
1893     }
1895   dpyinfo = FRAME_DISPLAY_INFO (*fp);
1897   block_input ();
1899   if (dpyinfo->last_mouse_scroll_bar != nil && insist == 0)
1900     {
1901       /* TODO: we do not use this path at the moment because drag events will
1902            go directly to the EmacsScroller.  Leaving code in for now. */
1903       [dpyinfo->last_mouse_scroll_bar
1904           getMouseMotionPart: (int *)part window: bar_window x: x y: y];
1905       if (time)
1906         *time = dpyinfo->last_mouse_movement_time;
1907       dpyinfo->last_mouse_scroll_bar = nil;
1908     }
1909   else
1910     {
1911       /* Clear the mouse-moved flag for every frame on this display.  */
1912       FOR_EACH_FRAME (tail, frame)
1913         if (FRAME_NS_P (XFRAME (frame))
1914             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1915           XFRAME (frame)->mouse_moved = 0;
1917       dpyinfo->last_mouse_scroll_bar = nil;
1918       if (dpyinfo->last_mouse_frame
1919           && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
1920         f = dpyinfo->last_mouse_frame;
1921       else
1922         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1923                                     : SELECTED_FRAME ();
1925       if (f && FRAME_NS_P (f))
1926         {
1927           view = FRAME_NS_VIEW (*fp);
1929           position = [[view window] mouseLocationOutsideOfEventStream];
1930           position = [view convertPoint: position fromView: nil];
1931           remember_mouse_glyph (f, position.x, position.y,
1932                                 &dpyinfo->last_mouse_glyph);
1933 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1935           if (bar_window) *bar_window = Qnil;
1936           if (part) *part = 0; /*scroll_bar_handle; */
1938           if (x) XSETINT (*x, lrint (position.x));
1939           if (y) XSETINT (*y, lrint (position.y));
1940           if (time)
1941             *time = dpyinfo->last_mouse_movement_time;
1942           *fp = f;
1943         }
1944     }
1946   unblock_input ();
1950 static void
1951 ns_frame_up_to_date (struct frame *f)
1952 /* --------------------------------------------------------------------------
1953     External (hook): Fix up mouse highlighting right after a full update.
1954     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1955    -------------------------------------------------------------------------- */
1957   NSTRACE (ns_frame_up_to_date);
1959   if (FRAME_NS_P (f))
1960     {
1961       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1962       if (f == hlinfo->mouse_face_mouse_frame)
1963         {
1964           block_input ();
1965           ns_update_begin(f);
1966           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1967                                 hlinfo->mouse_face_mouse_x,
1968                                 hlinfo->mouse_face_mouse_y);
1969           ns_update_end(f);
1970           unblock_input ();
1971         }
1972     }
1976 static void
1977 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1978 /* --------------------------------------------------------------------------
1979     External (RIF): set frame mouse pointer type.
1980    -------------------------------------------------------------------------- */
1982   NSTRACE (ns_define_frame_cursor);
1983   if (FRAME_POINTER_TYPE (f) != cursor)
1984     {
1985       EmacsView *view = FRAME_NS_VIEW (f);
1986       FRAME_POINTER_TYPE (f) = cursor;
1987       [[view window] invalidateCursorRectsForView: view];
1988       /* Redisplay assumes this function also draws the changed frame
1989          cursor, but this function doesn't, so do it explicitly.  */
1990       x_update_cursor (f, 1);
1991     }
1996 /* ==========================================================================
1998     Keyboard handling
2000    ========================================================================== */
2003 static unsigned
2004 ns_convert_key (unsigned code)
2005 /* --------------------------------------------------------------------------
2006     Internal call used by NSView-keyDown.
2007    -------------------------------------------------------------------------- */
2009   const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2010   unsigned keysym;
2011   /* An array would be faster, but less easy to read. */
2012   for (keysym = 0; keysym < last_keysym; keysym += 2)
2013     if (code == convert_ns_to_X_keysym[keysym])
2014       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2015   return 0;
2016 /* if decide to use keyCode and Carbon table, use this line:
2017      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2021 char *
2022 x_get_keysym_name (int keysym)
2023 /* --------------------------------------------------------------------------
2024     Called by keyboard.c.  Not sure if the return val is important, except
2025     that it be unique.
2026    -------------------------------------------------------------------------- */
2028   static char value[16];
2029   NSTRACE (x_get_keysym_name);
2030   sprintf (value, "%d", keysym);
2031   return value;
2036 /* ==========================================================================
2038     Block drawing operations
2040    ========================================================================== */
2043 static void
2044 ns_redraw_scroll_bars (struct frame *f)
2046   int i;
2047   id view;
2048   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2049   NSTRACE (ns_redraw_scroll_bars);
2050   for (i =[subviews count]-1; i >= 0; i--)
2051     {
2052       view = [subviews objectAtIndex: i];
2053       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2054       [view display];
2055     }
2059 void
2060 ns_clear_frame (struct frame *f)
2061 /* --------------------------------------------------------------------------
2062       External (hook): Erase the entire frame
2063    -------------------------------------------------------------------------- */
2065   NSView *view = FRAME_NS_VIEW (f);
2066   NSRect r;
2068   NSTRACE (ns_clear_frame);
2070  /* comes on initial frame because we have
2071     after-make-frame-functions = select-frame */
2072  if (!FRAME_DEFAULT_FACE (f))
2073    return;
2075   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2077   r = [view bounds];
2079   block_input ();
2080   ns_focus (f, &r, 1);
2081   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2082   NSRectFill (r);
2083   ns_unfocus (f);
2085   /* as of 2006/11 or so this is now needed */
2086   ns_redraw_scroll_bars (f);
2087   unblock_input ();
2091 static void
2092 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2093 /* --------------------------------------------------------------------------
2094     External (RIF):  Clear section of frame
2095    -------------------------------------------------------------------------- */
2097   NSRect r = NSMakeRect (x, y, width, height);
2098   NSView *view = FRAME_NS_VIEW (f);
2099   struct face *face = FRAME_DEFAULT_FACE (f);
2101   if (!view || !face)
2102     return;
2104   NSTRACE (ns_clear_frame_area);
2106   r = NSIntersectionRect (r, [view frame]);
2107   ns_focus (f, &r, 1);
2108   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2110   NSRectFill (r);
2112   ns_unfocus (f);
2113   return;
2117 static void
2118 ns_scroll_run (struct window *w, struct run *run)
2119 /* --------------------------------------------------------------------------
2120     External (RIF):  Insert or delete n lines at line vpos
2121    -------------------------------------------------------------------------- */
2123   struct frame *f = XFRAME (w->frame);
2124   int x, y, width, height, from_y, to_y, bottom_y;
2126   NSTRACE (ns_scroll_run);
2128   /* begin copy from other terms */
2129   /* Get frame-relative bounding box of the text display area of W,
2130      without mode lines.  Include in this box the left and right
2131      fringe of W.  */
2132   window_box (w, ANY_AREA, &x, &y, &width, &height);
2134   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2135   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2136   bottom_y = y + height;
2138   if (to_y < from_y)
2139     {
2140       /* Scrolling up.  Make sure we don't copy part of the mode
2141          line at the bottom.  */
2142       if (from_y + run->height > bottom_y)
2143         height = bottom_y - from_y;
2144       else
2145         height = run->height;
2146     }
2147   else
2148     {
2149       /* Scrolling down.  Make sure we don't copy over the mode line.
2150          at the bottom.  */
2151       if (to_y + run->height > bottom_y)
2152         height = bottom_y - to_y;
2153       else
2154         height = run->height;
2155     }
2156   /* end copy from other terms */
2158   if (height == 0)
2159       return;
2161   block_input ();
2163   x_clear_cursor (w);
2165   {
2166     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2167     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2168     NSPoint dstOrigin = NSMakePoint (x, to_y);
2170     ns_focus (f, &dstRect, 1);
2171     NSCopyBits (0, srcRect , dstOrigin);
2172     ns_unfocus (f);
2173   }
2175   unblock_input ();
2179 static void
2180 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2181 /* --------------------------------------------------------------------------
2182     External (RIF): preparatory to fringe update after text was updated
2183    -------------------------------------------------------------------------- */
2185   struct frame *f;
2186   int width, height;
2188   NSTRACE (ns_after_update_window_line);
2190   /* begin copy from other terms */
2191   eassert (w);
2193   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2194     desired_row->redraw_fringe_bitmaps_p = 1;
2196   /* When a window has disappeared, make sure that no rest of
2197      full-width rows stays visible in the internal border.  */
2198   if (windows_or_buffers_changed
2199       && desired_row->full_width_p
2200       && (f = XFRAME (w->frame),
2201           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2202           width != 0)
2203       && (height = desired_row->visible_height,
2204           height > 0))
2205     {
2206       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2208       block_input ();
2209       ns_clear_frame_area (f, 0, y, width, height);
2210       ns_clear_frame_area (f,
2211                            FRAME_PIXEL_WIDTH (f) - width,
2212                            y, width, height);
2213       unblock_input ();
2214     }
2218 static void
2219 ns_shift_glyphs_for_insert (struct frame *f,
2220                            int x, int y, int width, int height,
2221                            int shift_by)
2222 /* --------------------------------------------------------------------------
2223     External (RIF): copy an area horizontally, don't worry about clearing src
2224    -------------------------------------------------------------------------- */
2226   NSRect srcRect = NSMakeRect (x, y, width, height);
2227   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2228   NSPoint dstOrigin = dstRect.origin;
2230   NSTRACE (ns_shift_glyphs_for_insert);
2232   ns_focus (f, &dstRect, 1);
2233   NSCopyBits (0, srcRect, dstOrigin);
2234   ns_unfocus (f);
2239 /* ==========================================================================
2241     Character encoding and metrics
2243    ========================================================================== */
2246 static void
2247 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2248 /* --------------------------------------------------------------------------
2249      External (RIF); compute left/right overhang of whole string and set in s
2250    -------------------------------------------------------------------------- */
2252   struct font *font = s->font;
2254   if (s->char2b)
2255     {
2256       struct font_metrics metrics;
2257       unsigned int codes[2];
2258       codes[0] = *(s->char2b);
2259       codes[1] = *(s->char2b + s->nchars - 1);
2261       font->driver->text_extents (font, codes, 2, &metrics);
2262       s->left_overhang = -metrics.lbearing;
2263       s->right_overhang
2264         = metrics.rbearing > metrics.width
2265         ? metrics.rbearing - metrics.width : 0;
2266     }
2267   else
2268     {
2269       s->left_overhang = 0;
2270       if (EQ (font->driver->type, Qns))
2271         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2272           FONT_HEIGHT (font) * 0.2 : 0;
2273       else
2274         s->right_overhang = 0;
2275     }
2280 /* ==========================================================================
2282     Fringe and cursor drawing
2284    ========================================================================== */
2287 extern int max_used_fringe_bitmap;
2288 static void
2289 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2290                       struct draw_fringe_bitmap_params *p)
2291 /* --------------------------------------------------------------------------
2292     External (RIF); fringe-related
2293    -------------------------------------------------------------------------- */
2295   struct frame *f = XFRAME (WINDOW_FRAME (w));
2296   struct face *face = p->face;
2297   static EmacsImage **bimgs = NULL;
2298   static int nBimgs = 0;
2300   /* grow bimgs if needed */
2301   if (nBimgs < max_used_fringe_bitmap)
2302     {
2303       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2304       memset (bimgs + nBimgs, 0,
2305               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2306       nBimgs = max_used_fringe_bitmap;
2307     }
2309   /* Must clip because of partially visible lines.  */
2310   ns_clip_to_row (w, row, ANY_AREA, YES);
2312   if (!p->overlay_p)
2313     {
2314       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2316       if (bx >= 0 && nx > 0)
2317         {
2318           NSRect r = NSMakeRect (bx, by, nx, ny);
2319           NSRectClip (r);
2320           [ns_lookup_indexed_color (face->background, f) set];
2321           NSRectFill (r);
2322         }
2323     }
2325   if (p->which)
2326     {
2327       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2328       EmacsImage *img = bimgs[p->which - 1];
2330       if (!img)
2331         {
2332           unsigned short *bits = p->bits + p->dh;
2333           int len = p->h;
2334           int i;
2335           unsigned char *cbits = xmalloc (len);
2337           for (i = 0; i < len; i++)
2338             cbits[i] = ~(bits[i] & 0xff);
2339           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2340                                            flip: NO];
2341           bimgs[p->which - 1] = img;
2342           xfree (cbits);
2343         }
2345       NSRectClip (r);
2346       /* Since we composite the bitmap instead of just blitting it, we need
2347          to erase the whole background. */
2348       [ns_lookup_indexed_color(face->background, f) set];
2349       NSRectFill (r);
2350       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2351 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2352       [img drawInRect: r
2353               fromRect: NSZeroRect
2354              operation: NSCompositeSourceOver
2355               fraction: 1.0
2356            respectFlipped: YES
2357                 hints: nil];
2358 #else
2359       {
2360         NSPoint pt = r.origin;
2361         pt.y += p->h;
2362         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2363       }
2364 #endif
2365     }
2366   ns_unfocus (f);
2370 static void
2371 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2372                        int x, int y, enum text_cursor_kinds cursor_type,
2373                        int cursor_width, bool on_p, bool active_p)
2374 /* --------------------------------------------------------------------------
2375      External call (RIF): draw cursor.
2376      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2377    -------------------------------------------------------------------------- */
2379   NSRect r, s;
2380   int fx, fy, h, cursor_height;
2381   struct frame *f = WINDOW_XFRAME (w);
2382   struct glyph *phys_cursor_glyph;
2383   struct glyph *cursor_glyph;
2384   struct face *face;
2385   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2387   /* If cursor is out of bounds, don't draw garbage.  This can happen
2388      in mini-buffer windows when switching between echo area glyphs
2389      and mini-buffer.  */
2391   NSTRACE (dumpcursor);
2393   if (!on_p)
2394     return;
2396   w->phys_cursor_type = cursor_type;
2397   w->phys_cursor_on_p = on_p;
2399   if (cursor_type == NO_CURSOR)
2400     {
2401       w->phys_cursor_width = 0;
2402       return;
2403     }
2405   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2406     {
2407       if (glyph_row->exact_window_width_line_p
2408           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2409         {
2410           glyph_row->cursor_in_fringe_p = 1;
2411           draw_fringe_bitmap (w, glyph_row, 0);
2412         }
2413       return;
2414     }
2416   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2417      (other terminals do it the other way round).  We must set
2418      w->phys_cursor_width to the cursor width.  For bar cursors, that
2419      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2420   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2422   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2423      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2424   if (cursor_type == BAR_CURSOR)
2425     {
2426       if (cursor_width < 1)
2427         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2428       w->phys_cursor_width = cursor_width;
2429     }
2430   /* If we have an HBAR, "cursor_width" MAY specify height. */
2431   else if (cursor_type == HBAR_CURSOR)
2432     {
2433       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2434       fy += h - cursor_height;
2435       h = cursor_height;
2436     }
2438   r.origin.x = fx, r.origin.y = fy;
2439   r.size.height = h;
2440   r.size.width = w->phys_cursor_width;
2442   /* TODO: only needed in rare cases with last-resort font in HELLO..
2443      should we do this more efficiently? */
2444   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2447   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2448   if (face && NS_FACE_BACKGROUND (face)
2449       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2450     {
2451       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2452       hollow_color = FRAME_CURSOR_COLOR (f);
2453     }
2454   else
2455     [FRAME_CURSOR_COLOR (f) set];
2457 #ifdef NS_IMPL_COCOA
2458   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2459            atomic.  Cleaner ways of doing this should be investigated.
2460            One way would be to set a global variable DRAWING_CURSOR
2461            when making the call to draw_phys..(), don't focus in that
2462            case, then move the ns_unfocus() here after that call. */
2463   NSDisableScreenUpdates ();
2464 #endif
2466   switch (cursor_type)
2467     {
2468     case NO_CURSOR:
2469       break;
2470     case FILLED_BOX_CURSOR:
2471       NSRectFill (r);
2472       break;
2473     case HOLLOW_BOX_CURSOR:
2474       NSRectFill (r);
2475       [hollow_color set];
2476       NSRectFill (NSInsetRect (r, 1, 1));
2477       [FRAME_CURSOR_COLOR (f) set];
2478       break;
2479     case HBAR_CURSOR:
2480       NSRectFill (r);
2481       break;
2482     case BAR_CURSOR:
2483       s = r;
2484       /* If the character under cursor is R2L, draw the bar cursor
2485          on the right of its glyph, rather than on the left.  */
2486       cursor_glyph = get_phys_cursor_glyph (w);
2487       if ((cursor_glyph->resolved_level & 1) != 0)
2488         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2490       NSRectFill (s);
2491       break;
2492     }
2493   ns_unfocus (f);
2495   /* draw the character under the cursor */
2496   if (cursor_type != NO_CURSOR)
2497     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2499 #ifdef NS_IMPL_COCOA
2500   NSEnableScreenUpdates ();
2501 #endif
2506 static void
2507 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2508 /* --------------------------------------------------------------------------
2509      External (RIF): Draw a vertical line.
2510    -------------------------------------------------------------------------- */
2512   struct frame *f = XFRAME (WINDOW_FRAME (w));
2513   struct face *face;
2514   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2516   NSTRACE (ns_draw_vertical_window_border);
2518   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2519   if (face)
2520       [ns_lookup_indexed_color(face->foreground, f) set];
2522   ns_focus (f, &r, 1);
2523   NSRectFill(r);
2524   ns_unfocus (f);
2528 static void
2529 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2530 /* --------------------------------------------------------------------------
2531      External (RIF): Draw a window divider.
2532    -------------------------------------------------------------------------- */
2534   struct frame *f = XFRAME (WINDOW_FRAME (w));
2535   struct face *face;
2536   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2538   NSTRACE (ns_draw_window_divider);
2540   face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2541   if (face)
2542       [ns_lookup_indexed_color(face->foreground, f) set];
2544   ns_focus (f, &r, 1);
2545   NSRectFill(r);
2546   ns_unfocus (f);
2549 static void
2550 ns_show_hourglass (struct frame *f)
2552   /* TODO: add NSProgressIndicator to all frames.  */
2555 static void
2556 ns_hide_hourglass (struct frame *f)
2558   /* TODO: remove NSProgressIndicator from all frames.  */
2561 /* ==========================================================================
2563     Glyph drawing operations
2565    ========================================================================== */
2567 static int
2568 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2569 /* --------------------------------------------------------------------------
2570     Wrapper utility to account for internal border width on full-width lines,
2571     and allow top full-width rows to hit the frame top.  nr should be pointer
2572     to two successive NSRects.  Number of rects actually used is returned.
2573    -------------------------------------------------------------------------- */
2575   int n = get_glyph_string_clip_rects (s, nr, 2);
2576   return n;
2579 /* --------------------------------------------------------------------
2580    Draw a wavy line under glyph string s. The wave fills wave_height
2581    pixels from y.
2583                     x          wave_length = 2
2584                                  --
2585                 y    *   *   *   *   *
2586                      |* * * * * * * * *
2587     wave_height = 3  | *   *   *   *
2588   --------------------------------------------------------------------- */
2590 static void
2591 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2593   int wave_height = 3, wave_length = 2;
2594   int y, dx, dy, odd, xmax;
2595   NSPoint a, b;
2596   NSRect waveClip;
2598   dx = wave_length;
2599   dy = wave_height - 1;
2600   y =  s->ybase - wave_height + 3;
2601   xmax = x + width;
2603   /* Find and set clipping rectangle */
2604   waveClip = NSMakeRect (x, y, width, wave_height);
2605   [[NSGraphicsContext currentContext] saveGraphicsState];
2606   NSRectClip (waveClip);
2608   /* Draw the waves */
2609   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2610   b.x = a.x + dx;
2611   odd = (int)(a.x/dx) % 2;
2612   a.y = b.y = y + 0.5;
2614   if (odd)
2615     a.y += dy;
2616   else
2617     b.y += dy;
2619   while (a.x <= xmax)
2620     {
2621       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2622       a.x = b.x, a.y = b.y;
2623       b.x += dx, b.y = y + 0.5 + odd*dy;
2624       odd = !odd;
2625     }
2627   /* Restore previous clipping rectangle(s) */
2628   [[NSGraphicsContext currentContext] restoreGraphicsState];
2633 void
2634 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2635                          NSColor *defaultCol, CGFloat width, CGFloat x)
2636 /* --------------------------------------------------------------------------
2637    Draw underline, overline, and strike-through on glyph string s.
2638    -------------------------------------------------------------------------- */
2640   if (s->for_overlaps)
2641     return;
2643   /* Do underline. */
2644   if (face->underline_p)
2645     {
2646       if (s->face->underline_type == FACE_UNDER_WAVE)
2647         {
2648           if (face->underline_defaulted_p)
2649             [defaultCol set];
2650           else
2651             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2653           ns_draw_underwave (s, width, x);
2654         }
2655       else if (s->face->underline_type == FACE_UNDER_LINE)
2656         {
2658           NSRect r;
2659           unsigned long thickness, position;
2661           /* If the prev was underlined, match its appearance. */
2662           if (s->prev && s->prev->face->underline_p
2663               && s->prev->face->underline_type == FACE_UNDER_LINE
2664               && s->prev->underline_thickness > 0)
2665             {
2666               thickness = s->prev->underline_thickness;
2667               position = s->prev->underline_position;
2668             }
2669           else
2670             {
2671               struct font *font;
2672               unsigned long descent;
2674               font=s->font;
2675               descent = s->y + s->height - s->ybase;
2677               /* Use underline thickness of font, defaulting to 1. */
2678               thickness = (font && font->underline_thickness > 0)
2679                 ? font->underline_thickness : 1;
2681               /* Determine the offset of underlining from the baseline. */
2682               if (x_underline_at_descent_line)
2683                 position = descent - thickness;
2684               else if (x_use_underline_position_properties
2685                        && font && font->underline_position >= 0)
2686                 position = font->underline_position;
2687               else if (font)
2688                 position = lround (font->descent / 2);
2689               else
2690                 position = underline_minimum_offset;
2692               position = max (position, underline_minimum_offset);
2694               /* Ensure underlining is not cropped. */
2695               if (descent <= position)
2696                 {
2697                   position = descent - 1;
2698                   thickness = 1;
2699                 }
2700               else if (descent < position + thickness)
2701                 thickness = 1;
2702             }
2704           s->underline_thickness = thickness;
2705           s->underline_position = position;
2707           r = NSMakeRect (x, s->ybase + position, width, thickness);
2709           if (face->underline_defaulted_p)
2710             [defaultCol set];
2711           else
2712             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2713           NSRectFill (r);
2714         }
2715     }
2716   /* Do overline. We follow other terms in using a thickness of 1
2717      and ignoring overline_margin. */
2718   if (face->overline_p)
2719     {
2720       NSRect r;
2721       r = NSMakeRect (x, s->y, width, 1);
2723       if (face->overline_color_defaulted_p)
2724         [defaultCol set];
2725       else
2726         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2727       NSRectFill (r);
2728     }
2730   /* Do strike-through.  We follow other terms for thickness and
2731      vertical position.*/
2732   if (face->strike_through_p)
2733     {
2734       NSRect r;
2735       unsigned long dy;
2737       dy = lrint ((s->height - 1) / 2);
2738       r = NSMakeRect (x, s->y + dy, width, 1);
2740       if (face->strike_through_color_defaulted_p)
2741         [defaultCol set];
2742       else
2743         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2744       NSRectFill (r);
2745     }
2748 static void
2749 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2750              char left_p, char right_p)
2751 /* --------------------------------------------------------------------------
2752     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2753     Note we can't just use an NSDrawRect command, because of the possibility
2754     of some sides not being drawn, and because the rect will be filled.
2755    -------------------------------------------------------------------------- */
2757   NSRect s = r;
2758   [col set];
2760   /* top, bottom */
2761   s.size.height = thickness;
2762   NSRectFill (s);
2763   s.origin.y += r.size.height - thickness;
2764   NSRectFill (s);
2766   s.size.height = r.size.height;
2767   s.origin.y = r.origin.y;
2769   /* left, right (optional) */
2770   s.size.width = thickness;
2771   if (left_p)
2772     NSRectFill (s);
2773   if (right_p)
2774     {
2775       s.origin.x += r.size.width - thickness;
2776       NSRectFill (s);
2777     }
2781 static void
2782 ns_draw_relief (NSRect r, int thickness, char raised_p,
2783                char top_p, char bottom_p, char left_p, char right_p,
2784                struct glyph_string *s)
2785 /* --------------------------------------------------------------------------
2786     Draw a relief rect inside r, optionally leaving some sides open.
2787     Note we can't just use an NSDrawBezel command, because of the possibility
2788     of some sides not being drawn, and because the rect will be filled.
2789    -------------------------------------------------------------------------- */
2791   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2792   NSColor *newBaseCol = nil;
2793   NSRect sr = r;
2795   NSTRACE (ns_draw_relief);
2797   /* set up colors */
2799   if (s->face->use_box_color_for_shadows_p)
2800     {
2801       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2802     }
2803 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2804            && s->img->pixmap
2805            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2806        {
2807          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2808        } */
2809   else
2810     {
2811       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2812     }
2814   if (newBaseCol == nil)
2815     newBaseCol = [NSColor grayColor];
2817   if (newBaseCol != baseCol)  /* TODO: better check */
2818     {
2819       [baseCol release];
2820       baseCol = [newBaseCol retain];
2821       [lightCol release];
2822       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2823       [darkCol release];
2824       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2825     }
2827   [(raised_p ? lightCol : darkCol) set];
2829   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2831   /* top */
2832   sr.size.height = thickness;
2833   if (top_p) NSRectFill (sr);
2835   /* left */
2836   sr.size.height = r.size.height;
2837   sr.size.width = thickness;
2838   if (left_p) NSRectFill (sr);
2840   [(raised_p ? darkCol : lightCol) set];
2842   /* bottom */
2843   sr.size.width = r.size.width;
2844   sr.size.height = thickness;
2845   sr.origin.y += r.size.height - thickness;
2846   if (bottom_p) NSRectFill (sr);
2848   /* right */
2849   sr.size.height = r.size.height;
2850   sr.origin.y = r.origin.y;
2851   sr.size.width = thickness;
2852   sr.origin.x += r.size.width - thickness;
2853   if (right_p) NSRectFill (sr);
2857 static void
2858 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2859 /* --------------------------------------------------------------------------
2860       Function modeled after x_draw_glyph_string_box ().
2861       Sets up parameters for drawing.
2862    -------------------------------------------------------------------------- */
2864   int right_x, last_x;
2865   char left_p, right_p;
2866   struct glyph *last_glyph;
2867   NSRect r;
2868   int thickness;
2869   struct face *face;
2871   if (s->hl == DRAW_MOUSE_FACE)
2872     {
2873       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2874       if (!face)
2875         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2876     }
2877   else
2878     face = s->face;
2880   thickness = face->box_line_width;
2882   NSTRACE (ns_dumpglyphs_box_or_relief);
2884   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2885             ? WINDOW_RIGHT_EDGE_X (s->w)
2886             : window_box_right (s->w, s->area));
2887   last_glyph = (s->cmp || s->img
2888                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2890   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2891               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2893   left_p = (s->first_glyph->left_box_line_p
2894             || (s->hl == DRAW_MOUSE_FACE
2895                 && (s->prev == NULL || s->prev->hl != s->hl)));
2896   right_p = (last_glyph->right_box_line_p
2897              || (s->hl == DRAW_MOUSE_FACE
2898                  && (s->next == NULL || s->next->hl != s->hl)));
2900   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2902   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2903   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2904     {
2905       ns_draw_box (r, abs (thickness),
2906                    ns_lookup_indexed_color (face->box_color, s->f),
2907                   left_p, right_p);
2908     }
2909   else
2910     {
2911       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2912                      1, 1, left_p, right_p, s);
2913     }
2917 static void
2918 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2919 /* --------------------------------------------------------------------------
2920       Modeled after x_draw_glyph_string_background, which draws BG in
2921       certain cases.  Others are left to the text rendering routine.
2922    -------------------------------------------------------------------------- */
2924   NSTRACE (ns_maybe_dumpglyphs_background);
2926   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2927     {
2928       int box_line_width = max (s->face->box_line_width, 0);
2929       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2930           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2931         {
2932           struct face *face;
2933           if (s->hl == DRAW_MOUSE_FACE)
2934             {
2935               face = FACE_FROM_ID (s->f,
2936                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2937               if (!face)
2938                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2939             }
2940           else
2941             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2942           if (!face->stipple)
2943             [(NS_FACE_BACKGROUND (face) != 0
2944               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2945               : FRAME_BACKGROUND_COLOR (s->f)) set];
2946           else
2947             {
2948               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
2949               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2950             }
2952           if (s->hl != DRAW_CURSOR)
2953             {
2954               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2955                                     s->background_width,
2956                                     s->height-2*box_line_width);
2957               NSRectFill (r);
2958             }
2960           s->background_filled_p = 1;
2961         }
2962     }
2966 static void
2967 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2968 /* --------------------------------------------------------------------------
2969       Renders an image and associated borders.
2970    -------------------------------------------------------------------------- */
2972   EmacsImage *img = s->img->pixmap;
2973   int box_line_vwidth = max (s->face->box_line_width, 0);
2974   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2975   int bg_x, bg_y, bg_height;
2976   int th;
2977   char raised_p;
2978   NSRect br;
2979   struct face *face;
2980   NSColor *tdCol;
2982   NSTRACE (ns_dumpglyphs_image);
2984   if (s->face->box != FACE_NO_BOX
2985       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2986     x += abs (s->face->box_line_width);
2988   bg_x = x;
2989   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2990   bg_height = s->height;
2991   /* other terms have this, but was causing problems w/tabbar mode */
2992   /* - 2 * box_line_vwidth; */
2994   if (s->slice.x == 0) x += s->img->hmargin;
2995   if (s->slice.y == 0) y += s->img->vmargin;
2997   /* Draw BG: if we need larger area than image itself cleared, do that,
2998      otherwise, since we composite the image under NS (instead of mucking
2999      with its background color), we must clear just the image area. */
3000   if (s->hl == DRAW_MOUSE_FACE)
3001     {
3002       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3003       if (!face)
3004        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3005     }
3006   else
3007     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3009   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3011   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3012       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3013     {
3014       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3015       s->background_filled_p = 1;
3016     }
3017   else
3018     {
3019       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3020     }
3022   NSRectFill (br);
3024   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3025   if (img != nil)
3026     {
3027 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
3028       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3029       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3030                               s->slice.width, s->slice.height);
3031       [img drawInRect: dr
3032              fromRect: ir
3033              operation: NSCompositeSourceOver
3034               fraction: 1.0
3035            respectFlipped: YES
3036                 hints: nil];
3037 #else
3038       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3039                   operation: NSCompositeSourceOver];
3040 #endif
3041     }
3043   if (s->hl == DRAW_CURSOR)
3044     {
3045     [FRAME_CURSOR_COLOR (s->f) set];
3046     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3047       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3048     else
3049       /* Currently on NS img->mask is always 0. Since
3050          get_window_cursor_type specifies a hollow box cursor when on
3051          a non-masked image we never reach this clause. But we put it
3052          in in anticipation of better support for image masks on
3053          NS. */
3054       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3055     }
3056   else
3057     {
3058       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3059     }
3061   /* Draw underline, overline, strike-through. */
3062   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3064   /* Draw relief, if requested */
3065   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3066     {
3067       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3068         {
3069           th = tool_bar_button_relief >= 0 ?
3070             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3071           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3072         }
3073       else
3074         {
3075           th = abs (s->img->relief);
3076           raised_p = (s->img->relief > 0);
3077         }
3079       r.origin.x = x - th;
3080       r.origin.y = y - th;
3081       r.size.width = s->slice.width + 2*th-1;
3082       r.size.height = s->slice.height + 2*th-1;
3083       ns_draw_relief (r, th, raised_p,
3084                       s->slice.y == 0,
3085                       s->slice.y + s->slice.height == s->img->height,
3086                       s->slice.x == 0,
3087                       s->slice.x + s->slice.width == s->img->width, s);
3088     }
3090   /* If there is no mask, the background won't be seen,
3091      so draw a rectangle on the image for the cursor.
3092      Do this for all images, getting transparency right is not reliable.  */
3093   if (s->hl == DRAW_CURSOR)
3094     {
3095       int thickness = abs (s->img->relief);
3096       if (thickness == 0) thickness = 1;
3097       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3098     }
3102 static void
3103 ns_dumpglyphs_stretch (struct glyph_string *s)
3105   NSRect r[2];
3106   int n, i;
3107   struct face *face;
3108   NSColor *fgCol, *bgCol;
3110   if (!s->background_filled_p)
3111     {
3112       n = ns_get_glyph_string_clip_rect (s, r);
3113       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3115       ns_focus (s->f, r, n);
3117       if (s->hl == DRAW_MOUSE_FACE)
3118        {
3119          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3120          if (!face)
3121            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3122        }
3123       else
3124        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3126       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3127       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3129       for (i = 0; i < n; ++i)
3130         {
3131           if (!s->row->full_width_p)
3132             {
3133               int overrun, leftoverrun;
3135               /* truncate to avoid overwriting fringe and/or scrollbar */
3136               overrun = max (0, (s->x + s->background_width)
3137                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3138                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3139               r[i].size.width -= overrun;
3141               /* truncate to avoid overwriting to left of the window box */
3142               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3143                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3145               if (leftoverrun > 0)
3146                 {
3147                   r[i].origin.x += leftoverrun;
3148                   r[i].size.width -= leftoverrun;
3149                 }
3151               /* XXX: Try to work between problem where a stretch glyph on
3152                  a partially-visible bottom row will clear part of the
3153                  modeline, and another where list-buffers headers and similar
3154                  rows erroneously have visible_height set to 0.  Not sure
3155                  where this is coming from as other terms seem not to show. */
3156               r[i].size.height = min (s->height, s->row->visible_height);
3157             }
3159           [bgCol set];
3161           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3162              overwriting cursor (usually when cursor on a tab) */
3163           if (s->hl == DRAW_CURSOR)
3164             {
3165               CGFloat x, width;
3167               x = r[i].origin.x;
3168               width = s->w->phys_cursor_width;
3169               r[i].size.width -= width;
3170               r[i].origin.x += width;
3172               NSRectFill (r[i]);
3174               /* Draw overlining, etc. on the cursor. */
3175               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3176                 ns_draw_text_decoration (s, face, bgCol, width, x);
3177               else
3178                 ns_draw_text_decoration (s, face, fgCol, width, x);
3179             }
3180           else
3181             {
3182               NSRectFill (r[i]);
3183             }
3185           /* Draw overlining, etc. on the stretch glyph (or the part
3186              of the stretch glyph after the cursor). */
3187           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3188                                    r[i].origin.x);
3189         }
3190       ns_unfocus (s->f);
3191       s->background_filled_p = 1;
3192     }
3196 static void
3197 ns_draw_glyph_string (struct glyph_string *s)
3198 /* --------------------------------------------------------------------------
3199       External (RIF): Main draw-text call.
3200    -------------------------------------------------------------------------- */
3202   /* TODO (optimize): focus for box and contents draw */
3203   NSRect r[2];
3204   int n, flags;
3205   char box_drawn_p = 0;
3206   struct font *font = s->face->font;
3207   if (! font) font = FRAME_FONT (s->f);
3209   NSTRACE (ns_draw_glyph_string);
3211   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3212     {
3213       int width;
3214       struct glyph_string *next;
3216       for (width = 0, next = s->next;
3217            next && width < s->right_overhang;
3218            width += next->width, next = next->next)
3219         if (next->first_glyph->type != IMAGE_GLYPH)
3220           {
3221             if (next->first_glyph->type != STRETCH_GLYPH)
3222               {
3223                 n = ns_get_glyph_string_clip_rect (s->next, r);
3224                 ns_focus (s->f, r, n);
3225                 ns_maybe_dumpglyphs_background (s->next, 1);
3226                 ns_unfocus (s->f);
3227               }
3228             else
3229               {
3230                 ns_dumpglyphs_stretch (s->next);
3231               }
3232             next->num_clips = 0;
3233           }
3234     }
3236   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3237         && (s->first_glyph->type == CHAR_GLYPH
3238             || s->first_glyph->type == COMPOSITE_GLYPH))
3239     {
3240       n = ns_get_glyph_string_clip_rect (s, r);
3241       ns_focus (s->f, r, n);
3242       ns_maybe_dumpglyphs_background (s, 1);
3243       ns_dumpglyphs_box_or_relief (s);
3244       ns_unfocus (s->f);
3245       box_drawn_p = 1;
3246     }
3248   switch (s->first_glyph->type)
3249     {
3251     case IMAGE_GLYPH:
3252       n = ns_get_glyph_string_clip_rect (s, r);
3253       ns_focus (s->f, r, n);
3254       ns_dumpglyphs_image (s, r[0]);
3255       ns_unfocus (s->f);
3256       break;
3258     case STRETCH_GLYPH:
3259       ns_dumpglyphs_stretch (s);
3260       break;
3262     case CHAR_GLYPH:
3263     case COMPOSITE_GLYPH:
3264       n = ns_get_glyph_string_clip_rect (s, r);
3265       ns_focus (s->f, r, n);
3267       if (s->for_overlaps || (s->cmp_from > 0
3268                               && ! s->first_glyph->u.cmp.automatic))
3269         s->background_filled_p = 1;
3270       else
3271         ns_maybe_dumpglyphs_background
3272           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3274       flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3275         (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3276          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3277           NS_DUMPGLYPH_NORMAL));
3279       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3280         {
3281           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3282           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3283           NS_FACE_FOREGROUND (s->face) = tmp;
3284         }
3286       {
3287         BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3288         int end = isComposite ? s->cmp_to : s->nchars;
3290         font->driver->draw
3291           (s, s->cmp_from, end, s->x, s->ybase,
3292            (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3293            || flags == NS_DUMPGLYPH_MOUSEFACE);
3295       }
3297       {
3298         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3299                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3300                                                    s->f)
3301                         : FRAME_FOREGROUND_COLOR (s->f));
3302         [col set];
3304         /* Draw underline, overline, strike-through. */
3305         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3306       }
3308       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3309         {
3310           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3311           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3312           NS_FACE_FOREGROUND (s->face) = tmp;
3313         }
3315       ns_unfocus (s->f);
3316       break;
3318     case GLYPHLESS_GLYPH:
3319       n = ns_get_glyph_string_clip_rect (s, r);
3320       ns_focus (s->f, r, n);
3322       if (s->for_overlaps || (s->cmp_from > 0
3323                               && ! s->first_glyph->u.cmp.automatic))
3324         s->background_filled_p = 1;
3325       else
3326         ns_maybe_dumpglyphs_background
3327           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3328       /* ... */
3329       /* Not yet implemented.  */
3330       /* ... */
3331       ns_unfocus (s->f);
3332       break;
3334     default:
3335       emacs_abort ();
3336     }
3338   /* Draw box if not done already. */
3339   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3340     {
3341       n = ns_get_glyph_string_clip_rect (s, r);
3342       ns_focus (s->f, r, n);
3343       ns_dumpglyphs_box_or_relief (s);
3344       ns_unfocus (s->f);
3345     }
3347   s->num_clips = 0;
3352 /* ==========================================================================
3354     Event loop
3356    ========================================================================== */
3359 static void
3360 ns_send_appdefined (int value)
3361 /* --------------------------------------------------------------------------
3362     Internal: post an appdefined event which EmacsApp-sendEvent will
3363               recognize and take as a command to halt the event loop.
3364    -------------------------------------------------------------------------- */
3366   /*NSTRACE (ns_send_appdefined); */
3368 #ifdef NS_IMPL_GNUSTEP
3369   // GNUstep needs postEvent to happen on the main thread.
3370   if (! [[NSThread currentThread] isMainThread])
3371     {
3372       EmacsApp *app = (EmacsApp *)NSApp;
3373       app->nextappdefined = value;
3374       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3375                             withObject:nil
3376                          waitUntilDone:YES];
3377       return;
3378     }
3379 #endif
3381   /* Only post this event if we haven't already posted one.  This will end
3382        the [NXApp run] main loop after having processed all events queued at
3383        this moment.  */
3384   if (send_appdefined)
3385     {
3386       NSEvent *nxev;
3388       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3389       send_appdefined = NO;
3391       /* Don't need wakeup timer any more */
3392       if (timed_entry)
3393         {
3394           [timed_entry invalidate];
3395           [timed_entry release];
3396           timed_entry = nil;
3397         }
3399       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3400                                 location: NSMakePoint (0, 0)
3401                            modifierFlags: 0
3402                                timestamp: 0
3403                             windowNumber: [[NSApp mainWindow] windowNumber]
3404                                  context: [NSApp context]
3405                                  subtype: 0
3406                                    data1: value
3407                                    data2: 0];
3409       /* Post an application defined event on the event queue.  When this is
3410          received the [NXApp run] will return, thus having processed all
3411          events which are currently queued.  */
3412       [NSApp postEvent: nxev atStart: NO];
3413     }
3416 #ifdef HAVE_NATIVE_FS
3417 static void
3418 check_native_fs ()
3420   Lisp_Object frame, tail;
3422   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3423     return;
3425   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3427   FOR_EACH_FRAME (tail, frame)
3428     {
3429       struct frame *f = XFRAME (frame);
3430       if (FRAME_NS_P (f))
3431         {
3432           EmacsView *view = FRAME_NS_VIEW (f);
3433           [view updateCollectionBehavior];
3434         }
3435     }
3437 #endif
3439 /* GNUstep and OSX <= 10.4 does not have cancelTracking.  */
3440 #if defined (NS_IMPL_COCOA) && \
3441   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
3442 /* Check if menu open should be canceled or continued as normal.  */
3443 void
3444 ns_check_menu_open (NSMenu *menu)
3446   /* Click in menu bar? */
3447   NSArray *a = [[NSApp mainMenu] itemArray];
3448   int i;
3449   BOOL found = NO;
3451   if (menu == nil) // Menu tracking ended.
3452     {
3453       if (menu_will_open_state == MENU_OPENING)
3454         menu_will_open_state = MENU_NONE;
3455       return;
3456     }
3458   for (i = 0; ! found && i < [a count]; i++)
3459     found = menu == [[a objectAtIndex:i] submenu];
3460   if (found)
3461     {
3462       if (menu_will_open_state == MENU_NONE && emacs_event)
3463         {
3464           NSEvent *theEvent = [NSApp currentEvent];
3465           struct frame *emacsframe = SELECTED_FRAME ();
3467           [menu cancelTracking];
3468           menu_will_open_state = MENU_PENDING;
3469           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3470           EV_TRAILER (theEvent);
3472           CGEventRef ourEvent = CGEventCreate (NULL);
3473           menu_mouse_point = CGEventGetLocation (ourEvent);
3474           CFRelease (ourEvent);
3475         }
3476       else if (menu_will_open_state == MENU_OPENING)
3477         {
3478           menu_will_open_state = MENU_NONE;
3479         }
3480     }
3483 /* Redo saved menu click if state is MENU_PENDING.  */
3484 void
3485 ns_check_pending_open_menu ()
3487   if (menu_will_open_state == MENU_PENDING)
3488     {
3489       CGEventSourceRef source
3490         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3492       CGEventRef event = CGEventCreateMouseEvent (source,
3493                                                   kCGEventLeftMouseDown,
3494                                                   menu_mouse_point,
3495                                                   kCGMouseButtonLeft);
3496       CGEventSetType (event, kCGEventLeftMouseDown);
3497       CGEventPost (kCGHIDEventTap, event);
3498       CFRelease (event);
3499       CFRelease (source);
3501       menu_will_open_state = MENU_OPENING;
3502     }
3504 #endif /* NS_IMPL_COCOA) && >= MAC_OS_X_VERSION_10_5 */
3506 static int
3507 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3508 /* --------------------------------------------------------------------------
3509      External (hook): Post an event to ourself and keep reading events until
3510      we read it back again.  In effect process all events which were waiting.
3511      From 21+ we have to manage the event buffer ourselves.
3512    -------------------------------------------------------------------------- */
3514   struct input_event ev;
3515   int nevents;
3517 /* NSTRACE (ns_read_socket); */
3519 #ifdef HAVE_NATIVE_FS
3520   check_native_fs ();
3521 #endif
3523   if ([NSApp modalWindow] != nil)
3524     return -1;
3526   if (hold_event_q.nr > 0)
3527     {
3528       int i;
3529       for (i = 0; i < hold_event_q.nr; ++i)
3530         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3531       hold_event_q.nr = 0;
3532       return i;
3533     }
3535   block_input ();
3536   n_emacs_events_pending = 0;
3537   ns_init_events (&ev);
3538   q_event_ptr = hold_quit;
3540   /* we manage autorelease pools by allocate/reallocate each time around
3541      the loop; strict nesting is occasionally violated but seems not to
3542      matter.. earlier methods using full nesting caused major memory leaks */
3543   [outerpool release];
3544   outerpool = [[NSAutoreleasePool alloc] init];
3546   /* If have pending open-file requests, attend to the next one of those. */
3547   if (ns_pending_files && [ns_pending_files count] != 0
3548       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3549     {
3550       [ns_pending_files removeObjectAtIndex: 0];
3551     }
3552   /* Deal with pending service requests. */
3553   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3554     && [(EmacsApp *)
3555          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3556                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3557     {
3558       [ns_pending_service_names removeObjectAtIndex: 0];
3559       [ns_pending_service_args removeObjectAtIndex: 0];
3560     }
3561   else
3562     {
3563       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3564          to ourself, otherwise [NXApp run] will never exit.  */
3565       send_appdefined = YES;
3566       ns_send_appdefined (-1);
3568       if (++apploopnr != 1)
3569         {
3570           emacs_abort ();
3571         }
3572       [NSApp run];
3573       --apploopnr;
3574     }
3576   nevents = n_emacs_events_pending;
3577   n_emacs_events_pending = 0;
3578   ns_finish_events ();
3579   q_event_ptr = NULL;
3580   unblock_input ();
3582   return nevents;
3587 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3588            fd_set *exceptfds, struct timespec const *timeout,
3589            sigset_t const *sigmask)
3590 /* --------------------------------------------------------------------------
3591      Replacement for select, checking for events
3592    -------------------------------------------------------------------------- */
3594   int result;
3595   int t, k, nr = 0;
3596   struct input_event event;
3597   char c;
3599 /*  NSTRACE (ns_select); */
3601 #ifdef HAVE_NATIVE_FS
3602   check_native_fs ();
3603 #endif
3605   if (hold_event_q.nr > 0)
3606     {
3607       /* We already have events pending. */
3608       raise (SIGIO);
3609       errno = EINTR;
3610       return -1;
3611     }
3613   for (k = 0; k < nfds+1; k++)
3614     {
3615       if (readfds && FD_ISSET(k, readfds)) ++nr;
3616       if (writefds && FD_ISSET(k, writefds)) ++nr;
3617     }
3619   if (NSApp == nil
3620       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3621     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3623   [outerpool release];
3624   outerpool = [[NSAutoreleasePool alloc] init];
3627   send_appdefined = YES;
3628   if (nr > 0)
3629     {
3630       pthread_mutex_lock (&select_mutex);
3631       select_nfds = nfds;
3632       select_valid = 0;
3633       if (readfds)
3634         {
3635           select_readfds = *readfds;
3636           select_valid += SELECT_HAVE_READ;
3637         }
3638       if (writefds)
3639         {
3640           select_writefds = *writefds;
3641           select_valid += SELECT_HAVE_WRITE;
3642         }
3644       if (timeout)
3645         {
3646           select_timeout = *timeout;
3647           select_valid += SELECT_HAVE_TMO;
3648         }
3650       pthread_mutex_unlock (&select_mutex);
3652       /* Inform fd_handler that select should be called */
3653       c = 'g';
3654       emacs_write_sig (selfds[1], &c, 1);
3655     }
3656   else if (nr == 0 && timeout)
3657     {
3658       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3659       double time = timespectod (*timeout);
3660       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3661                                                       target: NSApp
3662                                                     selector:
3663                                   @selector (timeout_handler:)
3664                                                     userInfo: 0
3665                                                      repeats: NO]
3666                       retain];
3667     }
3668   else /* No timeout and no file descriptors, can this happen?  */
3669     {
3670       /* Send appdefined so we exit from the loop */
3671       ns_send_appdefined (-1);
3672     }
3674   block_input ();
3675   ns_init_events (&event);
3676   if (++apploopnr != 1)
3677     {
3678       emacs_abort ();
3679     }
3680   [NSApp run];
3681   --apploopnr;
3682   ns_finish_events ();
3683   if (nr > 0 && readfds)
3684     {
3685       c = 's';
3686       emacs_write_sig (selfds[1], &c, 1);
3687     }
3688   unblock_input ();
3690   t = last_appdefined_event_data;
3692   if (t != NO_APPDEFINED_DATA)
3693     {
3694       last_appdefined_event_data = NO_APPDEFINED_DATA;
3696       if (t == -2)
3697         {
3698           /* The NX_APPDEFINED event we received was a timeout. */
3699           result = 0;
3700         }
3701       else if (t == -1)
3702         {
3703           /* The NX_APPDEFINED event we received was the result of
3704              at least one real input event arriving.  */
3705           errno = EINTR;
3706           result = -1;
3707         }
3708       else
3709         {
3710           /* Received back from select () in fd_handler; copy the results */
3711           pthread_mutex_lock (&select_mutex);
3712           if (readfds) *readfds = select_readfds;
3713           if (writefds) *writefds = select_writefds;
3714           pthread_mutex_unlock (&select_mutex);
3715           result = t;
3716         }
3717     }
3718   else
3719     {
3720       errno = EINTR;
3721       result = -1;
3722     }
3724   return result;
3729 /* ==========================================================================
3731     Scrollbar handling
3733    ========================================================================== */
3736 static void
3737 ns_set_vertical_scroll_bar (struct window *window,
3738                            int portion, int whole, int position)
3739 /* --------------------------------------------------------------------------
3740       External (hook): Update or add scrollbar
3741    -------------------------------------------------------------------------- */
3743   Lisp_Object win;
3744   NSRect r, v;
3745   struct frame *f = XFRAME (WINDOW_FRAME (window));
3746   EmacsView *view = FRAME_NS_VIEW (f);
3747   EmacsScroller *bar;
3748   int window_y, window_height;
3749   int top, left, height, width;
3751   /* optimization; display engine sends WAY too many of these.. */
3752   if (!NILP (window->vertical_scroll_bar))
3753     {
3754       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3755       if ([bar checkSamePosition: position portion: portion whole: whole])
3756         {
3757           if (view->scrollbarsNeedingUpdate == 0)
3758             {
3759               if (!windows_or_buffers_changed)
3760                   return;
3761             }
3762           else
3763             view->scrollbarsNeedingUpdate--;
3764         }
3765     }
3767   NSTRACE (ns_set_vertical_scroll_bar);
3769   /* Get dimensions.  */
3770   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3771   top = window_y;
3772   height = window_height;
3773   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3774   left = WINDOW_SCROLL_BAR_AREA_X (window);
3776   r = NSMakeRect (left, top, width, height);
3777   /* the parent view is flipped, so we need to flip y value */
3778   v = [view frame];
3779   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3781   XSETWINDOW (win, window);
3782   block_input ();
3784   /* we want at least 5 lines to display a scrollbar */
3785   if (WINDOW_TOTAL_LINES (window) < 5)
3786     {
3787       if (!NILP (window->vertical_scroll_bar))
3788         {
3789           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3790           [bar removeFromSuperview];
3791           wset_vertical_scroll_bar (window, Qnil);
3792         }
3793       ns_clear_frame_area (f, left, top, width, height);
3794       unblock_input ();
3795       return;
3796     }
3798   if (NILP (window->vertical_scroll_bar))
3799     {
3800       if (width > 0 && height > 0)
3801         ns_clear_frame_area (f, left, top, width, height);
3803       bar = [[EmacsScroller alloc] initFrame: r window: win];
3804       wset_vertical_scroll_bar (window, make_save_ptr (bar));
3805     }
3806   else
3807     {
3808       NSRect oldRect;
3809       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3810       oldRect = [bar frame];
3811       r.size.width = oldRect.size.width;
3812       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3813         {
3814           if (oldRect.origin.x != r.origin.x)
3815               ns_clear_frame_area (f, left, top, width, height);
3816           [bar setFrame: r];
3817         }
3818     }
3820   [bar setPosition: position portion: portion whole: whole];
3821   unblock_input ();
3825 static void
3826 ns_set_horizontal_scroll_bar (struct window *window,
3827                               int portion, int whole, int position)
3828 /* --------------------------------------------------------------------------
3829       External (hook): Update or add scrollbar
3830    -------------------------------------------------------------------------- */
3832   Lisp_Object win;
3833   NSRect r, v;
3834   struct frame *f = XFRAME (WINDOW_FRAME (window));
3835   EmacsView *view = FRAME_NS_VIEW (f);
3836   EmacsScroller *bar;
3837   int top, height, left, width;
3838   int window_x, window_width;
3839   int pixel_width = WINDOW_PIXEL_WIDTH (window);
3841   /* optimization; display engine sends WAY too many of these.. */
3842   if (!NILP (window->horizontal_scroll_bar))
3843     {
3844       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3845       if ([bar checkSamePosition: position portion: portion whole: whole])
3846         {
3847           if (view->scrollbarsNeedingUpdate == 0)
3848             {
3849               if (!windows_or_buffers_changed)
3850                   return;
3851             }
3852           else
3853             view->scrollbarsNeedingUpdate--;
3854         }
3855     }
3857   NSTRACE (ns_set_horizontal_scroll_bar);
3859   /* Get dimensions.  */
3860   window_box (window, ANY_AREA, 0, &window_x, &window_width, 0);
3861   left = window_x;
3862   width = window_width;
3863   height = WINDOW_CONFIG_SCROLL_BAR_LINES (window) * FRAME_LINE_HEIGHT (f);
3864   top = WINDOW_SCROLL_BAR_AREA_Y (window);
3866   r = NSMakeRect (left, top, width, height);
3867   /* the parent view is flipped, so we need to flip y value */
3868   v = [view frame];
3869   /* ??????? PXW/scrollbars !!!!!!!!!!!!!!!!!!!! */
3870   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3872   XSETWINDOW (win, window);
3873   block_input ();
3875   if (WINDOW_TOTAL_COLS (window) < 5)
3876     {
3877       if (!NILP (window->horizontal_scroll_bar))
3878         {
3879           bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3880           [bar removeFromSuperview];
3881           wset_horizontal_scroll_bar (window, Qnil);
3882         }
3883       ns_clear_frame_area (f, left, top, width, height);
3884       unblock_input ();
3885       return;
3886     }
3888   if (NILP (window->horizontal_scroll_bar))
3889     {
3890       if (width > 0 && height > 0)
3891         ns_clear_frame_area (f, left, top, width, height);
3893       bar = [[EmacsScroller alloc] initFrame: r window: win];
3894       wset_horizontal_scroll_bar (window, make_save_ptr (bar));
3895     }
3896   else
3897     {
3898       NSRect oldRect;
3899       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3900       oldRect = [bar frame];
3901       r.size.width = oldRect.size.width;
3902       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3903         {
3904           if (oldRect.origin.x != r.origin.x)
3905               ns_clear_frame_area (f, left, top, width, height);
3906           [bar setFrame: r];
3907         }
3908     }
3910   [bar setPosition: position portion: portion whole: whole];
3911   unblock_input ();
3915 static void
3916 ns_condemn_scroll_bars (struct frame *f)
3917 /* --------------------------------------------------------------------------
3918      External (hook): arrange for all frame's scrollbars to be removed
3919      at next call to judge_scroll_bars, except for those redeemed.
3920    -------------------------------------------------------------------------- */
3922   int i;
3923   id view;
3924   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3926   NSTRACE (ns_condemn_scroll_bars);
3928   for (i =[subviews count]-1; i >= 0; i--)
3929     {
3930       view = [subviews objectAtIndex: i];
3931       if ([view isKindOfClass: [EmacsScroller class]])
3932         [view condemn];
3933     }
3937 static void
3938 ns_redeem_scroll_bar (struct window *window)
3939 /* --------------------------------------------------------------------------
3940      External (hook): arrange to spare this window's scrollbar
3941      at next call to judge_scroll_bars.
3942    -------------------------------------------------------------------------- */
3944   id bar;
3945   NSTRACE (ns_redeem_scroll_bar);
3946   if (!NILP (window->vertical_scroll_bar))
3947     {
3948       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3949       [bar reprieve];
3950     }
3952   if (!NILP (window->horizontal_scroll_bar))
3953     {
3954       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3955       [bar reprieve];
3956     }
3960 static void
3961 ns_judge_scroll_bars (struct frame *f)
3962 /* --------------------------------------------------------------------------
3963      External (hook): destroy all scrollbars on frame that weren't
3964      redeemed after call to condemn_scroll_bars.
3965    -------------------------------------------------------------------------- */
3967   int i;
3968   id view;
3969   EmacsView *eview = FRAME_NS_VIEW (f);
3970   NSArray *subviews = [[eview superview] subviews];
3971   BOOL removed = NO;
3973   NSTRACE (ns_judge_scroll_bars);
3974   for (i = [subviews count]-1; i >= 0; --i)
3975     {
3976       view = [subviews objectAtIndex: i];
3977       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3978       [view judge];
3979       removed = YES;
3980     }
3982   if (removed)
3983     [eview updateFrameSize: NO];
3986 /* ==========================================================================
3988     Initialization
3990    ========================================================================== */
3993 x_display_pixel_height (struct ns_display_info *dpyinfo)
3995   NSArray *screens = [NSScreen screens];
3996   NSEnumerator *enumerator = [screens objectEnumerator];
3997   NSScreen *screen;
3998   NSRect frame;
4000   frame = NSZeroRect;
4001   while ((screen = [enumerator nextObject]) != nil)
4002     frame = NSUnionRect (frame, [screen frame]);
4004   return NSHeight (frame);
4008 x_display_pixel_width (struct ns_display_info *dpyinfo)
4010   NSArray *screens = [NSScreen screens];
4011   NSEnumerator *enumerator = [screens objectEnumerator];
4012   NSScreen *screen;
4013   NSRect frame;
4015   frame = NSZeroRect;
4016   while ((screen = [enumerator nextObject]) != nil)
4017     frame = NSUnionRect (frame, [screen frame]);
4019   return NSWidth (frame);
4023 static Lisp_Object ns_string_to_lispmod (const char *s)
4024 /* --------------------------------------------------------------------------
4025      Convert modifier name to lisp symbol
4026    -------------------------------------------------------------------------- */
4028   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4029     return Qmeta;
4030   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4031     return Qsuper;
4032   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4033     return Qcontrol;
4034   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4035     return Qalt;
4036   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4037     return Qhyper;
4038   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4039     return Qnone;
4040   else
4041     return Qnil;
4045 static void
4046 ns_default (const char *parameter, Lisp_Object *result,
4047            Lisp_Object yesval, Lisp_Object noval,
4048            BOOL is_float, BOOL is_modstring)
4049 /* --------------------------------------------------------------------------
4050       Check a parameter value in user's preferences
4051    -------------------------------------------------------------------------- */
4053   const char *value = ns_get_defaults_value (parameter);
4055   if (value)
4056     {
4057       double f;
4058       char *pos;
4059       if (c_strcasecmp (value, "YES") == 0)
4060         *result = yesval;
4061       else if (c_strcasecmp (value, "NO") == 0)
4062         *result = noval;
4063       else if (is_float && (f = strtod (value, &pos), pos != value))
4064         *result = make_float (f);
4065       else if (is_modstring && value)
4066         *result = ns_string_to_lispmod (value);
4067       else fprintf (stderr,
4068                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4069     }
4073 static void
4074 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4075 /* --------------------------------------------------------------------------
4076       Initialize global info and storage for display.
4077    -------------------------------------------------------------------------- */
4079     NSScreen *screen = [NSScreen mainScreen];
4080     NSWindowDepth depth = [screen depth];
4082     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4083     dpyinfo->resy = 72.27;
4084     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4085                                                   NSColorSpaceFromDepth (depth)]
4086                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4087                                                  NSColorSpaceFromDepth (depth)];
4088     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4089     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4090     dpyinfo->color_table->colors = NULL;
4091     dpyinfo->root_window = 42; /* a placeholder.. */
4092     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4093     dpyinfo->n_fonts = 0;
4094     dpyinfo->smallest_font_height = 1;
4095     dpyinfo->smallest_char_width = 1;
4097     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4101 /* This and next define (many of the) public functions in this file. */
4102 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4103          with using despite presence in the "system dependent" redisplay
4104          interface.  In addition, many of the ns_ methods have code that is
4105          shared with all terms, indicating need for further refactoring. */
4106 extern frame_parm_handler ns_frame_parm_handlers[];
4107 static struct redisplay_interface ns_redisplay_interface =
4109   ns_frame_parm_handlers,
4110   x_produce_glyphs,
4111   x_write_glyphs,
4112   x_insert_glyphs,
4113   x_clear_end_of_line,
4114   ns_scroll_run,
4115   ns_after_update_window_line,
4116   ns_update_window_begin,
4117   ns_update_window_end,
4118   0, /* flush_display */
4119   x_clear_window_mouse_face,
4120   x_get_glyph_overhangs,
4121   x_fix_overlapping_area,
4122   ns_draw_fringe_bitmap,
4123   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4124   0, /* destroy_fringe_bitmap */
4125   ns_compute_glyph_string_overhangs,
4126   ns_draw_glyph_string,
4127   ns_define_frame_cursor,
4128   ns_clear_frame_area,
4129   ns_draw_window_cursor,
4130   ns_draw_vertical_window_border,
4131   ns_draw_window_divider,
4132   ns_shift_glyphs_for_insert,
4133   ns_show_hourglass,
4134   ns_hide_hourglass
4138 static void
4139 ns_delete_display (struct ns_display_info *dpyinfo)
4141   /* TODO... */
4145 /* This function is called when the last frame on a display is deleted. */
4146 static void
4147 ns_delete_terminal (struct terminal *terminal)
4149   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4151   /* Protect against recursive calls.  delete_frame in
4152      delete_terminal calls us back when it deletes our last frame.  */
4153   if (!terminal->name)
4154     return;
4156   block_input ();
4158   x_destroy_all_bitmaps (dpyinfo);
4159   ns_delete_display (dpyinfo);
4160   unblock_input ();
4164 static struct terminal *
4165 ns_create_terminal (struct ns_display_info *dpyinfo)
4166 /* --------------------------------------------------------------------------
4167       Set up use of NS before we make the first connection.
4168    -------------------------------------------------------------------------- */
4170   struct terminal *terminal;
4172   NSTRACE (ns_create_terminal);
4174   terminal = create_terminal (output_ns, &ns_redisplay_interface);
4176   terminal->display_info.ns = dpyinfo;
4177   dpyinfo->terminal = terminal;
4179   terminal->clear_frame_hook = ns_clear_frame;
4180   terminal->ring_bell_hook = ns_ring_bell;
4181   terminal->update_begin_hook = ns_update_begin;
4182   terminal->update_end_hook = ns_update_end;
4183   terminal->read_socket_hook = ns_read_socket;
4184   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4185   terminal->mouse_position_hook = ns_mouse_position;
4186   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4187   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4188   terminal->fullscreen_hook = ns_fullscreen_hook;
4189   terminal->menu_show_hook = ns_menu_show;
4190   terminal->popup_dialog_hook = ns_popup_dialog;
4191   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4192   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4193   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4194   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4195   terminal->delete_frame_hook = x_destroy_window;
4196   terminal->delete_terminal_hook = ns_delete_terminal;
4197   /* Other hooks are NULL by default.  */
4199   return terminal;
4203 struct ns_display_info *
4204 ns_term_init (Lisp_Object display_name)
4205 /* --------------------------------------------------------------------------
4206      Start the Application and get things rolling.
4207    -------------------------------------------------------------------------- */
4209   struct terminal *terminal;
4210   struct ns_display_info *dpyinfo;
4211   static int ns_initialized = 0;
4212   Lisp_Object tmp;
4214   if (ns_initialized) return x_display_list;
4215   ns_initialized = 1;
4217   NSTRACE (ns_term_init);
4219   [outerpool release];
4220   outerpool = [[NSAutoreleasePool alloc] init];
4222   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4223   /*GSDebugAllocationActive (YES); */
4224   block_input ();
4226   baud_rate = 38400;
4227   Fset_input_interrupt_mode (Qnil);
4229   if (selfds[0] == -1)
4230     {
4231       if (emacs_pipe (selfds) != 0)
4232         {
4233           fprintf (stderr, "Failed to create pipe: %s\n",
4234                    emacs_strerror (errno));
4235           emacs_abort ();
4236         }
4238       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4239       FD_ZERO (&select_readfds);
4240       FD_ZERO (&select_writefds);
4241       pthread_mutex_init (&select_mutex, NULL);
4242     }
4244   ns_pending_files = [[NSMutableArray alloc] init];
4245   ns_pending_service_names = [[NSMutableArray alloc] init];
4246   ns_pending_service_args = [[NSMutableArray alloc] init];
4248 /* Start app and create the main menu, window, view.
4249      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4250      The view will then ask the NSApp to stop and return to Emacs. */
4251   [EmacsApp sharedApplication];
4252   if (NSApp == nil)
4253     return NULL;
4254   [NSApp setDelegate: NSApp];
4256   /* Start the select thread.  */
4257   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4258                            toTarget:NSApp
4259                          withObject:nil];
4261   /* debugging: log all notifications */
4262   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4263                                          selector: @selector (logNotification:)
4264                                              name: nil object: nil]; */
4266   dpyinfo = xzalloc (sizeof *dpyinfo);
4268   ns_initialize_display_info (dpyinfo);
4269   terminal = ns_create_terminal (dpyinfo);
4271   terminal->kboard = allocate_kboard (Qns);
4272   /* Don't let the initial kboard remain current longer than necessary.
4273      That would cause problems if a file loaded on startup tries to
4274      prompt in the mini-buffer.  */
4275   if (current_kboard == initial_kboard)
4276     current_kboard = terminal->kboard;
4277   terminal->kboard->reference_count++;
4279   dpyinfo->next = x_display_list;
4280   x_display_list = dpyinfo;
4282   dpyinfo->name_list_element = Fcons (display_name, Qnil);
4284   terminal->name = xstrdup (SSDATA (display_name));
4286   unblock_input ();
4288   if (!inhibit_x_resources)
4289     {
4290       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4291                  Qt, Qnil, NO, NO);
4292       tmp = Qnil;
4293       /* this is a standard variable */
4294       ns_default ("AppleAntiAliasingThreshold", &tmp,
4295                  make_float (10.0), make_float (6.0), YES, NO);
4296       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4297     }
4299   {
4300     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4302     if ( cl == nil )
4303       {
4304         Lisp_Object color_file, color_map, color;
4305         unsigned long c;
4306         char *name;
4308         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4309                          Fsymbol_value (intern ("data-directory")));
4311         color_map = Fx_load_color_file (color_file);
4312         if (NILP (color_map))
4313           fatal ("Could not read %s.\n", SDATA (color_file));
4315         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4316         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4317           {
4318             color = XCAR (color_map);
4319             name = SSDATA (XCAR (color));
4320             c = XINT (XCDR (color));
4321             [cl setColor:
4322                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4323                                       green: GREEN_FROM_ULONG (c) / 255.0
4324                                        blue: BLUE_FROM_ULONG (c) / 255.0
4325                                       alpha: 1.0]
4326                   forKey: [NSString stringWithUTF8String: name]];
4327           }
4328         [cl writeToFile: nil];
4329       }
4330   }
4332   {
4333 #ifdef NS_IMPL_GNUSTEP
4334     Vwindow_system_version = build_string (gnustep_base_version);
4335 #else
4336     /*PSnextrelease (128, c); */
4337     char c[DBL_BUFSIZE_BOUND];
4338     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4339     Vwindow_system_version = make_unibyte_string (c, len);
4340 #endif
4341   }
4343   delete_keyboard_wait_descriptor (0);
4345   ns_app_name = [[NSProcessInfo processInfo] processName];
4347 /* Set up OS X app menu */
4348 #ifdef NS_IMPL_COCOA
4349   {
4350     NSMenu *appMenu;
4351     NSMenuItem *item;
4352     /* set up the application menu */
4353     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4354     [svcsMenu setAutoenablesItems: NO];
4355     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4356     [appMenu setAutoenablesItems: NO];
4357     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4358     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4360     [appMenu insertItemWithTitle: @"About Emacs"
4361                           action: @selector (orderFrontStandardAboutPanel:)
4362                    keyEquivalent: @""
4363                          atIndex: 0];
4364     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4365     [appMenu insertItemWithTitle: @"Preferences..."
4366                           action: @selector (showPreferencesWindow:)
4367                    keyEquivalent: @","
4368                          atIndex: 2];
4369     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4370     item = [appMenu insertItemWithTitle: @"Services"
4371                                  action: @selector (menuDown:)
4372                           keyEquivalent: @""
4373                                 atIndex: 4];
4374     [appMenu setSubmenu: svcsMenu forItem: item];
4375     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4376     [appMenu insertItemWithTitle: @"Hide Emacs"
4377                           action: @selector (hide:)
4378                    keyEquivalent: @"h"
4379                          atIndex: 6];
4380     item =  [appMenu insertItemWithTitle: @"Hide Others"
4381                           action: @selector (hideOtherApplications:)
4382                    keyEquivalent: @"h"
4383                          atIndex: 7];
4384     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4385     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4386     [appMenu insertItemWithTitle: @"Quit Emacs"
4387                           action: @selector (terminate:)
4388                    keyEquivalent: @"q"
4389                          atIndex: 9];
4391     item = [mainMenu insertItemWithTitle: ns_app_name
4392                                   action: @selector (menuDown:)
4393                            keyEquivalent: @""
4394                                  atIndex: 0];
4395     [mainMenu setSubmenu: appMenu forItem: item];
4396     [dockMenu insertItemWithTitle: @"New Frame"
4397                            action: @selector (newFrame:)
4398                     keyEquivalent: @""
4399                           atIndex: 0];
4401     [NSApp setMainMenu: mainMenu];
4402     [NSApp setAppleMenu: appMenu];
4403     [NSApp setServicesMenu: svcsMenu];
4404     /* Needed at least on Cocoa, to get dock menu to show windows */
4405     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4407     [[NSNotificationCenter defaultCenter]
4408       addObserver: mainMenu
4409          selector: @selector (trackingNotification:)
4410              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4411     [[NSNotificationCenter defaultCenter]
4412       addObserver: mainMenu
4413          selector: @selector (trackingNotification:)
4414              name: NSMenuDidEndTrackingNotification object: mainMenu];
4415   }
4416 #endif /* MAC OS X menu setup */
4418   /* Register our external input/output types, used for determining
4419      applicable services and also drag/drop eligibility. */
4420   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4421   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4422                       retain];
4423   ns_drag_types = [[NSArray arrayWithObjects:
4424                             NSStringPboardType,
4425                             NSTabularTextPboardType,
4426                             NSFilenamesPboardType,
4427                             NSURLPboardType, nil] retain];
4429   /* If fullscreen is in init/default-frame-alist, focus isn't set
4430      right for fullscreen windows, so set this.  */
4431   [NSApp activateIgnoringOtherApps:YES];
4433   [NSApp run];
4434   ns_do_open_file = YES;
4436 #ifdef NS_IMPL_GNUSTEP
4437   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4438      We must re-catch it so subprocess works.  */
4439   catch_child_signal ();
4440 #endif
4441   return dpyinfo;
4445 void
4446 ns_term_shutdown (int sig)
4448   [[NSUserDefaults standardUserDefaults] synchronize];
4450   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4451   if (STRINGP (Vauto_save_list_file_name))
4452     unlink (SSDATA (Vauto_save_list_file_name));
4454   if (sig == 0 || sig == SIGTERM)
4455     {
4456       [NSApp terminate: NSApp];
4457     }
4458   else // force a stack trace to happen
4459     {
4460       emacs_abort ();
4461     }
4465 /* ==========================================================================
4467     EmacsApp implementation
4469    ========================================================================== */
4472 @implementation EmacsApp
4474 - (id)init
4476   if (self = [super init])
4477     {
4478 #ifdef NS_IMPL_COCOA
4479       self->isFirst = YES;
4480 #endif
4481 #ifdef NS_IMPL_GNUSTEP
4482       self->applicationDidFinishLaunchingCalled = NO;
4483 #endif
4484     }
4486   return self;
4489 #ifdef NS_IMPL_COCOA
4490 - (void)run
4492 #ifndef NSAppKitVersionNumber10_8
4493 #define NSAppKitVersionNumber10_8 1187
4494 #endif
4496   if (NSAppKitVersionNumber <= NSAppKitVersionNumber10_8) 
4497     {
4498       [super run];
4499       return;
4500     }
4502   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4504   if (isFirst) [self finishLaunching];
4505   isFirst = NO;
4507   shouldKeepRunning = YES;
4508   do
4509     {
4510       [pool release];
4511       pool = [[NSAutoreleasePool alloc] init];
4513       NSEvent *event =
4514         [self nextEventMatchingMask:NSAnyEventMask
4515                           untilDate:[NSDate distantFuture]
4516                              inMode:NSDefaultRunLoopMode
4517                             dequeue:YES];
4518       [self sendEvent:event];
4519       [self updateWindows];
4520     } while (shouldKeepRunning);
4522   [pool release];
4525 - (void)stop: (id)sender
4527     shouldKeepRunning = NO;
4528     // Stop possible dialog also.  Noop if no dialog present.
4529     // The file dialog still leaks 7k - 10k on 10.9 though.
4530     [super stop:sender];
4532 #endif /* NS_IMPL_COCOA */
4534 - (void)logNotification: (NSNotification *)notification
4536   const char *name = [[notification name] UTF8String];
4537   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4538       && !strstr (name, "WindowNumber"))
4539     NSLog (@"notification: '%@'", [notification name]);
4543 - (void)sendEvent: (NSEvent *)theEvent
4544 /* --------------------------------------------------------------------------
4545      Called when NSApp is running for each event received.  Used to stop
4546      the loop when we choose, since there's no way to just run one iteration.
4547    -------------------------------------------------------------------------- */
4549   int type = [theEvent type];
4550   NSWindow *window = [theEvent window];
4552 /*  NSTRACE (sendEvent); */
4553 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4555 #ifdef NS_IMPL_GNUSTEP
4556   // Keyboard events aren't propagated to file dialogs for some reason.
4557   if ([NSApp modalWindow] != nil &&
4558       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4559     {
4560       [[NSApp modalWindow] sendEvent: theEvent];
4561       return;
4562     }
4563 #endif
4565   if (type == NSApplicationDefined)
4566     {
4567       switch ([theEvent data2])
4568         {
4569 #ifdef NS_IMPL_COCOA
4570         case NSAPP_DATA2_RUNASSCRIPT:
4571           ns_run_ascript ();
4572           [self stop: self];
4573           return;
4574 #endif
4575         case NSAPP_DATA2_RUNFILEDIALOG:
4576           ns_run_file_dialog ();
4577           [self stop: self];
4578           return;
4579         }
4580     }
4582   if (type == NSCursorUpdate && window == nil)
4583     {
4584       fprintf (stderr, "Dropping external cursor update event.\n");
4585       return;
4586     }
4588   if (type == NSApplicationDefined)
4589     {
4590       /* Events posted by ns_send_appdefined interrupt the run loop here.
4591          But, if a modal window is up, an appdefined can still come through,
4592          (e.g., from a makeKeyWindow event) but stopping self also stops the
4593          modal loop. Just defer it until later. */
4594       if ([NSApp modalWindow] == nil)
4595         {
4596           last_appdefined_event_data = [theEvent data1];
4597           [self stop: self];
4598         }
4599       else
4600         {
4601           send_appdefined = YES;
4602         }
4603     }
4606 #ifdef NS_IMPL_COCOA
4607   /* If no dialog and none of our frames have focus and it is a move, skip it.
4608      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4609      such as Wifi, sound, date or similar.
4610      This prevents "spooky" highlighting in the frame under the menu.  */
4611   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4612     {
4613       struct ns_display_info *di;
4614       BOOL has_focus = NO;
4615       for (di = x_display_list; ! has_focus && di; di = di->next)
4616         has_focus = di->x_focus_frame != 0;
4617       if (! has_focus)
4618         return;
4619     }
4620 #endif
4622   [super sendEvent: theEvent];
4626 - (void)showPreferencesWindow: (id)sender
4628   struct frame *emacsframe = SELECTED_FRAME ();
4629   NSEvent *theEvent = [NSApp currentEvent];
4631   if (!emacs_event)
4632     return;
4633   emacs_event->kind = NS_NONKEY_EVENT;
4634   emacs_event->code = KEY_NS_SHOW_PREFS;
4635   emacs_event->modifiers = 0;
4636   EV_TRAILER (theEvent);
4640 - (void)newFrame: (id)sender
4642   struct frame *emacsframe = SELECTED_FRAME ();
4643   NSEvent *theEvent = [NSApp currentEvent];
4645   if (!emacs_event)
4646     return;
4647   emacs_event->kind = NS_NONKEY_EVENT;
4648   emacs_event->code = KEY_NS_NEW_FRAME;
4649   emacs_event->modifiers = 0;
4650   EV_TRAILER (theEvent);
4654 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4655 - (BOOL) openFile: (NSString *)fileName
4657   struct frame *emacsframe = SELECTED_FRAME ();
4658   NSEvent *theEvent = [NSApp currentEvent];
4660   if (!emacs_event)
4661     return NO;
4663   emacs_event->kind = NS_NONKEY_EVENT;
4664   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4665   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4666   ns_input_line = Qnil; /* can be start or cons start,end */
4667   emacs_event->modifiers =0;
4668   EV_TRAILER (theEvent);
4670   return YES;
4674 /* **************************************************************************
4676       EmacsApp delegate implementation
4678    ************************************************************************** */
4680 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4681 /* --------------------------------------------------------------------------
4682      When application is loaded, terminate event loop in ns_term_init
4683    -------------------------------------------------------------------------- */
4685   NSTRACE (applicationDidFinishLaunching);
4686 #ifdef NS_IMPL_GNUSTEP
4687   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
4688 #endif
4689   [NSApp setServicesProvider: NSApp];
4691   [self antialiasThresholdDidChange:nil];
4692 #ifdef NS_IMPL_COCOA
4693 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
4694   [[NSNotificationCenter defaultCenter]
4695     addObserver:self
4696        selector:@selector(antialiasThresholdDidChange:)
4697            name:NSAntialiasThresholdChangedNotification
4698          object:nil];
4699 #endif
4700 #endif
4702   ns_send_appdefined (-2);
4705 - (void)antialiasThresholdDidChange:(NSNotification *)notification
4707 #ifdef NS_IMPL_COCOA
4708 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
4709   macfont_update_antialias_threshold ();
4710 #endif
4711 #endif
4715 /* Termination sequences:
4716     C-x C-c:
4717     Cmd-Q:
4718     MenuBar | File | Exit:
4719     Select Quit from App menubar:
4720         -terminate
4721         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4722         ns_term_shutdown()
4724     Select Quit from Dock menu:
4725     Logout attempt:
4726         -appShouldTerminate
4727           Cancel -> Nothing else
4728           Accept ->
4730           -terminate
4731           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4732           ns_term_shutdown()
4736 - (void) terminate: (id)sender
4738   struct frame *emacsframe = SELECTED_FRAME ();
4740   if (!emacs_event)
4741     return;
4743   emacs_event->kind = NS_NONKEY_EVENT;
4744   emacs_event->code = KEY_NS_POWER_OFF;
4745   emacs_event->arg = Qt; /* mark as non-key event */
4746   EV_TRAILER ((id)nil);
4750 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4752   int ret;
4754   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4755     return NSTerminateNow;
4757     ret = NSRunAlertPanel(ns_app_name,
4758                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4759                           @"Save Buffers and Exit", @"Cancel", nil);
4761     if (ret == NSAlertDefaultReturn)
4762         return NSTerminateNow;
4763     else if (ret == NSAlertAlternateReturn)
4764         return NSTerminateCancel;
4765     return NSTerminateNow;  /* just in case */
4768 static int
4769 not_in_argv (NSString *arg)
4771   int k;
4772   const char *a = [arg UTF8String];
4773   for (k = 1; k < initial_argc; ++k)
4774     if (strcmp (a, initial_argv[k]) == 0) return 0;
4775   return 1;
4778 /*   Notification from the Workspace to open a file */
4779 - (BOOL)application: sender openFile: (NSString *)file
4781   if (ns_do_open_file || not_in_argv (file))
4782     [ns_pending_files addObject: file];
4783   return YES;
4787 /*   Open a file as a temporary file */
4788 - (BOOL)application: sender openTempFile: (NSString *)file
4790   if (ns_do_open_file || not_in_argv (file))
4791     [ns_pending_files addObject: file];
4792   return YES;
4796 /*   Notification from the Workspace to open a file noninteractively (?) */
4797 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4799   if (ns_do_open_file || not_in_argv (file))
4800     [ns_pending_files addObject: file];
4801   return YES;
4804 /*   Notification from the Workspace to open multiple files */
4805 - (void)application: sender openFiles: (NSArray *)fileList
4807   NSEnumerator *files = [fileList objectEnumerator];
4808   NSString *file;
4809   /* Don't open files from the command line unconditionally,
4810      Cocoa parses the command line wrong, --option value tries to open value
4811      if --option is the last option.  */
4812   while ((file = [files nextObject]) != nil)
4813     if (ns_do_open_file || not_in_argv (file))
4814       [ns_pending_files addObject: file];
4816   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4821 /* Handle dock menu requests.  */
4822 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4824   return dockMenu;
4828 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4829 - (void)applicationWillBecomeActive: (NSNotification *)notification
4831   //ns_app_active=YES;
4833 - (void)applicationDidBecomeActive: (NSNotification *)notification
4835   NSTRACE (applicationDidBecomeActive);
4837 #ifdef NS_IMPL_GNUSTEP
4838   if (! applicationDidFinishLaunchingCalled)
4839     [self applicationDidFinishLaunching:notification];
4840 #endif
4841   //ns_app_active=YES;
4843   ns_update_auto_hide_menu_bar ();
4844   // No constraining takes place when the application is not active.
4845   ns_constrain_all_frames ();
4847 - (void)applicationDidResignActive: (NSNotification *)notification
4849   //ns_app_active=NO;
4850   ns_send_appdefined (-1);
4855 /* ==========================================================================
4857     EmacsApp aux handlers for managing event loop
4859    ========================================================================== */
4862 - (void)timeout_handler: (NSTimer *)timedEntry
4863 /* --------------------------------------------------------------------------
4864      The timeout specified to ns_select has passed.
4865    -------------------------------------------------------------------------- */
4867   /*NSTRACE (timeout_handler); */
4868   ns_send_appdefined (-2);
4871 #ifdef NS_IMPL_GNUSTEP
4872 - (void)sendFromMainThread:(id)unused
4874   ns_send_appdefined (nextappdefined);
4876 #endif
4878 - (void)fd_handler:(id)unused
4879 /* --------------------------------------------------------------------------
4880      Check data waiting on file descriptors and terminate if so
4881    -------------------------------------------------------------------------- */
4883   int result;
4884   int waiting = 1, nfds;
4885   char c;
4887   fd_set readfds, writefds, *wfds;
4888   struct timespec timeout, *tmo;
4889   NSAutoreleasePool *pool = nil;
4891   /* NSTRACE (fd_handler); */
4893   for (;;)
4894     {
4895       [pool release];
4896       pool = [[NSAutoreleasePool alloc] init];
4898       if (waiting)
4899         {
4900           fd_set fds;
4901           FD_ZERO (&fds);
4902           FD_SET (selfds[0], &fds);
4903           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4904           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4905             waiting = 0;
4906         }
4907       else
4908         {
4909           pthread_mutex_lock (&select_mutex);
4910           nfds = select_nfds;
4912           if (select_valid & SELECT_HAVE_READ)
4913             readfds = select_readfds;
4914           else
4915             FD_ZERO (&readfds);
4917           if (select_valid & SELECT_HAVE_WRITE)
4918             {
4919               writefds = select_writefds;
4920               wfds = &writefds;
4921             }
4922           else
4923             wfds = NULL;
4924           if (select_valid & SELECT_HAVE_TMO)
4925             {
4926               timeout = select_timeout;
4927               tmo = &timeout;
4928             }
4929           else
4930             tmo = NULL;
4932           pthread_mutex_unlock (&select_mutex);
4934           FD_SET (selfds[0], &readfds);
4935           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4937           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4939           if (result == 0)
4940             ns_send_appdefined (-2);
4941           else if (result > 0)
4942             {
4943               if (FD_ISSET (selfds[0], &readfds))
4944                 {
4945                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4946                     waiting = 1;
4947                 }
4948               else
4949                 {
4950                   pthread_mutex_lock (&select_mutex);
4951                   if (select_valid & SELECT_HAVE_READ)
4952                     select_readfds = readfds;
4953                   if (select_valid & SELECT_HAVE_WRITE)
4954                     select_writefds = writefds;
4955                   if (select_valid & SELECT_HAVE_TMO)
4956                     select_timeout = timeout;
4957                   pthread_mutex_unlock (&select_mutex);
4959                   ns_send_appdefined (result);
4960                 }
4961             }
4962           waiting = 1;
4963         }
4964     }
4969 /* ==========================================================================
4971     Service provision
4973    ========================================================================== */
4975 /* called from system: queue for next pass through event loop */
4976 - (void)requestService: (NSPasteboard *)pboard
4977               userData: (NSString *)userData
4978                  error: (NSString **)error
4980   [ns_pending_service_names addObject: userData];
4981   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4982       SSDATA (ns_string_from_pasteboard (pboard))]];
4986 /* called from ns_read_socket to clear queue */
4987 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4989   struct frame *emacsframe = SELECTED_FRAME ();
4990   NSEvent *theEvent = [NSApp currentEvent];
4992   if (!emacs_event)
4993     return NO;
4995   emacs_event->kind = NS_NONKEY_EVENT;
4996   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4997   ns_input_spi_name = build_string ([name UTF8String]);
4998   ns_input_spi_arg = build_string ([arg UTF8String]);
4999   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5000   EV_TRAILER (theEvent);
5002   return YES;
5006 @end  /* EmacsApp */
5010 /* ==========================================================================
5012     EmacsView implementation
5014    ========================================================================== */
5017 @implementation EmacsView
5019 /* needed to inform when window closed from LISP */
5020 - (void) setWindowClosing: (BOOL)closing
5022   windowClosing = closing;
5026 - (void)dealloc
5028   NSTRACE (EmacsView_dealloc);
5029   [toolbar release];
5030   if (fs_state == FULLSCREEN_BOTH)
5031     [nonfs_window release];
5032   [super dealloc];
5036 /* called on font panel selection */
5037 - (void)changeFont: (id)sender
5039   NSEvent *e = [[self window] currentEvent];
5040   struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5041   struct font *font = face->font;
5042   id newFont;
5043   CGFloat size;
5044   NSFont *nsfont;
5046   NSTRACE (changeFont);
5048   if (!emacs_event)
5049     return;
5051   if (EQ (font->driver->type, Qns))
5052     nsfont = ((struct nsfont_info *)font)->nsfont;
5053 #ifdef NS_IMPL_COCOA
5054 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
5055   else
5056     nsfont = (NSFont *) macfont_get_nsctfont (font);
5057 #endif
5058 #endif
5060   if ((newFont = [sender convertFont: nsfont]))
5061     {
5062       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5064       emacs_event->kind = NS_NONKEY_EVENT;
5065       emacs_event->modifiers = 0;
5066       emacs_event->code = KEY_NS_CHANGE_FONT;
5068       size = [newFont pointSize];
5069       ns_input_fontsize = make_number (lrint (size));
5070       ns_input_font = build_string ([[newFont familyName] UTF8String]);
5071       EV_TRAILER (e);
5072     }
5076 - (BOOL)acceptsFirstResponder
5078   NSTRACE (acceptsFirstResponder);
5079   return YES;
5083 - (void)resetCursorRects
5085   NSRect visible = [self visibleRect];
5086   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5087   NSTRACE (resetCursorRects);
5089   if (currentCursor == nil)
5090     currentCursor = [NSCursor arrowCursor];
5092   if (!NSIsEmptyRect (visible))
5093     [self addCursorRect: visible cursor: currentCursor];
5094   [currentCursor setOnMouseEntered: YES];
5099 /*****************************************************************************/
5100 /* Keyboard handling. */
5101 #define NS_KEYLOG 0
5103 - (void)keyDown: (NSEvent *)theEvent
5105   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5106   int code;
5107   unsigned fnKeysym = 0;
5108   static NSMutableArray *nsEvArray;
5109 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5110   static BOOL firstTime = YES;
5111 #endif
5112   int left_is_none;
5113   unsigned int flags = [theEvent modifierFlags];
5115   NSTRACE (keyDown);
5117   /* Rhapsody and OS X give up and down events for the arrow keys */
5118   if (ns_fake_keydown == YES)
5119     ns_fake_keydown = NO;
5120   else if ([theEvent type] != NSKeyDown)
5121     return;
5123   if (!emacs_event)
5124     return;
5126  if (![[self window] isKeyWindow]
5127      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5128      /* we must avoid an infinite loop here. */
5129      && (EmacsView *)[[theEvent window] delegate] != self)
5130    {
5131      /* XXX: There is an occasional condition in which, when Emacs display
5132          updates a different frame from the current one, and temporarily
5133          selects it, then processes some interrupt-driven input
5134          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5135          for some reason that window has its first responder set to the NSView
5136          most recently updated (I guess), which is not the correct one. */
5137      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5138      return;
5139    }
5141   if (nsEvArray == nil)
5142     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5144   [NSCursor setHiddenUntilMouseMoves: YES];
5146   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5147     {
5148       clear_mouse_face (hlinfo);
5149       hlinfo->mouse_face_hidden = 1;
5150     }
5152   if (!processingCompose)
5153     {
5154       /* When using screen sharing, no left or right information is sent,
5155          so use Left key in those cases.  */
5156       int is_left_key, is_right_key;
5158       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5159         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5161       /* (Carbon way: [theEvent keyCode]) */
5163       /* is it a "function key"? */
5164       /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5165          flag set (this is probably a bug in the OS).
5166       */
5167       if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5168         {
5169           fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5170         }
5171       if (fnKeysym == 0)
5172         {
5173           fnKeysym = ns_convert_key (code);
5174         }
5176       if (fnKeysym)
5177         {
5178           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5179              because Emacs treats Delete and KP-Delete same (in simple.el). */
5180           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5181 #ifdef NS_IMPL_GNUSTEP
5182               /*  GNUstep uses incompatible keycodes, even for those that are
5183                   supposed to be hardware independent.  Just check for delete.
5184                   Keypad delete does not have keysym 0xFFFF.
5185                   See http://savannah.gnu.org/bugs/?25395
5186               */
5187               || (fnKeysym == 0xFFFF && code == 127)
5188 #endif
5189             )
5190             code = 0xFF08; /* backspace */
5191           else
5192             code = fnKeysym;
5193         }
5195       /* are there modifiers? */
5196       emacs_event->modifiers = 0;
5198       if (flags & NSHelpKeyMask)
5199           emacs_event->modifiers |= hyper_modifier;
5201       if (flags & NSShiftKeyMask)
5202         emacs_event->modifiers |= shift_modifier;
5204       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5205       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5206         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5208       if (is_right_key)
5209         emacs_event->modifiers |= parse_solitary_modifier
5210           (EQ (ns_right_command_modifier, Qleft)
5211            ? ns_command_modifier
5212            : ns_right_command_modifier);
5214       if (is_left_key)
5215         {
5216           emacs_event->modifiers |= parse_solitary_modifier
5217             (ns_command_modifier);
5219           /* if super (default), take input manager's word so things like
5220              dvorak / qwerty layout work */
5221           if (EQ (ns_command_modifier, Qsuper)
5222               && !fnKeysym
5223               && [[theEvent characters] length] != 0)
5224             {
5225               /* XXX: the code we get will be unshifted, so if we have
5226                  a shift modifier, must convert ourselves */
5227               if (!(flags & NSShiftKeyMask))
5228                 code = [[theEvent characters] characterAtIndex: 0];
5229 #if 0
5230               /* this is ugly and also requires linking w/Carbon framework
5231                  (for LMGetKbdType) so for now leave this rare (?) case
5232                  undealt with.. in future look into CGEvent methods */
5233               else
5234                 {
5235                   long smv = GetScriptManagerVariable (smKeyScript);
5236                   Handle uchrHandle = GetResource
5237                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5238                   UInt32 dummy = 0;
5239                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5240                                  [[theEvent characters] characterAtIndex: 0],
5241                                  kUCKeyActionDisplay,
5242                                  (flags & ~NSCommandKeyMask) >> 8,
5243                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5244                                  &dummy, 1, &dummy, &code);
5245                   code &= 0xFF;
5246                 }
5247 #endif
5248             }
5249         }
5251       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5252       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5253         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5255       if (is_right_key)
5256           emacs_event->modifiers |= parse_solitary_modifier
5257               (EQ (ns_right_control_modifier, Qleft)
5258                ? ns_control_modifier
5259                : ns_right_control_modifier);
5261       if (is_left_key)
5262         emacs_event->modifiers |= parse_solitary_modifier
5263           (ns_control_modifier);
5265       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5266           emacs_event->modifiers |=
5267             parse_solitary_modifier (ns_function_modifier);
5269       left_is_none = NILP (ns_alternate_modifier)
5270         || EQ (ns_alternate_modifier, Qnone);
5272       is_right_key = (flags & NSRightAlternateKeyMask)
5273         == NSRightAlternateKeyMask;
5274       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5275         || (! is_right_key
5276             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5278       if (is_right_key)
5279         {
5280           if ((NILP (ns_right_alternate_modifier)
5281                || EQ (ns_right_alternate_modifier, Qnone)
5282                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5283               && !fnKeysym)
5284             {   /* accept pre-interp alt comb */
5285               if ([[theEvent characters] length] > 0)
5286                 code = [[theEvent characters] characterAtIndex: 0];
5287               /*HACK: clear lone shift modifier to stop next if from firing */
5288               if (emacs_event->modifiers == shift_modifier)
5289                 emacs_event->modifiers = 0;
5290             }
5291           else
5292             emacs_event->modifiers |= parse_solitary_modifier
5293               (EQ (ns_right_alternate_modifier, Qleft)
5294                ? ns_alternate_modifier
5295                : ns_right_alternate_modifier);
5296         }
5298       if (is_left_key) /* default = meta */
5299         {
5300           if (left_is_none && !fnKeysym)
5301             {   /* accept pre-interp alt comb */
5302               if ([[theEvent characters] length] > 0)
5303                 code = [[theEvent characters] characterAtIndex: 0];
5304               /*HACK: clear lone shift modifier to stop next if from firing */
5305               if (emacs_event->modifiers == shift_modifier)
5306                 emacs_event->modifiers = 0;
5307             }
5308           else
5309               emacs_event->modifiers |=
5310                 parse_solitary_modifier (ns_alternate_modifier);
5311         }
5313   if (NS_KEYLOG)
5314     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5315              code, fnKeysym, flags, emacs_event->modifiers);
5317       /* if it was a function key or had modifiers, pass it directly to emacs */
5318       if (fnKeysym || (emacs_event->modifiers
5319                        && (emacs_event->modifiers != shift_modifier)
5320                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5321 /*[[theEvent characters] length] */
5322         {
5323           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5324           if (code < 0x20)
5325             code |= (1<<28)|(3<<16);
5326           else if (code == 0x7f)
5327             code |= (1<<28)|(3<<16);
5328           else if (!fnKeysym)
5329             emacs_event->kind = code > 0xFF
5330               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5332           emacs_event->code = code;
5333           EV_TRAILER (theEvent);
5334           processingCompose = NO;
5335           return;
5336         }
5337     }
5340 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5341   /* if we get here we should send the key for input manager processing */
5342   /* Disable warning, there is nothing a user can do about it anyway, and
5343      it does not seem to matter.  */
5344 #if 0
5345   if (firstTime && [[NSInputManager currentInputManager]
5346                      wantsToDelayTextChangeNotifications] == NO)
5347     fprintf (stderr,
5348           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5349 #endif
5350   firstTime = NO;
5351 #endif
5352   if (NS_KEYLOG && !processingCompose)
5353     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5355   processingCompose = YES;
5356   [nsEvArray addObject: theEvent];
5357   [self interpretKeyEvents: nsEvArray];
5358   [nsEvArray removeObject: theEvent];
5362 #ifdef NS_IMPL_COCOA
5363 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5364    decided not to send key-down for.
5365    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5366    This only applies on Tiger and earlier.
5367    If it matches one of these, send it on to keyDown. */
5368 -(void)keyUp: (NSEvent *)theEvent
5370   int flags = [theEvent modifierFlags];
5371   int code = [theEvent keyCode];
5372   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5373       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5374     {
5375       if (NS_KEYLOG)
5376         fprintf (stderr, "keyUp: passed test");
5377       ns_fake_keydown = YES;
5378       [self keyDown: theEvent];
5379     }
5381 #endif
5384 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5387 /* <NSTextInput>: called when done composing;
5388    NOTE: also called when we delete over working text, followed immed.
5389          by doCommandBySelector: deleteBackward: */
5390 - (void)insertText: (id)aString
5392   int code;
5393   int len = [(NSString *)aString length];
5394   int i;
5396   if (NS_KEYLOG)
5397     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5398   processingCompose = NO;
5400   if (!emacs_event)
5401     return;
5403   /* first, clear any working text */
5404   if (workingText != nil)
5405     [self deleteWorkingText];
5407   /* now insert the string as keystrokes */
5408   for (i =0; i<len; i++)
5409     {
5410       code = [aString characterAtIndex: i];
5411       /* TODO: still need this? */
5412       if (code == 0x2DC)
5413         code = '~'; /* 0x7E */
5414       if (code != 32) /* Space */
5415         emacs_event->modifiers = 0;
5416       emacs_event->kind
5417         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5418       emacs_event->code = code;
5419       EV_TRAILER ((id)nil);
5420     }
5424 /* <NSTextInput>: inserts display of composing characters */
5425 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5427   NSString *str = [aString respondsToSelector: @selector (string)] ?
5428     [aString string] : aString;
5429   if (NS_KEYLOG)
5430     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5431            str, (unsigned long)[str length],
5432            (unsigned long)selRange.length,
5433            (unsigned long)selRange.location);
5435   if (workingText != nil)
5436     [self deleteWorkingText];
5437   if ([str length] == 0)
5438     return;
5440   if (!emacs_event)
5441     return;
5443   processingCompose = YES;
5444   workingText = [str copy];
5445   ns_working_text = build_string ([workingText UTF8String]);
5447   emacs_event->kind = NS_TEXT_EVENT;
5448   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5449   EV_TRAILER ((id)nil);
5453 /* delete display of composing characters [not in <NSTextInput>] */
5454 - (void)deleteWorkingText
5456   if (workingText == nil)
5457     return;
5458   if (NS_KEYLOG)
5459     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5460   [workingText release];
5461   workingText = nil;
5462   processingCompose = NO;
5464   if (!emacs_event)
5465     return;
5467   emacs_event->kind = NS_TEXT_EVENT;
5468   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5469   EV_TRAILER ((id)nil);
5473 - (BOOL)hasMarkedText
5475   return workingText != nil;
5479 - (NSRange)markedRange
5481   NSRange rng = workingText != nil
5482     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5483   if (NS_KEYLOG)
5484     NSLog (@"markedRange request");
5485   return rng;
5489 - (void)unmarkText
5491   if (NS_KEYLOG)
5492     NSLog (@"unmark (accept) text");
5493   [self deleteWorkingText];
5494   processingCompose = NO;
5498 /* used to position char selection windows, etc. */
5499 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5501   NSRect rect;
5502   NSPoint pt;
5503   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5504   if (NS_KEYLOG)
5505     NSLog (@"firstRectForCharRange request");
5507   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5508   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5509   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5510   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5511                                        +FRAME_LINE_HEIGHT (emacsframe));
5513   pt = [self convertPoint: pt toView: nil];
5514   pt = [[self window] convertBaseToScreen: pt];
5515   rect.origin = pt;
5516   return rect;
5520 - (NSInteger)conversationIdentifier
5522   return (NSInteger)self;
5526 - (void)doCommandBySelector: (SEL)aSelector
5528   if (NS_KEYLOG)
5529     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5531   processingCompose = NO;
5532   if (aSelector == @selector (deleteBackward:))
5533     {
5534       /* happens when user backspaces over an ongoing composition:
5535          throw a 'delete' into the event queue */
5536       if (!emacs_event)
5537         return;
5538       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5539       emacs_event->code = 0xFF08;
5540       EV_TRAILER ((id)nil);
5541     }
5544 - (NSArray *)validAttributesForMarkedText
5546   static NSArray *arr = nil;
5547   if (arr == nil) arr = [NSArray new];
5548  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5549   return arr;
5552 - (NSRange)selectedRange
5554   if (NS_KEYLOG)
5555     NSLog (@"selectedRange request");
5556   return NSMakeRange (NSNotFound, 0);
5559 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5560     GNUSTEP_GUI_MINOR_VERSION > 22
5561 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5562 #else
5563 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5564 #endif
5566   if (NS_KEYLOG)
5567     NSLog (@"characterIndexForPoint request");
5568   return 0;
5571 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5573   static NSAttributedString *str = nil;
5574   if (str == nil) str = [NSAttributedString new];
5575   if (NS_KEYLOG)
5576     NSLog (@"attributedSubstringFromRange request");
5577   return str;
5580 /* End <NSTextInput> impl. */
5581 /*****************************************************************************/
5584 /* This is what happens when the user presses a mouse button.  */
5585 - (void)mouseDown: (NSEvent *)theEvent
5587   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5588   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5590   NSTRACE (mouseDown);
5592   [self deleteWorkingText];
5594   if (!emacs_event)
5595     return;
5597   dpyinfo->last_mouse_frame = emacsframe;
5598   /* appears to be needed to prevent spurious movement events generated on
5599      button clicks */
5600   emacsframe->mouse_moved = 0;
5602   if ([theEvent type] == NSScrollWheel)
5603     {
5604       CGFloat delta = [theEvent deltaY];
5605       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5606       if (delta == 0)
5607         {
5608           delta = [theEvent deltaX];
5609           if (delta == 0)
5610             {
5611               NSTRACE (deltaIsZero);
5612               return;
5613             }
5614           emacs_event->kind = HORIZ_WHEEL_EVENT;
5615         }
5616       else
5617         emacs_event->kind = WHEEL_EVENT;
5619       emacs_event->code = 0;
5620       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5621         ((delta > 0) ? up_modifier : down_modifier);
5622     }
5623   else
5624     {
5625       emacs_event->kind = MOUSE_CLICK_EVENT;
5626       emacs_event->code = EV_BUTTON (theEvent);
5627       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5628                              | EV_UDMODIFIERS (theEvent);
5629     }
5630   XSETINT (emacs_event->x, lrint (p.x));
5631   XSETINT (emacs_event->y, lrint (p.y));
5632   EV_TRAILER (theEvent);
5636 - (void)rightMouseDown: (NSEvent *)theEvent
5638   NSTRACE (rightMouseDown);
5639   [self mouseDown: theEvent];
5643 - (void)otherMouseDown: (NSEvent *)theEvent
5645   NSTRACE (otherMouseDown);
5646   [self mouseDown: theEvent];
5650 - (void)mouseUp: (NSEvent *)theEvent
5652   NSTRACE (mouseUp);
5653   [self mouseDown: theEvent];
5657 - (void)rightMouseUp: (NSEvent *)theEvent
5659   NSTRACE (rightMouseUp);
5660   [self mouseDown: theEvent];
5664 - (void)otherMouseUp: (NSEvent *)theEvent
5666   NSTRACE (otherMouseUp);
5667   [self mouseDown: theEvent];
5671 - (void) scrollWheel: (NSEvent *)theEvent
5673   NSTRACE (scrollWheel);
5674   [self mouseDown: theEvent];
5678 /* Tell emacs the mouse has moved. */
5679 - (void)mouseMoved: (NSEvent *)e
5681   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5682   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5683   Lisp_Object frame;
5684   NSPoint pt;
5686 //  NSTRACE (mouseMoved);
5688   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
5689   pt = [self convertPoint: [e locationInWindow] fromView: nil];
5690   dpyinfo->last_mouse_motion_x = pt.x;
5691   dpyinfo->last_mouse_motion_y = pt.y;
5693   /* update any mouse face */
5694   if (hlinfo->mouse_face_hidden)
5695     {
5696       hlinfo->mouse_face_hidden = 0;
5697       clear_mouse_face (hlinfo);
5698     }
5700   /* tooltip handling */
5701   previous_help_echo_string = help_echo_string;
5702   help_echo_string = Qnil;
5704   if (!NILP (Vmouse_autoselect_window))
5705     {
5706       NSTRACE (mouse_autoselect_window);
5707       static Lisp_Object last_mouse_window;
5708       Lisp_Object window
5709         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
5711       if (WINDOWP (window)
5712           && !EQ (window, last_mouse_window)
5713           && !EQ (window, selected_window)
5714           && (focus_follows_mouse
5715               || (EQ (XWINDOW (window)->frame,
5716                       XWINDOW (selected_window)->frame))))
5717         {
5718           NSTRACE (in_window);
5719           emacs_event->kind = SELECT_WINDOW_EVENT;
5720           emacs_event->frame_or_window = window;
5721           EV_TRAILER2 (e);
5722         }
5723       /* Remember the last window where we saw the mouse.  */
5724       last_mouse_window = window;
5725     }
5727   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
5728     help_echo_string = previous_help_echo_string;
5730   XSETFRAME (frame, emacsframe);
5731   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5732     {
5733       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5734          (note_mouse_highlight), which is called through the
5735          note_mouse_movement () call above */
5736       any_help_event_p = YES;
5737       gen_help_event (help_echo_string, frame, help_echo_window,
5738                       help_echo_object, help_echo_pos);
5739     }
5741   if (emacsframe->mouse_moved && send_appdefined)
5742     ns_send_appdefined (-1);
5746 - (void)mouseDragged: (NSEvent *)e
5748   NSTRACE (mouseDragged);
5749   [self mouseMoved: e];
5753 - (void)rightMouseDragged: (NSEvent *)e
5755   NSTRACE (rightMouseDragged);
5756   [self mouseMoved: e];
5760 - (void)otherMouseDragged: (NSEvent *)e
5762   NSTRACE (otherMouseDragged);
5763   [self mouseMoved: e];
5767 - (BOOL)windowShouldClose: (id)sender
5769   NSEvent *e =[[self window] currentEvent];
5771   NSTRACE (windowShouldClose);
5772   windowClosing = YES;
5773   if (!emacs_event)
5774     return NO;
5775   emacs_event->kind = DELETE_WINDOW_EVENT;
5776   emacs_event->modifiers = 0;
5777   emacs_event->code = 0;
5778   EV_TRAILER (e);
5779   /* Don't close this window, let this be done from lisp code.  */
5780   return NO;
5783 - (void) updateFrameSize: (BOOL) delay;
5785   NSWindow *window = [self window];
5786   NSRect wr = [window frame];
5787   int extra = 0;
5788   int oldc = cols, oldr = rows;
5789   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
5790   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5791   int neww, newh;
5793   NSTRACE (updateFrameSize);
5794   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
5796   if (! [self isFullscreen])
5797     {
5798 #ifdef NS_IMPL_GNUSTEP
5799       // GNUstep does not always update the tool bar height.  Force it.
5800       if (toolbar) update_frame_tool_bar (emacsframe);
5801 #endif
5803       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5804         + FRAME_TOOLBAR_HEIGHT (emacsframe);
5805     }
5807   if (wait_for_tool_bar)
5808     {
5809       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
5810         return;
5811       wait_for_tool_bar = NO;
5812     }
5814   neww = (int)wr.size.width - emacsframe->border_width;
5815   newh = (int)wr.size.height - extra;
5817   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
5818   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
5820   if (cols < MINWIDTH)
5821     cols = MINWIDTH;
5823   if (rows < MINHEIGHT)
5824     rows = MINHEIGHT;
5826   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5827     {
5828       NSView *view = FRAME_NS_VIEW (emacsframe);
5829       NSWindow *win = [view window];
5830       NSSize sz = [win resizeIncrements];
5832       change_frame_size (emacsframe,
5833                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
5834                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
5835                          0, delay, 0, 1);
5836       SET_FRAME_GARBAGED (emacsframe);
5837       cancel_mouse_face (emacsframe);
5839       // Did resize increments change because of a font change?
5840       if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5841           sz.height != FRAME_LINE_HEIGHT (emacsframe))
5842         {
5843           sz.width = FRAME_COLUMN_WIDTH (emacsframe);
5844           sz.height = FRAME_LINE_HEIGHT (emacsframe);
5845           [win setResizeIncrements: sz];
5847           NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
5848         }
5850       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5851       [self windowDidMove:nil];   // Update top/left.
5852     }
5855 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5856 /* normalize frame to gridded text size */
5858   int extra = 0;
5860   NSTRACE (windowWillResize);
5861   NSTRACE_SIZE ("Original size", frameSize);
5862 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5864   if (fs_state == FULLSCREEN_MAXIMIZED
5865       && (maximized_width != (int)frameSize.width
5866           || maximized_height != (int)frameSize.height))
5867     [self setFSValue: FULLSCREEN_NONE];
5868   else if (fs_state == FULLSCREEN_WIDTH
5869            && maximized_width != (int)frameSize.width)
5870     [self setFSValue: FULLSCREEN_NONE];
5871   else if (fs_state == FULLSCREEN_HEIGHT
5872            && maximized_height != (int)frameSize.height)
5873     [self setFSValue: FULLSCREEN_NONE];
5874   if (fs_state == FULLSCREEN_NONE)
5875     maximized_width = maximized_height = -1;
5877   if (! [self isFullscreen])
5878     {
5879       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5880         + FRAME_TOOLBAR_HEIGHT (emacsframe);
5881     }
5883   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
5884   if (cols < MINWIDTH)
5885     cols = MINWIDTH;
5887   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5888                                            frameSize.height - extra);
5889   if (rows < MINHEIGHT)
5890     rows = MINHEIGHT;
5891 #ifdef NS_IMPL_COCOA
5892   {
5893     /* this sets window title to have size in it; the wm does this under GS */
5894     NSRect r = [[self window] frame];
5895     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5896       {
5897         if (old_title != 0)
5898           {
5899             xfree (old_title);
5900             old_title = 0;
5901           }
5902       }
5903     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5904       {
5905         char *size_title;
5906         NSWindow *window = [self window];
5907         if (old_title == 0)
5908           {
5909             char *t = strdup ([[[self window] title] UTF8String]);
5910             char *pos = strstr (t, "  â€”  ");
5911             if (pos)
5912               *pos = '\0';
5913             old_title = t;
5914           }
5915         size_title = xmalloc (strlen (old_title) + 40);
5916         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5917         [window setTitle: [NSString stringWithUTF8String: size_title]];
5918         [window display];
5919         xfree (size_title);
5920       }
5921   }
5922 #endif /* NS_IMPL_COCOA */
5923 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5925   return frameSize;
5929 - (void)windowDidResize: (NSNotification *)notification
5931   if (! [self fsIsNative])
5932     {
5933       NSWindow *theWindow = [notification object];
5934       /* We can get notification on the non-FS window when in
5935          fullscreen mode.  */
5936       if ([self window] != theWindow) return;
5937     }
5939 #ifdef NS_IMPL_GNUSTEP
5940   NSWindow *theWindow = [notification object];
5942    /* In GNUstep, at least currently, it's possible to get a didResize
5943       without getting a willResize.. therefore we need to act as if we got
5944       the willResize now */
5945   NSSize sz = [theWindow frame].size;
5946   sz = [self windowWillResize: theWindow toSize: sz];
5947 #endif /* NS_IMPL_GNUSTEP */
5949   NSTRACE (windowDidResize);
5950 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5952 if (cols > 0 && rows > 0)
5953     {
5954       [self updateFrameSize: YES];
5955     }
5957   ns_send_appdefined (-1);
5960 #ifdef NS_IMPL_COCOA
5961 - (void)viewDidEndLiveResize
5963   [super viewDidEndLiveResize];
5964   if (old_title != 0)
5965     {
5966       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
5967       xfree (old_title);
5968       old_title = 0;
5969     }
5970   maximizing_resize = NO;
5972 #endif /* NS_IMPL_COCOA */
5975 - (void)windowDidBecomeKey: (NSNotification *)notification
5976 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5978   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5979   struct frame *old_focus = dpyinfo->x_focus_frame;
5981   NSTRACE (windowDidBecomeKey);
5983   if (emacsframe != old_focus)
5984     dpyinfo->x_focus_frame = emacsframe;
5986   ns_frame_rehighlight (emacsframe);
5988   if (emacs_event)
5989     {
5990       emacs_event->kind = FOCUS_IN_EVENT;
5991       EV_TRAILER ((id)nil);
5992     }
5996 - (void)windowDidResignKey: (NSNotification *)notification
5997 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5999   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6000   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6001   NSTRACE (windowDidResignKey);
6003   if (is_focus_frame)
6004     dpyinfo->x_focus_frame = 0;
6006   emacsframe->mouse_moved = 0;
6007   ns_frame_rehighlight (emacsframe);
6009   /* FIXME: for some reason needed on second and subsequent clicks away
6010             from sole-frame Emacs to get hollow box to show */
6011   if (!windowClosing && [[self window] isVisible] == YES)
6012     {
6013       x_update_cursor (emacsframe, 1);
6014       x_set_frame_alpha (emacsframe);
6015     }
6017   if (any_help_event_p)
6018     {
6019       Lisp_Object frame;
6020       XSETFRAME (frame, emacsframe);
6021       help_echo_string = Qnil;
6022       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6023     }
6025   if (emacs_event && is_focus_frame)
6026     {
6027       [self deleteWorkingText];
6028       emacs_event->kind = FOCUS_OUT_EVENT;
6029       EV_TRAILER ((id)nil);
6030     }
6034 - (void)windowWillMiniaturize: sender
6036   NSTRACE (windowWillMiniaturize);
6040 - (BOOL)isFlipped
6042   return YES;
6046 - (BOOL)isOpaque
6048   return NO;
6052 - initFrameFromEmacs: (struct frame *)f
6054   NSRect r, wr;
6055   Lisp_Object tem;
6056   NSWindow *win;
6057   NSSize sz;
6058   NSColor *col;
6059   NSString *name;
6061   NSTRACE (initFrameFromEmacs);
6063   windowClosing = NO;
6064   processingCompose = NO;
6065   scrollbarsNeedingUpdate = 0;
6066   fs_state = FULLSCREEN_NONE;
6067   fs_before_fs = next_maximized = -1;
6068 #ifdef HAVE_NATIVE_FS
6069   fs_is_native = ns_use_native_fullscreen;
6070 #else
6071   fs_is_native = NO;
6072 #endif
6073   maximized_width = maximized_height = -1;
6074   nonfs_window = nil;
6076 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
6078   ns_userRect = NSMakeRect (0, 0, 0, 0);
6079   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6080                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6081   [self initWithFrame: r];
6082   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6084   FRAME_NS_VIEW (f) = self;
6085   emacsframe = f;
6086 #ifdef NS_IMPL_COCOA
6087   old_title = 0;
6088   maximizing_resize = NO;
6089 #endif
6091   win = [[EmacsWindow alloc]
6092             initWithContentRect: r
6093                       styleMask: (NSResizableWindowMask |
6094 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6095                                   NSTitledWindowMask |
6096 #endif
6097                                   NSMiniaturizableWindowMask |
6098                                   NSClosableWindowMask)
6099                         backing: NSBackingStoreBuffered
6100                           defer: YES];
6102 #ifdef HAVE_NATIVE_FS
6103     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6104 #endif
6106   wr = [win frame];
6107   bwidth = f->border_width = wr.size.width - r.size.width;
6108   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6110   [win setAcceptsMouseMovedEvents: YES];
6111   [win setDelegate: self];
6112   [win useOptimizedDrawing: YES];
6114   sz.width = FRAME_COLUMN_WIDTH (f);
6115   sz.height = FRAME_LINE_HEIGHT (f);
6116   [win setResizeIncrements: sz];
6118   [[win contentView] addSubview: self];
6120   if (ns_drag_types)
6121     [self registerForDraggedTypes: ns_drag_types];
6123   tem = f->name;
6124   name = [NSString stringWithUTF8String:
6125                    NILP (tem) ? "Emacs" : SSDATA (tem)];
6126   [win setTitle: name];
6128   /* toolbar support */
6129   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6130                          [NSString stringWithFormat: @"Emacs Frame %d",
6131                                    ns_window_num]];
6132   [win setToolbar: toolbar];
6133   [toolbar setVisible: NO];
6135   /* Don't set frame garbaged until tool bar is up to date?
6136      This avoids an extra clear and redraw (flicker) at frame creation.  */
6137   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6138   else wait_for_tool_bar = NO;
6141 #ifdef NS_IMPL_COCOA
6142   {
6143     NSButton *toggleButton;
6144   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6145   [toggleButton setTarget: self];
6146   [toggleButton setAction: @selector (toggleToolbar: )];
6147   }
6148 #endif
6149   FRAME_TOOLBAR_HEIGHT (f) = 0;
6151   tem = f->icon_name;
6152   if (!NILP (tem))
6153     [win setMiniwindowTitle:
6154            [NSString stringWithUTF8String: SSDATA (tem)]];
6156   {
6157     NSScreen *screen = [win screen];
6159     if (screen != 0)
6160       [win setFrameTopLeftPoint: NSMakePoint
6161            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6162             IN_BOUND (-SCREENMAX,
6163                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
6164   }
6166   [win makeFirstResponder: self];
6168   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6169                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6170   [win setBackgroundColor: col];
6171   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6172     [win setOpaque: NO];
6174   [self allocateGState];
6176   [NSApp registerServicesMenuSendTypes: ns_send_types
6177                            returnTypes: nil];
6179   ns_window_num++;
6180   return self;
6184 - (void)windowDidMove: sender
6186   NSWindow *win = [self window];
6187   NSRect r = [win frame];
6188   NSArray *screens = [NSScreen screens];
6189   NSScreen *screen = [screens objectAtIndex: 0];
6191   NSTRACE (windowDidMove);
6193   if (!emacsframe->output_data.ns)
6194     return;
6195   if (screen != nil)
6196     {
6197       emacsframe->left_pos = r.origin.x;
6198       emacsframe->top_pos =
6199         [screen frame].size.height - (r.origin.y + r.size.height);
6200     }
6204 /* Called AFTER method below, but before our windowWillResize call there leads
6205    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
6206    location so set_window_size moves the frame. */
6207 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6209   emacsframe->output_data.ns->zooming = 1;
6210   return YES;
6214 /* Override to do something slightly nonstandard, but nice.  First click on
6215    zoom button will zoom vertically.  Second will zoom completely.  Third
6216    returns to original. */
6217 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6218                         defaultFrame:(NSRect)defaultFrame
6220   NSRect result = [sender frame];
6222   NSTRACE (windowWillUseStandardFrame);
6224   if (fs_before_fs != -1) /* Entering fullscreen */
6225       {
6226         result = defaultFrame;
6227       }
6228   else if (next_maximized == FULLSCREEN_HEIGHT
6229       || (next_maximized == -1
6230           && abs (defaultFrame.size.height - result.size.height)
6231           > FRAME_LINE_HEIGHT (emacsframe)))
6232     {
6233       /* first click */
6234       ns_userRect = result;
6235       maximized_height = result.size.height = defaultFrame.size.height;
6236       maximized_width = -1;
6237       result.origin.y = defaultFrame.origin.y;
6238       [self setFSValue: FULLSCREEN_HEIGHT];
6239 #ifdef NS_IMPL_COCOA
6240       maximizing_resize = YES;
6241 #endif
6242     }
6243   else if (next_maximized == FULLSCREEN_WIDTH)
6244     {
6245       ns_userRect = result;
6246       maximized_width = result.size.width = defaultFrame.size.width;
6247       maximized_height = -1;
6248       result.origin.x = defaultFrame.origin.x;
6249       [self setFSValue: FULLSCREEN_WIDTH];
6250     }
6251   else if (next_maximized == FULLSCREEN_MAXIMIZED
6252            || (next_maximized == -1
6253                && abs (defaultFrame.size.width - result.size.width)
6254                > FRAME_COLUMN_WIDTH (emacsframe)))
6255     {
6256       result = defaultFrame;  /* second click */
6257       maximized_width = result.size.width;
6258       maximized_height = result.size.height;
6259       [self setFSValue: FULLSCREEN_MAXIMIZED];
6260 #ifdef NS_IMPL_COCOA
6261       maximizing_resize = YES;
6262 #endif
6263     }
6264   else
6265     {
6266       /* restore */
6267       result = ns_userRect.size.height ? ns_userRect : result;
6268       ns_userRect = NSMakeRect (0, 0, 0, 0);
6269 #ifdef NS_IMPL_COCOA
6270       maximizing_resize = fs_state != FULLSCREEN_NONE;
6271 #endif
6272       [self setFSValue: FULLSCREEN_NONE];
6273       maximized_width = maximized_height = -1;
6274     }
6276   if (fs_before_fs == -1) next_maximized = -1;
6277   [self windowWillResize: sender toSize: result.size];
6278   return result;
6282 - (void)windowDidDeminiaturize: sender
6284   NSTRACE (windowDidDeminiaturize);
6285   if (!emacsframe->output_data.ns)
6286     return;
6288   SET_FRAME_ICONIFIED (emacsframe, 0);
6289   SET_FRAME_VISIBLE (emacsframe, 1);
6290   windows_or_buffers_changed = 63;
6292   if (emacs_event)
6293     {
6294       emacs_event->kind = DEICONIFY_EVENT;
6295       EV_TRAILER ((id)nil);
6296     }
6300 - (void)windowDidExpose: sender
6302   NSTRACE (windowDidExpose);
6303   if (!emacsframe->output_data.ns)
6304     return;
6306   SET_FRAME_VISIBLE (emacsframe, 1);
6307   SET_FRAME_GARBAGED (emacsframe);
6309   if (send_appdefined)
6310     ns_send_appdefined (-1);
6314 - (void)windowDidMiniaturize: sender
6316   NSTRACE (windowDidMiniaturize);
6317   if (!emacsframe->output_data.ns)
6318     return;
6320   SET_FRAME_ICONIFIED (emacsframe, 1);
6321   SET_FRAME_VISIBLE (emacsframe, 0);
6323   if (emacs_event)
6324     {
6325       emacs_event->kind = ICONIFY_EVENT;
6326       EV_TRAILER ((id)nil);
6327     }
6330 #ifdef HAVE_NATIVE_FS
6331 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6332       willUseFullScreenPresentationOptions:
6333   (NSApplicationPresentationOptions)proposedOptions
6335   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6337 #endif
6339 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6341   fs_before_fs = fs_state;
6344 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6346   [self setFSValue: FULLSCREEN_BOTH];
6347   if (! [self fsIsNative])
6348     {
6349       [self windowDidBecomeKey:notification];
6350       [nonfs_window orderOut:self];
6351     }
6352   else
6353     {
6354       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
6355 #ifdef NS_IMPL_COCOA
6356 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6357       unsigned val = (unsigned)[NSApp presentationOptions];
6359       // OSX 10.7 bug fix, the menu won't appear without this.
6360       // val is non-zero on other OSX versions.
6361       if (val == 0)
6362         {
6363           NSApplicationPresentationOptions options
6364             = NSApplicationPresentationAutoHideDock
6365             | NSApplicationPresentationAutoHideMenuBar
6366             | NSApplicationPresentationFullScreen
6367             | NSApplicationPresentationAutoHideToolbar;
6369           [NSApp setPresentationOptions: options];
6370         }
6371 #endif
6372 #endif
6373       [toolbar setVisible:tbar_visible];
6374     }
6377 - (void)windowWillExitFullScreen:(NSNotification *)notification
6379   if (next_maximized != -1)
6380     fs_before_fs = next_maximized;
6383 - (void)windowDidExitFullScreen:(NSNotification *)notification
6385   [self setFSValue: fs_before_fs];
6386   fs_before_fs = -1;
6387 #ifdef HAVE_NATIVE_FS
6388   [self updateCollectionBehavior];
6389 #endif
6390   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6391     {
6392       [toolbar setVisible:YES];
6393       update_frame_tool_bar (emacsframe);
6394       [self updateFrameSize:YES];
6395       [[self window] display];
6396     }
6397   else
6398     [toolbar setVisible:NO];
6400   if (next_maximized != -1)
6401     [[self window] performZoom:self];
6404 - (BOOL)fsIsNative
6406   return fs_is_native;
6409 - (BOOL)isFullscreen
6411   if (! fs_is_native) return nonfs_window != nil;
6412 #ifdef HAVE_NATIVE_FS
6413   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6414 #else
6415   return NO;
6416 #endif
6419 #ifdef HAVE_NATIVE_FS
6420 - (void)updateCollectionBehavior
6422   if (! [self isFullscreen])
6423     {
6424       NSWindow *win = [self window];
6425       NSWindowCollectionBehavior b = [win collectionBehavior];
6426       if (ns_use_native_fullscreen)
6427         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6428       else
6429         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6431       [win setCollectionBehavior: b];
6432       fs_is_native = ns_use_native_fullscreen;
6433     }
6435 #endif
6437 - (void)toggleFullScreen: (id)sender
6439   NSWindow *w, *fw;
6440   BOOL onFirstScreen;
6441   struct frame *f;
6442   NSSize sz;
6443   NSRect r, wr;
6444   NSColor *col;
6446   if (fs_is_native)
6447     {
6448 #ifdef HAVE_NATIVE_FS
6449       [[self window] toggleFullScreen:sender];
6450 #endif
6451       return;
6452     }
6454   w = [self window];
6455   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6456   f = emacsframe;
6457   wr = [w frame];
6458   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6459                                  (FRAME_DEFAULT_FACE (f)),
6460                                  f);
6462   sz.width = FRAME_COLUMN_WIDTH (f);
6463   sz.height = FRAME_LINE_HEIGHT (f);
6465   if (fs_state != FULLSCREEN_BOTH)
6466     {
6467       NSScreen *screen = [w screen];
6469 #if defined (NS_IMPL_COCOA) && \
6470   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
6471       /* Hide ghost menu bar on secondary monitor? */
6472       if (! onFirstScreen)
6473         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
6474 #endif
6475       /* Hide dock and menubar if we are on the primary screen.  */
6476       if (onFirstScreen)
6477         {
6478 #if defined (NS_IMPL_COCOA) && \
6479   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6480           NSApplicationPresentationOptions options
6481             = NSApplicationPresentationAutoHideDock
6482             | NSApplicationPresentationAutoHideMenuBar;
6484           [NSApp setPresentationOptions: options];
6485 #else
6486           [NSMenu setMenuBarVisible:NO];
6487 #endif
6488         }
6490       fw = [[EmacsFSWindow alloc]
6491                        initWithContentRect:[w contentRectForFrameRect:wr]
6492                                  styleMask:NSBorderlessWindowMask
6493                                    backing:NSBackingStoreBuffered
6494                                      defer:YES
6495                                     screen:screen];
6497       [fw setContentView:[w contentView]];
6498       [fw setTitle:[w title]];
6499       [fw setDelegate:self];
6500       [fw setAcceptsMouseMovedEvents: YES];
6501       [fw useOptimizedDrawing: YES];
6502       [fw setResizeIncrements: sz];
6503       [fw setBackgroundColor: col];
6504       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6505         [fw setOpaque: NO];
6507       f->border_width = 0;
6508       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6509       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6510       FRAME_TOOLBAR_HEIGHT (f) = 0;
6512       nonfs_window = w;
6514       [self windowWillEnterFullScreen:nil];
6515       [fw makeKeyAndOrderFront:NSApp];
6516       [fw makeFirstResponder:self];
6517       [w orderOut:self];
6518       r = [fw frameRectForContentRect:[screen frame]];
6519       [fw setFrame: r display:YES animate:YES];
6520       [self windowDidEnterFullScreen:nil];
6521       [fw display];
6522     }
6523   else
6524     {
6525       fw = w;
6526       w = nonfs_window;
6527       nonfs_window = nil;
6529       if (onFirstScreen)
6530         {
6531 #if defined (NS_IMPL_COCOA) && \
6532   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6533           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6534 #else
6535           [NSMenu setMenuBarVisible:YES];
6536 #endif
6537         }
6539       [w setContentView:[fw contentView]];
6540       [w setResizeIncrements: sz];
6541       [w setBackgroundColor: col];
6542       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6543         [w setOpaque: NO];
6545       f->border_width = bwidth;
6546       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6547       if (FRAME_EXTERNAL_TOOL_BAR (f))
6548         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6550       [self windowWillExitFullScreen:nil];
6551       [fw setFrame: [w frame] display:YES animate:YES];
6552       [fw close];
6553       [w makeKeyAndOrderFront:NSApp];
6554       [self windowDidExitFullScreen:nil];
6555       [self updateFrameSize:YES];
6556     }
6559 - (void)handleFS
6561   if (fs_state != emacsframe->want_fullscreen)
6562     {
6563       if (fs_state == FULLSCREEN_BOTH)
6564         {
6565           [self toggleFullScreen:self];
6566         }
6568       switch (emacsframe->want_fullscreen)
6569         {
6570         case FULLSCREEN_BOTH:
6571           [self toggleFullScreen:self];
6572           break;
6573         case FULLSCREEN_WIDTH:
6574           next_maximized = FULLSCREEN_WIDTH;
6575           if (fs_state != FULLSCREEN_BOTH)
6576             [[self window] performZoom:self];
6577           break;
6578         case FULLSCREEN_HEIGHT:
6579           next_maximized = FULLSCREEN_HEIGHT;
6580           if (fs_state != FULLSCREEN_BOTH)
6581             [[self window] performZoom:self];
6582           break;
6583         case FULLSCREEN_MAXIMIZED:
6584           next_maximized = FULLSCREEN_MAXIMIZED;
6585           if (fs_state != FULLSCREEN_BOTH)
6586             [[self window] performZoom:self];
6587           break;
6588         case FULLSCREEN_NONE:
6589           if (fs_state != FULLSCREEN_BOTH)
6590             {
6591               next_maximized = FULLSCREEN_NONE;
6592               [[self window] performZoom:self];
6593             }
6594           break;
6595         }
6597       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6598     }
6602 - (void) setFSValue: (int)value
6604   Lisp_Object lval = Qnil;
6605   switch (value)
6606     {
6607     case FULLSCREEN_BOTH:
6608       lval = Qfullboth;
6609       break;
6610     case FULLSCREEN_WIDTH:
6611       lval = Qfullwidth;
6612       break;
6613     case FULLSCREEN_HEIGHT:
6614       lval = Qfullheight;
6615       break;
6616     case FULLSCREEN_MAXIMIZED:
6617       lval = Qmaximized;
6618       break;
6619     }
6620   store_frame_param (emacsframe, Qfullscreen, lval);
6621   fs_state = value;
6624 - (void)mouseEntered: (NSEvent *)theEvent
6626   NSTRACE (mouseEntered);
6627   if (emacsframe)
6628     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6629       = EV_TIMESTAMP (theEvent);
6633 - (void)mouseExited: (NSEvent *)theEvent
6635   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6637   NSTRACE (mouseExited);
6639   if (!hlinfo)
6640     return;
6642   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6643     = EV_TIMESTAMP (theEvent);
6645   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6646     {
6647       clear_mouse_face (hlinfo);
6648       hlinfo->mouse_face_mouse_frame = 0;
6649     }
6653 - menuDown: sender
6655   NSTRACE (menuDown);
6656   if (context_menu_value == -1)
6657     context_menu_value = [sender tag];
6658   else
6659     {
6660       NSInteger tag = [sender tag];
6661       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6662                                     emacsframe->menu_bar_vector,
6663                                     (void *)tag);
6664     }
6666   ns_send_appdefined (-1);
6667   return self;
6671 - (EmacsToolbar *)toolbar
6673   return toolbar;
6677 /* this gets called on toolbar button click */
6678 - toolbarClicked: (id)item
6680   NSEvent *theEvent;
6681   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6683   NSTRACE (toolbarClicked);
6685   if (!emacs_event)
6686     return self;
6688   /* send first event (for some reason two needed) */
6689   theEvent = [[self window] currentEvent];
6690   emacs_event->kind = TOOL_BAR_EVENT;
6691   XSETFRAME (emacs_event->arg, emacsframe);
6692   EV_TRAILER (theEvent);
6694   emacs_event->kind = TOOL_BAR_EVENT;
6695 /*   XSETINT (emacs_event->code, 0); */
6696   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6697                            idx + TOOL_BAR_ITEM_KEY);
6698   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6699   EV_TRAILER (theEvent);
6700   return self;
6704 - toggleToolbar: (id)sender
6706   if (!emacs_event)
6707     return self;
6709   emacs_event->kind = NS_NONKEY_EVENT;
6710   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6711   EV_TRAILER ((id)nil);
6712   return self;
6716 - (void)drawRect: (NSRect)rect
6718   int x = NSMinX (rect), y = NSMinY (rect);
6719   int width = NSWidth (rect), height = NSHeight (rect);
6721   NSTRACE (drawRect);
6723   if (!emacsframe || !emacsframe->output_data.ns)
6724     return;
6726   ns_clear_frame_area (emacsframe, x, y, width, height);
6727   expose_frame (emacsframe, x, y, width, height);
6729   /*
6730     drawRect: may be called (at least in OS X 10.5) for invisible
6731     views as well for some reason.  Thus, do not infer visibility
6732     here.
6734     emacsframe->async_visible = 1;
6735     emacsframe->async_iconified = 0;
6736   */
6740 /* NSDraggingDestination protocol methods.  Actually this is not really a
6741    protocol, but a category of Object.  O well...  */
6743 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6745   NSTRACE (draggingEntered);
6746   return NSDragOperationGeneric;
6750 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6752   return YES;
6756 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6758   id pb;
6759   int x, y;
6760   NSString *type;
6761   NSEvent *theEvent = [[self window] currentEvent];
6762   NSPoint position;
6763   NSDragOperation op = [sender draggingSourceOperationMask];
6764   int modifiers = 0;
6766   NSTRACE (performDragOperation);
6768   if (!emacs_event)
6769     return NO;
6771   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6772   x = lrint (position.x);  y = lrint (position.y);
6774   pb = [sender draggingPasteboard];
6775   type = [pb availableTypeFromArray: ns_drag_types];
6777   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
6778       // URL drags contain all operations (0xf), don't allow all to be set.
6779       (op & 0xf) != 0xf)
6780     {
6781       if (op & NSDragOperationLink)
6782         modifiers |= NSControlKeyMask;
6783       if (op & NSDragOperationCopy)
6784         modifiers |= NSAlternateKeyMask;
6785       if (op & NSDragOperationGeneric)
6786         modifiers |= NSCommandKeyMask;
6787     }
6789   modifiers = EV_MODIFIERS2 (modifiers);
6790   if (type == 0)
6791     {
6792       return NO;
6793     }
6794   else if ([type isEqualToString: NSFilenamesPboardType])
6795     {
6796       NSArray *files;
6797       NSEnumerator *fenum;
6798       NSString *file;
6800       if (!(files = [pb propertyListForType: type]))
6801         return NO;
6803       fenum = [files objectEnumerator];
6804       while ( (file = [fenum nextObject]) )
6805         {
6806           emacs_event->kind = DRAG_N_DROP_EVENT;
6807           XSETINT (emacs_event->x, x);
6808           XSETINT (emacs_event->y, y);
6809           ns_input_file = append2 (ns_input_file,
6810                                    build_string ([file UTF8String]));
6811           emacs_event->modifiers = modifiers;
6812           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
6813           EV_TRAILER (theEvent);
6814         }
6815       return YES;
6816     }
6817   else if ([type isEqualToString: NSURLPboardType])
6818     {
6819       NSURL *url = [NSURL URLFromPasteboard: pb];
6820       if (url == nil) return NO;
6822       emacs_event->kind = DRAG_N_DROP_EVENT;
6823       XSETINT (emacs_event->x, x);
6824       XSETINT (emacs_event->y, y);
6825       emacs_event->modifiers = modifiers;
6826       emacs_event->arg =  list2 (Qurl,
6827                                  build_string ([[url absoluteString]
6828                                                  UTF8String]));
6829       EV_TRAILER (theEvent);
6831       if ([url isFileURL] != NO)
6832         {
6833           NSString *file = [url path];
6834           ns_input_file = append2 (ns_input_file,
6835                                    build_string ([file UTF8String]));
6836         }
6837       return YES;
6838     }
6839   else if ([type isEqualToString: NSStringPboardType]
6840            || [type isEqualToString: NSTabularTextPboardType])
6841     {
6842       NSString *data;
6844       if (! (data = [pb stringForType: type]))
6845         return NO;
6847       emacs_event->kind = DRAG_N_DROP_EVENT;
6848       XSETINT (emacs_event->x, x);
6849       XSETINT (emacs_event->y, y);
6850       emacs_event->modifiers = modifiers;
6851       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
6852       EV_TRAILER (theEvent);
6853       return YES;
6854     }
6855   else
6856     {
6857       error ("Invalid data type in dragging pasteboard");
6858       return NO;
6859     }
6863 - (id) validRequestorForSendType: (NSString *)typeSent
6864                       returnType: (NSString *)typeReturned
6866   NSTRACE (validRequestorForSendType);
6867   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6868       && typeReturned == nil)
6869     {
6870       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6871         return self;
6872     }
6874   return [super validRequestorForSendType: typeSent
6875                                returnType: typeReturned];
6879 /* The next two methods are part of NSServicesRequests informal protocol,
6880    supposedly called when a services menu item is chosen from this app.
6881    But this should not happen because we override the services menu with our
6882    own entries which call ns-perform-service.
6883    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6884    So let's at least stub them out until further investigation can be done. */
6886 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6888   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6889      be written into the buffer in place of the existing selection..
6890      ordinary service calls go through functions defined in ns-win.el */
6891   return NO;
6894 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6896   NSArray *typesDeclared;
6897   Lisp_Object val;
6899   /* We only support NSStringPboardType */
6900   if ([types containsObject:NSStringPboardType] == NO) {
6901     return NO;
6902   }
6904   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6905   if (CONSP (val) && SYMBOLP (XCAR (val)))
6906     {
6907       val = XCDR (val);
6908       if (CONSP (val) && NILP (XCDR (val)))
6909         val = XCAR (val);
6910     }
6911   if (! STRINGP (val))
6912     return NO;
6914   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6915   [pb declareTypes:typesDeclared owner:nil];
6916   ns_string_to_pasteboard (pb, val);
6917   return YES;
6921 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6922    (gives a miniaturized version of the window); currently we use the latter for
6923    frames whose active buffer doesn't correspond to any file
6924    (e.g., '*scratch*') */
6925 - setMiniwindowImage: (BOOL) setMini
6927   id image = [[self window] miniwindowImage];
6928   NSTRACE (setMiniwindowImage);
6930   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6931      about "AppleDockIconEnabled" notwithstanding, however the set message
6932      below has its effect nonetheless. */
6933   if (image != emacsframe->output_data.ns->miniimage)
6934     {
6935       if (image && [image isKindOfClass: [EmacsImage class]])
6936         [image release];
6937       [[self window] setMiniwindowImage:
6938                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6939     }
6941   return self;
6945 - (void) setRows: (int) r andColumns: (int) c
6947   rows = r;
6948   cols = c;
6951 @end  /* EmacsView */
6955 /* ==========================================================================
6957     EmacsWindow implementation
6959    ========================================================================== */
6961 @implementation EmacsWindow
6963 #ifdef NS_IMPL_COCOA
6964 - (id)accessibilityAttributeValue:(NSString *)attribute
6966   Lisp_Object str = Qnil;
6967   struct frame *f = SELECTED_FRAME ();
6968   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
6970   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6971     return NSAccessibilityTextFieldRole;
6973   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6974       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6975     {
6976       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6977     }
6978   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6979     {
6980       if (! NILP (BVAR (curbuf, mark_active)))
6981           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6983       if (NILP (str))
6984         {
6985           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6986           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6987           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6989           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6990             str = make_uninit_multibyte_string (range, byte_range);
6991           else
6992             str = make_uninit_string (range);
6993           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6994              Is this a problem?  */
6995           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6996         }
6997     }
7000   if (! NILP (str))
7001     {
7002       if (CONSP (str) && SYMBOLP (XCAR (str)))
7003         {
7004           str = XCDR (str);
7005           if (CONSP (str) && NILP (XCDR (str)))
7006             str = XCAR (str);
7007         }
7008       if (STRINGP (str))
7009         {
7010           const char *utfStr = SSDATA (str);
7011           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7012           return nsStr;
7013         }
7014     }
7016   return [super accessibilityAttributeValue:attribute];
7018 #endif /* NS_IMPL_COCOA */
7020 /* If we have multiple monitors, one above the other, we don't want to
7021    restrict the height to just one monitor.  So we override this.  */
7022 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7024   /* When making the frame visible for the first time or if there is just
7025      one screen, we want to constrain.  Other times not.  */
7026   NSArray *screens = [NSScreen screens];
7027   NSUInteger nr_screens = [screens count], nr_eff_screens = 0, i;
7028   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
7029   NSTRACE (constrainFrameRect);
7030   NSTRACE_RECT ("input", frameRect);
7032   if (ns_menu_bar_should_be_hidden ())
7033     return frameRect;
7035   if (nr_screens == 1)
7036     return [super constrainFrameRect:frameRect toScreen:screen];
7038 #ifdef NS_IMPL_COCOA
7039 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7040   // If separate spaces is on, it is like each screen is independent.  There is
7041   // no spanning of frames across screens.
7042   if ([NSScreen screensHaveSeparateSpaces])
7043     return [super constrainFrameRect:frameRect toScreen:screen];
7044 #endif
7045 #endif
7047   for (i = 0; i < nr_screens; ++i) 
7048     {
7049       NSScreen *s = [screens objectAtIndex: i];
7050       NSRect scrrect = [s frame];
7051       NSRect intersect = NSIntersectionRect (frameRect, scrrect);
7053       if (intersect.size.width > 0 || intersect.size.height > 0)
7054         ++nr_eff_screens;
7055     }
7057   if (nr_eff_screens == 1)
7058     return [super constrainFrameRect:frameRect toScreen:screen];
7060   /* The default implementation does two things 1) ensure that the top
7061      of the rectangle is below the menu bar (or below the top of the
7062      screen) and 2) resizes windows larger than the screen. As we
7063      don't want the latter, a smaller rectangle is used. */
7064 #define FAKE_HEIGHT 64
7065   float old_top = frameRect.origin.y + frameRect.size.height;
7066   NSRect r;
7067   r.size.height = FAKE_HEIGHT;
7068   r.size.width = frameRect.size.width;
7069   r.origin.x = frameRect.origin.x;
7070   r.origin.y = old_top - FAKE_HEIGHT;
7072   NSTRACE_RECT ("input to super", r);
7074   r = [super constrainFrameRect:r toScreen:screen];
7076   NSTRACE_RECT ("output from super", r);
7078   float new_top = r.origin.y + FAKE_HEIGHT;
7079   if (new_top < old_top)
7080   {
7081     frameRect.origin.y = new_top - frameRect.size.height;
7082   }
7084   NSTRACE_RECT ("output", frameRect);
7086   return frameRect;
7087 #undef FAKE_HEIGHT
7090 @end /* EmacsWindow */
7093 @implementation EmacsFSWindow
7095 - (BOOL)canBecomeKeyWindow
7097   return YES;
7100 - (BOOL)canBecomeMainWindow
7102   return YES;
7105 @end
7107 /* ==========================================================================
7109     EmacsScroller implementation
7111    ========================================================================== */
7114 @implementation EmacsScroller
7116 /* for repeat button push */
7117 #define SCROLL_BAR_FIRST_DELAY 0.5
7118 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
7120 + (CGFloat) scrollerWidth
7122   /* TODO: if we want to allow variable widths, this is the place to do it,
7123            however neither GNUstep nor Cocoa support it very well */
7124   return [NSScroller scrollerWidth];
7128 - initFrame: (NSRect )r window: (Lisp_Object)nwin
7130   NSTRACE (EmacsScroller_initFrame);
7132   r.size.width = [EmacsScroller scrollerWidth];
7133   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
7134   [self setContinuous: YES];
7135   [self setEnabled: YES];
7137   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
7138      locked against the top and bottom edges, and right edge on OS X, where
7139      scrollers are on right. */
7140 #ifdef NS_IMPL_GNUSTEP
7141   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
7142 #else
7143   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
7144 #endif
7146   win = nwin;
7147   condemned = NO;
7148   pixel_height = NSHeight (r);
7149   if (pixel_height == 0) pixel_height = 1;
7150   min_portion = 20 / pixel_height;
7152   frame = XFRAME (XWINDOW (win)->frame);
7153   if (FRAME_LIVE_P (frame))
7154     {
7155       int i;
7156       EmacsView *view = FRAME_NS_VIEW (frame);
7157       NSView *sview = [[view window] contentView];
7158       NSArray *subs = [sview subviews];
7160       /* disable optimization stopping redraw of other scrollbars */
7161       view->scrollbarsNeedingUpdate = 0;
7162       for (i =[subs count]-1; i >= 0; i--)
7163         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
7164           view->scrollbarsNeedingUpdate++;
7165       [sview addSubview: self];
7166     }
7168 /*  [self setFrame: r]; */
7170   return self;
7174 - (void)setFrame: (NSRect)newRect
7176   NSTRACE (EmacsScroller_setFrame);
7177 /*  block_input (); */
7178   pixel_height = NSHeight (newRect);
7179   if (pixel_height == 0) pixel_height = 1;
7180   min_portion = 20 / pixel_height;
7181   [super setFrame: newRect];
7182   [self display];
7183 /*  unblock_input (); */
7187 - condemn
7189   NSTRACE (condemn);
7190   condemned =YES;
7191   return self;
7195 - reprieve
7197   NSTRACE (reprieve);
7198   condemned =NO;
7199   return self;
7203 - judge
7205   NSTRACE (judge);
7206   if (condemned)
7207     {
7208       EmacsView *view;
7209       block_input ();
7210       /* ensure other scrollbar updates after deletion */
7211       view = (EmacsView *)FRAME_NS_VIEW (frame);
7212       if (view != nil)
7213         view->scrollbarsNeedingUpdate++;
7214       if (!NILP (win))
7215         wset_vertical_scroll_bar (XWINDOW (win), Qnil);
7216       win = Qnil;
7217       [self removeFromSuperview];
7218       [self release];
7219       unblock_input ();
7220     }
7221   return self;
7225 - (void)resetCursorRects
7227   NSRect visible = [self visibleRect];
7228   NSTRACE (resetCursorRects);
7230   if (!NSIsEmptyRect (visible))
7231     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
7232   [[NSCursor arrowCursor] setOnMouseEntered: YES];
7236 - (int) checkSamePosition: (int) position portion: (int) portion
7237                     whole: (int) whole
7239   return em_position ==position && em_portion ==portion && em_whole ==whole
7240     && portion != whole; /* needed for resize empty buf */
7244 - setPosition: (int)position portion: (int)portion whole: (int)whole
7246   NSTRACE (setPosition);
7248   em_position = position;
7249   em_portion = portion;
7250   em_whole = whole;
7252   if (portion >= whole)
7253     {
7254 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
7255       [self setKnobProportion: 1.0];
7256       [self setDoubleValue: 1.0];
7257 #else
7258       [self setFloatValue: 0.0 knobProportion: 1.0];
7259 #endif
7260     }
7261   else
7262     {
7263       float pos;
7264       CGFloat por;
7265       portion = max ((float)whole*min_portion/pixel_height, portion);
7266       pos = (float)position / (whole - portion);
7267       por = (CGFloat)portion/whole;
7268 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
7269       [self setKnobProportion: por];
7270       [self setDoubleValue: pos];
7271 #else
7272       [self setFloatValue: pos knobProportion: por];
7273 #endif
7274     }
7276   /* Events may come here even if the event loop is not running.
7277      If we don't enter the event loop, the scroll bar will not update.
7278      So send SIGIO to ourselves.  */
7279   if (apploopnr == 0) raise (SIGIO);
7281   return self;
7284 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
7285      drag events will go directly to the EmacsScroller.  Leaving in for now. */
7286 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
7287                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
7289   *part = last_hit_part;
7290   *window = win;
7291   XSETINT (*y, pixel_height);
7292   if ([self floatValue] > 0.999F)
7293     XSETINT (*x, pixel_height);
7294   else
7295     XSETINT (*x, pixel_height * [self floatValue]);
7299 /* set up emacs_event */
7300 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
7302   if (!emacs_event)
7303     return;
7305   emacs_event->part = last_hit_part;
7306   emacs_event->code = 0;
7307   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
7308   emacs_event->frame_or_window = win;
7309   emacs_event->timestamp = EV_TIMESTAMP (e);
7310   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
7311   emacs_event->arg = Qnil;
7312   XSETINT (emacs_event->x, loc * pixel_height);
7313   XSETINT (emacs_event->y, pixel_height-20);
7315   if (q_event_ptr)
7316     {
7317       n_emacs_events_pending++;
7318       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7319     }
7320   else
7321     hold_event (emacs_event);
7322   EVENT_INIT (*emacs_event);
7323   ns_send_appdefined (-1);
7327 /* called manually thru timer to implement repeated button action w/hold-down */
7328 - repeatScroll: (NSTimer *)scrollEntry
7330   NSEvent *e = [[self window] currentEvent];
7331   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
7332   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7334   /* clear timer if need be */
7335   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7336     {
7337         [scroll_repeat_entry invalidate];
7338         [scroll_repeat_entry release];
7339         scroll_repeat_entry = nil;
7341         if (inKnob)
7342           return self;
7344         scroll_repeat_entry
7345           = [[NSTimer scheduledTimerWithTimeInterval:
7346                         SCROLL_BAR_CONTINUOUS_DELAY
7347                                             target: self
7348                                           selector: @selector (repeatScroll:)
7349                                           userInfo: 0
7350                                            repeats: YES]
7351               retain];
7352     }
7354   [self sendScrollEventAtLoc: 0 fromEvent: e];
7355   return self;
7359 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
7360    mouseDragged events without going into a modal loop. */
7361 - (void)mouseDown: (NSEvent *)e
7363   NSRect sr, kr;
7364   /* hitPart is only updated AFTER event is passed on */
7365   NSScrollerPart part = [self testPart: [e locationInWindow]];
7366   CGFloat inc = 0.0, loc, kloc, pos;
7367   int edge = 0;
7369   NSTRACE (EmacsScroller_mouseDown);
7371   switch (part)
7372     {
7373     case NSScrollerDecrementPage:
7374         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7375     case NSScrollerIncrementPage:
7376         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7377     case NSScrollerDecrementLine:
7378       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7379     case NSScrollerIncrementLine:
7380       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7381     case NSScrollerKnob:
7382       last_hit_part = scroll_bar_handle; break;
7383     case NSScrollerKnobSlot:  /* GNUstep-only */
7384       last_hit_part = scroll_bar_move_ratio; break;
7385     default:  /* NSScrollerNoPart? */
7386       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7387                (long) part);
7388       return;
7389     }
7391   if (inc != 0.0)
7392     {
7393       pos = 0;      /* ignored */
7395       /* set a timer to repeat, as we can't let superclass do this modally */
7396       scroll_repeat_entry
7397         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7398                                             target: self
7399                                           selector: @selector (repeatScroll:)
7400                                           userInfo: 0
7401                                            repeats: YES]
7402             retain];
7403     }
7404   else
7405     {
7406       /* handle, or on GNUstep possibly slot */
7407       NSEvent *fake_event;
7409       /* compute float loc in slot and mouse offset on knob */
7410       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7411                       toView: nil];
7412       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7413       if (loc <= 0.0)
7414         {
7415           loc = 0.0;
7416           edge = -1;
7417         }
7418       else if (loc >= NSHeight (sr))
7419         {
7420           loc = NSHeight (sr);
7421           edge = 1;
7422         }
7424       if (edge)
7425         kloc = 0.5 * edge;
7426       else
7427         {
7428           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7429                           toView: nil];
7430           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7431         }
7432       last_mouse_offset = kloc;
7434       /* if knob, tell emacs a location offset by knob pos
7435          (to indicate top of handle) */
7436       if (part == NSScrollerKnob)
7437           pos = (loc - last_mouse_offset) / NSHeight (sr);
7438       else
7439         /* else this is a slot click on GNUstep: go straight there */
7440         pos = loc / NSHeight (sr);
7442       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7443       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7444                                       location: [e locationInWindow]
7445                                  modifierFlags: [e modifierFlags]
7446                                      timestamp: [e timestamp]
7447                                   windowNumber: [e windowNumber]
7448                                        context: [e context]
7449                                    eventNumber: [e eventNumber]
7450                                     clickCount: [e clickCount]
7451                                       pressure: [e pressure]];
7452       [super mouseUp: fake_event];
7453     }
7455   if (part != NSScrollerKnob)
7456     [self sendScrollEventAtLoc: pos fromEvent: e];
7460 /* Called as we manually track scroller drags, rather than superclass. */
7461 - (void)mouseDragged: (NSEvent *)e
7463     NSRect sr;
7464     double loc, pos;
7466     NSTRACE (EmacsScroller_mouseDragged);
7468       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7469                       toView: nil];
7470       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7472       if (loc <= 0.0)
7473         {
7474           loc = 0.0;
7475         }
7476       else if (loc >= NSHeight (sr) + last_mouse_offset)
7477         {
7478           loc = NSHeight (sr) + last_mouse_offset;
7479         }
7481       pos = (loc - last_mouse_offset) / NSHeight (sr);
7482       [self sendScrollEventAtLoc: pos fromEvent: e];
7486 - (void)mouseUp: (NSEvent *)e
7488   if (scroll_repeat_entry)
7489     {
7490       [scroll_repeat_entry invalidate];
7491       [scroll_repeat_entry release];
7492       scroll_repeat_entry = nil;
7493     }
7494   last_hit_part = 0;
7498 /* treat scrollwheel events in the bar as though they were in the main window */
7499 - (void) scrollWheel: (NSEvent *)theEvent
7501   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7502   [view mouseDown: theEvent];
7505 @end  /* EmacsScroller */
7508 #ifdef NS_IMPL_GNUSTEP
7509 /* Dummy class to get rid of startup warnings.  */
7510 @implementation EmacsDocument
7512 @end
7513 #endif
7516 /* ==========================================================================
7518    Font-related functions; these used to be in nsfaces.m
7520    ========================================================================== */
7523 Lisp_Object
7524 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7526   struct font *font = XFONT_OBJECT (font_object);
7527   EmacsView *view = FRAME_NS_VIEW (f);
7529   if (fontset < 0)
7530     fontset = fontset_from_font (font_object);
7531   FRAME_FONTSET (f) = fontset;
7533   if (FRAME_FONT (f) == font)
7534     /* This font is already set in frame F.  There's nothing more to
7535        do.  */
7536     return font_object;
7538   FRAME_FONT (f) = font;
7540   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7541   FRAME_COLUMN_WIDTH (f) = font->average_width;
7542   FRAME_LINE_HEIGHT (f) = font->height;
7544   /* Compute the scroll bar width in character columns.  */
7545   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7546     {
7547       int wid = FRAME_COLUMN_WIDTH (f);
7548       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7549         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7550     }
7551   else
7552     {
7553       int wid = FRAME_COLUMN_WIDTH (f);
7554       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7555     }
7557   /* Compute the scroll bar height in character lines.  */
7558   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
7559     {
7560       int height = FRAME_LINE_HEIGHT (f);
7561       FRAME_CONFIG_SCROLL_BAR_LINES (f)
7562         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
7563     }
7564   else
7565     {
7566       int height = FRAME_LINE_HEIGHT (f);
7567       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
7568     }
7570   /* Now make the frame display the given font.  */
7571   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
7572     x_set_window_size (f, 0, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
7573                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 1);
7575   return font_object;
7579 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7580 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7581          in 1.43. */
7583 const char *
7584 ns_xlfd_to_fontname (const char *xlfd)
7585 /* --------------------------------------------------------------------------
7586     Convert an X font name (XLFD) to an NS font name.
7587     Only family is used.
7588     The string returned is temporarily allocated.
7589    -------------------------------------------------------------------------- */
7591   char *name = xmalloc (180);
7592   int i, len;
7593   const char *ret;
7595   if (!strncmp (xlfd, "--", 2))
7596     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7597   else
7598     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7600   /* stopgap for malformed XLFD input */
7601   if (strlen (name) == 0)
7602     strcpy (name, "Monaco");
7604   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7605      also uppercase after '-' or ' ' */
7606   name[0] = c_toupper (name[0]);
7607   for (len =strlen (name), i =0; i<len; i++)
7608     {
7609       if (name[i] == '$')
7610         {
7611           name[i] = '-';
7612           if (i+1<len)
7613             name[i+1] = c_toupper (name[i+1]);
7614         }
7615       else if (name[i] == '_')
7616         {
7617           name[i] = ' ';
7618           if (i+1<len)
7619             name[i+1] = c_toupper (name[i+1]);
7620         }
7621     }
7622 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7623   ret = [[NSString stringWithUTF8String: name] UTF8String];
7624   xfree (name);
7625   return ret;
7629 void
7630 syms_of_nsterm (void)
7632   NSTRACE (syms_of_nsterm);
7634   ns_antialias_threshold = 10.0;
7636   /* from 23+ we need to tell emacs what modifiers there are.. */
7637   DEFSYM (Qmodifier_value, "modifier-value");
7638   DEFSYM (Qalt, "alt");
7639   DEFSYM (Qhyper, "hyper");
7640   DEFSYM (Qmeta, "meta");
7641   DEFSYM (Qsuper, "super");
7642   DEFSYM (Qcontrol, "control");
7643   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7645   DEFSYM (Qfile, "file");
7646   DEFSYM (Qurl, "url");
7648   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7649   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7650   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7651   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7652   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7654   DEFVAR_LISP ("ns-input-file", ns_input_file,
7655               "The file specified in the last NS event.");
7656   ns_input_file =Qnil;
7658   DEFVAR_LISP ("ns-working-text", ns_working_text,
7659               "String for visualizing working composition sequence.");
7660   ns_working_text =Qnil;
7662   DEFVAR_LISP ("ns-input-font", ns_input_font,
7663               "The font specified in the last NS event.");
7664   ns_input_font =Qnil;
7666   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7667               "The fontsize specified in the last NS event.");
7668   ns_input_fontsize =Qnil;
7670   DEFVAR_LISP ("ns-input-line", ns_input_line,
7671                "The line specified in the last NS event.");
7672   ns_input_line =Qnil;
7674   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7675                "The service name specified in the last NS event.");
7676   ns_input_spi_name =Qnil;
7678   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7679                "The service argument specified in the last NS event.");
7680   ns_input_spi_arg =Qnil;
7682   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7683                "This variable describes the behavior of the alternate or option key.\n\
7684 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7685 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7686 at all, allowing it to be used at a lower level for accented character entry.");
7687   ns_alternate_modifier = Qmeta;
7689   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7690                "This variable describes the behavior of the right alternate or option key.\n\
7691 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7692 Set to left means be the same key as `ns-alternate-modifier'.\n\
7693 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7694 at all, allowing it to be used at a lower level for accented character entry.");
7695   ns_right_alternate_modifier = Qleft;
7697   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7698                "This variable describes the behavior of the command key.\n\
7699 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7700   ns_command_modifier = Qsuper;
7702   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7703                "This variable describes the behavior of the right command key.\n\
7704 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7705 Set to left means be the same key as `ns-command-modifier'.\n\
7706 Set to none means that the command / option key is not interpreted by Emacs\n\
7707 at all, allowing it to be used at a lower level for accented character entry.");
7708   ns_right_command_modifier = Qleft;
7710   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7711                "This variable describes the behavior of the control key.\n\
7712 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7713   ns_control_modifier = Qcontrol;
7715   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7716                "This variable describes the behavior of the right control key.\n\
7717 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7718 Set to left means be the same key as `ns-control-modifier'.\n\
7719 Set to none means that the control / option key is not interpreted by Emacs\n\
7720 at all, allowing it to be used at a lower level for accented character entry.");
7721   ns_right_control_modifier = Qleft;
7723   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7724                "This variable describes the behavior of the function key (on laptops).\n\
7725 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7726 Set to none means that the function key is not interpreted by Emacs at all,\n\
7727 allowing it to be used at a lower level for accented character entry.");
7728   ns_function_modifier = Qnone;
7730   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7731                "Non-nil (the default) means to render text antialiased.");
7732   ns_antialias_text = Qt;
7734   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7735                "Whether to confirm application quit using dialog.");
7736   ns_confirm_quit = Qnil;
7738   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7739                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7740 Only works on OSX 10.6 or later.  */);
7741   ns_auto_hide_menu_bar = Qnil;
7743   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7744      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7745 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7746 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7747 Default is t for OSX >= 10.7, nil otherwise.  */);
7748 #ifdef HAVE_NATIVE_FS
7749   ns_use_native_fullscreen = YES;
7750 #else
7751   ns_use_native_fullscreen = NO;
7752 #endif
7753   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7755   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
7756      doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
7757 Note that this does not apply to images.
7758 This variable is ignored on OSX < 10.7 and GNUstep.  */);
7759   ns_use_srgb_colorspace = YES;
7761   /* TODO: move to common code */
7762   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7763                doc: /* Which toolkit scroll bars Emacs uses, if any.
7764 A value of nil means Emacs doesn't use toolkit scroll bars.
7765 With the X Window system, the value is a symbol describing the
7766 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7767 With MS Windows or Nextstep, the value is t.  */);
7768   Vx_toolkit_scroll_bars = Qt;
7770   DEFVAR_BOOL ("x-use-underline-position-properties",
7771                x_use_underline_position_properties,
7772      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7773 A value of nil means ignore them.  If you encounter fonts with bogus
7774 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7775 to 4.1, set this to nil. */);
7776   x_use_underline_position_properties = 0;
7778   DEFVAR_BOOL ("x-underline-at-descent-line",
7779                x_underline_at_descent_line,
7780      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7781 A value of nil means to draw the underline according to the value of the
7782 variable `x-use-underline-position-properties', which is usually at the
7783 baseline level.  The default value is nil.  */);
7784   x_underline_at_descent_line = 0;
7786   /* Tell Emacs about this window system.  */
7787   Fprovide (Qns, Qnil);
7789   DEFSYM (Qcocoa, "cocoa");
7790   DEFSYM (Qgnustep, "gnustep");
7792   syms_of_nsfont ();
7793 #ifdef NS_IMPL_COCOA
7794   Fprovide (Qcocoa, Qnil);
7795 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
7796   syms_of_macfont ();
7797 #endif
7798 #else
7799   Fprovide (Qgnustep, Qnil);
7800 #endif