Warn against renaming git-bzr remote; nfc.
[emacs.git] / src / nsterm.m
blob842ff194c408d9ba1a5d3893c12e3d6514a19996
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"
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, Qleft;
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 static struct {
287   struct input_event *q;
288   int nr, cap;
289 } hold_event_q = {
290   NULL, 0, 0
293 #ifdef NS_IMPL_COCOA
295  * State for pending menu activation:
296  * MENU_NONE     Normal state
297  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
298  *               run lisp to update the menu.
299  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
300  *               will open.
301  */
302 #define MENU_NONE 0
303 #define MENU_PENDING 1
304 #define MENU_OPENING 2
305 static int menu_will_open_state = MENU_NONE;
307 /* Saved position for menu click.  */
308 static CGPoint menu_mouse_point;
309 #endif
311 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
312 #define NS_FUNCTION_KEY_MASK 0x800000
313 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
314 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
315 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
316 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
317 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
318 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
319 #define EV_MODIFIERS2(flags)                          \
320     (((flags & NSHelpKeyMask) ?           \
321            hyper_modifier : 0)                        \
322      | (!EQ (ns_right_alternate_modifier, Qleft) && \
323         ((flags & NSRightAlternateKeyMask) \
324          == NSRightAlternateKeyMask) ? \
325            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
326      | ((flags & NSAlternateKeyMask) ?                 \
327            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
328      | ((flags & NSShiftKeyMask) ?     \
329            shift_modifier : 0)                        \
330      | (!EQ (ns_right_control_modifier, Qleft) && \
331         ((flags & NSRightControlKeyMask) \
332          == NSRightControlKeyMask) ? \
333            parse_solitary_modifier (ns_right_control_modifier) : 0) \
334      | ((flags & NSControlKeyMask) ?      \
335            parse_solitary_modifier (ns_control_modifier) : 0)     \
336      | ((flags & NS_FUNCTION_KEY_MASK) ?  \
337            parse_solitary_modifier (ns_function_modifier) : 0)    \
338      | (!EQ (ns_right_command_modifier, Qleft) && \
339         ((flags & NSRightCommandKeyMask) \
340          == NSRightCommandKeyMask) ? \
341            parse_solitary_modifier (ns_right_command_modifier) : 0) \
342      | ((flags & NSCommandKeyMask) ?      \
343            parse_solitary_modifier (ns_command_modifier):0))
344 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
346 #define EV_UDMODIFIERS(e)                                      \
347     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
348      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
349      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
350      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
351      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
352      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
353      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
354      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
355      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
357 #define EV_BUTTON(e)                                                         \
358     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
359       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
360      [e buttonNumber] - 1)
362 /* Convert the time field to a timestamp in milliseconds. */
363 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
365 /* This is a piece of code which is common to all the event handling
366    methods.  Maybe it should even be a function.  */
367 #define EV_TRAILER(e)                                                   \
368   {                                                                     \
369     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
370     EV_TRAILER2 (e);                                                    \
371   }
373 #define EV_TRAILER2(e)                                                  \
374   {                                                                     \
375       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
376       if (q_event_ptr)                                                  \
377         {                                                               \
378           n_emacs_events_pending++;                                     \
379           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
380         }                                                               \
381       else                                                              \
382         hold_event (emacs_event);                                       \
383       EVENT_INIT (*emacs_event);                                        \
384       ns_send_appdefined (-1);                                          \
385     }
387 /* TODO: get rid of need for these forward declarations */
388 static void ns_condemn_scroll_bars (struct frame *f);
389 static void ns_judge_scroll_bars (struct frame *f);
390 void x_set_frame_alpha (struct frame *f);
393 /* ==========================================================================
395     Utilities
397    ========================================================================== */
399 static void
400 hold_event (struct input_event *event)
402   if (hold_event_q.nr == hold_event_q.cap)
403     {
404       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
405       else hold_event_q.cap *= 2;
406       hold_event_q.q =
407         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
408     }
410   hold_event_q.q[hold_event_q.nr++] = *event;
411   /* Make sure ns_read_socket is called, i.e. we have input.  */
412   raise (SIGIO);
413   send_appdefined = YES;
416 static Lisp_Object
417 append2 (Lisp_Object list, Lisp_Object item)
418 /* --------------------------------------------------------------------------
419    Utility to append to a list
420    -------------------------------------------------------------------------- */
422   Lisp_Object array[2];
423   array[0] = list;
424   array[1] = list1 (item);
425   return Fnconc (2, &array[0]);
429 const char *
430 ns_etc_directory (void)
431 /* If running as a self-contained app bundle, return as a string the
432    filename of the etc directory, if present; else nil.  */
434   NSBundle *bundle = [NSBundle mainBundle];
435   NSString *resourceDir = [bundle resourcePath];
436   NSString *resourcePath;
437   NSFileManager *fileManager = [NSFileManager defaultManager];
438   BOOL isDir;
440   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
441   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
442     {
443       if (isDir) return [resourcePath UTF8String];
444     }
445   return NULL;
449 const char *
450 ns_exec_path (void)
451 /* If running as a self-contained app bundle, return as a path string
452    the filenames of the libexec and bin directories, ie libexec:bin.
453    Otherwise, return nil.
454    Normally, Emacs does not add its own bin/ directory to the PATH.
455    However, a self-contained NS build has a different layout, with
456    bin/ and libexec/ subdirectories in the directory that contains
457    Emacs.app itself.
458    We put libexec first, because init_callproc_1 uses the first
459    element to initialize exec-directory.  An alternative would be
460    for init_callproc to check for invocation-directory/libexec.
463   NSBundle *bundle = [NSBundle mainBundle];
464   NSString *resourceDir = [bundle resourcePath];
465   NSString *binDir = [bundle bundlePath];
466   NSString *resourcePath, *resourcePaths;
467   NSRange range;
468   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
469   NSFileManager *fileManager = [NSFileManager defaultManager];
470   NSArray *paths;
471   NSEnumerator *pathEnum;
472   BOOL isDir;
474   range = [resourceDir rangeOfString: @"Contents"];
475   if (range.location != NSNotFound)
476     {
477       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
478 #ifdef NS_IMPL_COCOA
479       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
480 #endif
481     }
483   paths = [binDir stringsByAppendingPaths:
484                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
485   pathEnum = [paths objectEnumerator];
486   resourcePaths = @"";
488   while ((resourcePath = [pathEnum nextObject]))
489     {
490       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
491         if (isDir)
492           {
493             if ([resourcePaths length] > 0)
494               resourcePaths
495                 = [resourcePaths stringByAppendingString: pathSeparator];
496             resourcePaths
497               = [resourcePaths stringByAppendingString: resourcePath];
498           }
499     }
500   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
502   return NULL;
506 const char *
507 ns_load_path (void)
508 /* If running as a self-contained app bundle, return as a path string
509    the filenames of the site-lisp and lisp directories.
510    Ie, site-lisp:lisp.  Otherwise, return nil.  */
512   NSBundle *bundle = [NSBundle mainBundle];
513   NSString *resourceDir = [bundle resourcePath];
514   NSString *resourcePath, *resourcePaths;
515   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
516   NSFileManager *fileManager = [NSFileManager defaultManager];
517   BOOL isDir;
518   NSArray *paths = [resourceDir stringsByAppendingPaths:
519                               [NSArray arrayWithObjects:
520                                          @"site-lisp", @"lisp", nil]];
521   NSEnumerator *pathEnum = [paths objectEnumerator];
522   resourcePaths = @"";
524   /* Hack to skip site-lisp.  */
525   if (no_site_lisp) resourcePath = [pathEnum nextObject];
527   while ((resourcePath = [pathEnum nextObject]))
528     {
529       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
530         if (isDir)
531           {
532             if ([resourcePaths length] > 0)
533               resourcePaths
534                 = [resourcePaths stringByAppendingString: pathSeparator];
535             resourcePaths
536               = [resourcePaths stringByAppendingString: resourcePath];
537           }
538     }
539   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
541   return NULL;
544 static void
545 ns_timeout (int usecs)
546 /* --------------------------------------------------------------------------
547      Blocking timer utility used by ns_ring_bell
548    -------------------------------------------------------------------------- */
550   struct timespec wakeup = timespec_add (current_timespec (),
551                                          make_timespec (0, usecs * 1000));
553   /* Keep waiting until past the time wakeup.  */
554   while (1)
555     {
556       struct timespec timeout, now = current_timespec ();
557       if (timespec_cmp (wakeup, now) <= 0)
558         break;
559       timeout = timespec_sub (wakeup, now);
561       /* Try to wait that long--but we might wake up sooner.  */
562       pselect (0, NULL, NULL, NULL, &timeout, NULL);
563     }
567 void
568 ns_release_object (void *obj)
569 /* --------------------------------------------------------------------------
570     Release an object (callable from C)
571    -------------------------------------------------------------------------- */
573     [(id)obj release];
577 void
578 ns_retain_object (void *obj)
579 /* --------------------------------------------------------------------------
580     Retain an object (callable from C)
581    -------------------------------------------------------------------------- */
583     [(id)obj retain];
587 void *
588 ns_alloc_autorelease_pool (void)
589 /* --------------------------------------------------------------------------
590      Allocate a pool for temporary objects (callable from C)
591    -------------------------------------------------------------------------- */
593   return [[NSAutoreleasePool alloc] init];
597 void
598 ns_release_autorelease_pool (void *pool)
599 /* --------------------------------------------------------------------------
600      Free a pool and temporary objects it refers to (callable from C)
601    -------------------------------------------------------------------------- */
603   ns_release_object (pool);
608 /* ==========================================================================
610     Focus (clipping) and screen update
612    ========================================================================== */
615 // Window constraining
616 // -------------------
618 // To ensure that the windows are not placed under the menu bar, they
619 // are typically moved by the call-back constrainFrameRect. However,
620 // by overriding it, it's possible to inhibit this, leaving the window
621 // in it's original position.
623 // It's possible to hide the menu bar. However, technically, it's only
624 // possible to hide it when the application is active. To ensure that
625 // this work properly, the menu bar and window constraining are
626 // deferred until the application becomes active.
628 // Even though it's not possible to manually move a window above the
629 // top of the screen, it is allowed if it's done programmatically,
630 // when the menu is hidden. This allows the editable area to cover the
631 // full screen height.
633 // Test cases
634 // ----------
636 // Use the following extra files:
638 //    init.el:
639 //       ;; Hide menu and place frame slightly above the top of the screen.
640 //       (setq ns-auto-hide-menu-bar t)
641 //       (set-frame-position (selected-frame) 0 -20)
643 // Test 1:
645 //    emacs -Q -l init.el
647 //    Result: No menu bar, and the title bar should be above the screen.
649 // Test 2:
651 //    emacs -Q
653 //    Result: Menu bar visible, frame placed immediately below the menu.
656 static void
657 ns_constrain_all_frames (void)
659   Lisp_Object tail, frame;
661   FOR_EACH_FRAME (tail, frame)
662     {
663       struct frame *f = XFRAME (frame);
664       if (FRAME_NS_P (f))
665         {
666           NSView *view = FRAME_NS_VIEW (f);
667           /* This no-op will trigger the default window placing
668            * constraint system. */
669           [[view window] setFrameOrigin:[[view window] frame].origin];
670         }
671     }
675 /* True, if the menu bar should be hidden.  */
677 static BOOL
678 ns_menu_bar_should_be_hidden (void)
680   return !NILP (ns_auto_hide_menu_bar)
681     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
685 /* Show or hide the menu bar, based on user setting.  */
687 static void
688 ns_update_auto_hide_menu_bar (void)
690 #ifdef NS_IMPL_COCOA
691 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
692   block_input ();
694   NSTRACE (ns_update_auto_hide_menu_bar);
696   if (NSApp != nil && [NSApp isActive])
697     {
698       // Note, "setPresentationOptions" triggers an error unless the
699       // application is active.
700       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
702       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
703         {
704           NSApplicationPresentationOptions options
705             = NSApplicationPresentationDefault;
707           if (menu_bar_should_be_hidden)
708             options |= NSApplicationPresentationAutoHideMenuBar
709               | NSApplicationPresentationAutoHideDock;
711           [NSApp setPresentationOptions: options];
713           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
715           if (!ns_menu_bar_is_hidden)
716             {
717               ns_constrain_all_frames ();
718             }
719         }
720     }
722   unblock_input ();
723 #endif
724 #endif
728 static void
729 ns_update_begin (struct frame *f)
730 /* --------------------------------------------------------------------------
731    Prepare for a grouped sequence of drawing calls
732    external (RIF) call; whole frame, called before update_window_begin
733    -------------------------------------------------------------------------- */
735   EmacsView *view = FRAME_NS_VIEW (f);
736   NSTRACE (ns_update_begin);
738   ns_update_auto_hide_menu_bar ();
740 #ifdef NS_IMPL_COCOA
741   if ([view isFullscreen] && [view fsIsNative])
742   {
743     // Fix reappearing tool bar in fullscreen for OSX 10.7
744     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
745     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
746     if (! tbar_visible != ! [toolbar isVisible])
747       [toolbar setVisible: tbar_visible];
748   }
749 #endif
751   ns_updating_frame = f;
752   [view lockFocus];
754   /* drawRect may have been called for say the minibuffer, and then clip path
755      is for the minibuffer.  But the display engine may draw more because
756      we have set the frame as garbaged.  So reset clip path to the whole
757      view.  */
758 #ifdef NS_IMPL_COCOA
759   {
760     NSBezierPath *bp;
761     NSRect r = [view frame];
762     NSRect cr = [[view window] frame];
763     /* If a large frame size is set, r may be larger than the window frame
764        before constrained.  In that case don't change the clip path, as we
765        will clear in to the tool bar and title bar.  */
766     if (r.size.height
767         + FRAME_NS_TITLEBAR_HEIGHT (f)
768         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
769       {
770         bp = [[NSBezierPath bezierPathWithRect: r] retain];
771         [bp setClip];
772         [bp release];
773       }
774   }
775 #endif
777 #ifdef NS_IMPL_GNUSTEP
778   uRect = NSMakeRect (0, 0, 0, 0);
779 #endif
783 static void
784 ns_update_window_begin (struct window *w)
785 /* --------------------------------------------------------------------------
786    Prepare for a grouped sequence of drawing calls
787    external (RIF) call; for one window, called after update_begin
788    -------------------------------------------------------------------------- */
790   struct frame *f = XFRAME (WINDOW_FRAME (w));
791   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
793   NSTRACE (ns_update_window_begin);
794   w->output_cursor = w->cursor;
796   block_input ();
798   if (f == hlinfo->mouse_face_mouse_frame)
799     {
800       /* Don't do highlighting for mouse motion during the update.  */
801       hlinfo->mouse_face_defer = 1;
803         /* If the frame needs to be redrawn,
804            simply forget about any prior mouse highlighting.  */
805       if (FRAME_GARBAGED_P (f))
806         hlinfo->mouse_face_window = Qnil;
808       /* (further code for mouse faces ifdef'd out in other terms elided) */
809     }
811   unblock_input ();
815 static void
816 ns_update_window_end (struct window *w, bool cursor_on_p,
817                       bool mouse_face_overwritten_p)
818 /* --------------------------------------------------------------------------
819    Finished a grouped sequence of drawing calls
820    external (RIF) call; for one window called before update_end
821    -------------------------------------------------------------------------- */
823   /* note: this fn is nearly identical in all terms */
824   if (!w->pseudo_window_p)
825     {
826       block_input ();
828       if (cursor_on_p)
829         display_and_set_cursor (w, 1,
830                                 w->output_cursor.hpos, w->output_cursor.vpos,
831                                 w->output_cursor.x, w->output_cursor.y);
833       if (draw_window_fringes (w, 1))
834         {
835           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
836             x_draw_right_divider (w);
837           else
838             x_draw_vertical_border (w);
839         }
841       unblock_input ();
842     }
844   /* If a row with mouse-face was overwritten, arrange for
845      frame_up_to_date to redisplay the mouse highlight.  */
846   if (mouse_face_overwritten_p)
847     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
849   NSTRACE (update_window_end);
853 static void
854 ns_update_end (struct frame *f)
855 /* --------------------------------------------------------------------------
856    Finished a grouped sequence of drawing calls
857    external (RIF) call; for whole frame, called after update_window_end
858    -------------------------------------------------------------------------- */
860   EmacsView *view = FRAME_NS_VIEW (f);
862 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
863   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
865   block_input ();
867   [view unlockFocus];
868   [[view window] flushWindow];
870   unblock_input ();
871   ns_updating_frame = NULL;
872   NSTRACE (ns_update_end);
875 static void
876 ns_focus (struct frame *f, NSRect *r, int n)
877 /* --------------------------------------------------------------------------
878    Internal: Focus on given frame.  During small local updates this is used to
879      draw, however during large updates, ns_update_begin and ns_update_end are
880      called to wrap the whole thing, in which case these calls are stubbed out.
881      Except, on GNUstep, we accumulate the rectangle being drawn into, because
882      the back end won't do this automatically, and will just end up flushing
883      the entire window.
884    -------------------------------------------------------------------------- */
886 //  NSTRACE (ns_focus);
887 /* static int c =0;
888    fprintf (stderr, "focus: %d", c++);
889    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
890    fprintf (stderr, "\n"); */
892   if (f != ns_updating_frame)
893     {
894       NSView *view = FRAME_NS_VIEW (f);
895       if (view != focus_view)
896         {
897           if (focus_view != NULL)
898             {
899               [focus_view unlockFocus];
900               [[focus_view window] flushWindow];
901 /*debug_lock--; */
902             }
904           if (view)
905             [view lockFocus];
906           focus_view = view;
907 /*if (view) debug_lock++; */
908         }
909     }
911   /* clipping */
912   if (r)
913     {
914       [[NSGraphicsContext currentContext] saveGraphicsState];
915       if (n == 2)
916         NSRectClipList (r, 2);
917       else
918         NSRectClip (*r);
919       gsaved = YES;
920     }
924 static void
925 ns_unfocus (struct frame *f)
926 /* --------------------------------------------------------------------------
927      Internal: Remove focus on given frame
928    -------------------------------------------------------------------------- */
930 //  NSTRACE (ns_unfocus);
932   if (gsaved)
933     {
934       [[NSGraphicsContext currentContext] restoreGraphicsState];
935       gsaved = NO;
936     }
938   if (f != ns_updating_frame)
939     {
940       if (focus_view != NULL)
941         {
942           [focus_view unlockFocus];
943           [[focus_view window] flushWindow];
944           focus_view = NULL;
945 /*debug_lock--; */
946         }
947     }
951 static void
952 ns_clip_to_row (struct window *w, struct glyph_row *row,
953                 enum glyph_row_area area, BOOL gc)
954 /* --------------------------------------------------------------------------
955      Internal (but parallels other terms): Focus drawing on given row
956    -------------------------------------------------------------------------- */
958   struct frame *f = XFRAME (WINDOW_FRAME (w));
959   NSRect clip_rect;
960   int window_x, window_y, window_width;
962   window_box (w, area, &window_x, &window_y, &window_width, 0);
964   clip_rect.origin.x = window_x;
965   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
966   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
967   clip_rect.size.width = window_width;
968   clip_rect.size.height = row->visible_height;
970   ns_focus (f, &clip_rect, 1);
974 static void
975 ns_ring_bell (struct frame *f)
976 /* --------------------------------------------------------------------------
977      "Beep" routine
978    -------------------------------------------------------------------------- */
980   NSTRACE (ns_ring_bell);
981   if (visible_bell)
982     {
983       NSAutoreleasePool *pool;
984       struct frame *frame = SELECTED_FRAME ();
985       NSView *view;
987       block_input ();
988       pool = [[NSAutoreleasePool alloc] init];
990       view = FRAME_NS_VIEW (frame);
991       if (view != nil)
992         {
993           NSRect r, surr;
994           NSPoint dim = NSMakePoint (128, 128);
996           r = [view bounds];
997           r.origin.x += (r.size.width - dim.x) / 2;
998           r.origin.y += (r.size.height - dim.y) / 2;
999           r.size.width = dim.x;
1000           r.size.height = dim.y;
1001           surr = NSInsetRect (r, -2, -2);
1002           ns_focus (frame, &surr, 1);
1003           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
1004           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
1005                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
1006           NSRectFill (r);
1007           [[view window] flushWindow];
1008           ns_timeout (150000);
1009           [[view window] restoreCachedImage];
1010           [[view window] flushWindow];
1011           ns_unfocus (frame);
1012         }
1013       [pool release];
1014       unblock_input ();
1015     }
1016   else
1017     {
1018       NSBeep ();
1019     }
1022 /* ==========================================================================
1024     Frame / window manager related functions
1026    ========================================================================== */
1029 static void
1030 ns_raise_frame (struct frame *f)
1031 /* --------------------------------------------------------------------------
1032      Bring window to foreground and make it active
1033    -------------------------------------------------------------------------- */
1035   NSView *view;
1036   check_window_system (f);
1037   view = FRAME_NS_VIEW (f);
1038   block_input ();
1039   if (FRAME_VISIBLE_P (f))
1040     [[view window] makeKeyAndOrderFront: NSApp];
1041   unblock_input ();
1045 static void
1046 ns_lower_frame (struct frame *f)
1047 /* --------------------------------------------------------------------------
1048      Send window to back
1049    -------------------------------------------------------------------------- */
1051   NSView *view;
1052   check_window_system (f);
1053   view = FRAME_NS_VIEW (f);
1054   block_input ();
1055   [[view window] orderBack: NSApp];
1056   unblock_input ();
1060 static void
1061 ns_frame_raise_lower (struct frame *f, int raise)
1062 /* --------------------------------------------------------------------------
1063      External (hook)
1064    -------------------------------------------------------------------------- */
1066   NSTRACE (ns_frame_raise_lower);
1068   if (raise)
1069     ns_raise_frame (f);
1070   else
1071     ns_lower_frame (f);
1075 static void
1076 ns_frame_rehighlight (struct frame *frame)
1077 /* --------------------------------------------------------------------------
1078      External (hook): called on things like window switching within frame
1079    -------------------------------------------------------------------------- */
1081   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1082   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1084   NSTRACE (ns_frame_rehighlight);
1085   if (dpyinfo->x_focus_frame)
1086     {
1087       dpyinfo->x_highlight_frame
1088         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1089            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1090            : dpyinfo->x_focus_frame);
1091       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1092         {
1093           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1094           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1095         }
1096     }
1097   else
1098       dpyinfo->x_highlight_frame = 0;
1100   if (dpyinfo->x_highlight_frame &&
1101          dpyinfo->x_highlight_frame != old_highlight)
1102     {
1103       if (old_highlight)
1104         {
1105           x_update_cursor (old_highlight, 1);
1106           x_set_frame_alpha (old_highlight);
1107         }
1108       if (dpyinfo->x_highlight_frame)
1109         {
1110           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1111           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1112         }
1113     }
1117 void
1118 x_make_frame_visible (struct frame *f)
1119 /* --------------------------------------------------------------------------
1120      External: Show the window (X11 semantics)
1121    -------------------------------------------------------------------------- */
1123   NSTRACE (x_make_frame_visible);
1124   /* XXX: at some points in past this was not needed, as the only place that
1125      called this (frame.c:Fraise_frame ()) also called raise_lower;
1126      if this ends up the case again, comment this out again. */
1127   if (!FRAME_VISIBLE_P (f))
1128     {
1129       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1131       SET_FRAME_VISIBLE (f, 1);
1132       ns_raise_frame (f);
1134       /* Making a new frame from a fullscreen frame will make the new frame
1135          fullscreen also.  So skip handleFS as this will print an error.  */
1136       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1137           && [view isFullscreen])
1138         return;
1140       if (f->want_fullscreen != FULLSCREEN_NONE)
1141         {
1142           block_input ();
1143           [view handleFS];
1144           unblock_input ();
1145         }
1146     }
1150 void
1151 x_make_frame_invisible (struct frame *f)
1152 /* --------------------------------------------------------------------------
1153      External: Hide the window (X11 semantics)
1154    -------------------------------------------------------------------------- */
1156   NSView *view;
1157   NSTRACE (x_make_frame_invisible);
1158   check_window_system (f);
1159   view = FRAME_NS_VIEW (f);
1160   [[view window] orderOut: NSApp];
1161   SET_FRAME_VISIBLE (f, 0);
1162   SET_FRAME_ICONIFIED (f, 0);
1166 void
1167 x_iconify_frame (struct frame *f)
1168 /* --------------------------------------------------------------------------
1169      External: Iconify window
1170    -------------------------------------------------------------------------- */
1172   NSView *view;
1173   struct ns_display_info *dpyinfo;
1175   NSTRACE (x_iconify_frame);
1176   check_window_system (f);
1177   view = FRAME_NS_VIEW (f);
1178   dpyinfo = FRAME_DISPLAY_INFO (f);
1180   if (dpyinfo->x_highlight_frame == f)
1181     dpyinfo->x_highlight_frame = 0;
1183   if ([[view window] windowNumber] <= 0)
1184     {
1185       /* the window is still deferred.  Make it very small, bring it
1186          on screen and order it out. */
1187       NSRect s = { { 100, 100}, {0, 0} };
1188       NSRect t;
1189       t = [[view window] frame];
1190       [[view window] setFrame: s display: NO];
1191       [[view window] orderBack: NSApp];
1192       [[view window] orderOut: NSApp];
1193       [[view window] setFrame: t display: NO];
1194     }
1195   [[view window] miniaturize: NSApp];
1198 /* Free X resources of frame F.  */
1200 void
1201 x_free_frame_resources (struct frame *f)
1203   NSView *view;
1204   struct ns_display_info *dpyinfo;
1205   Mouse_HLInfo *hlinfo;
1207   NSTRACE (x_free_frame_resources);
1208   check_window_system (f);
1209   view = FRAME_NS_VIEW (f);
1210   dpyinfo = FRAME_DISPLAY_INFO (f);
1211   hlinfo = MOUSE_HL_INFO (f);
1213   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1215   block_input ();
1217   free_frame_menubar (f);
1218   free_frame_faces (f);
1220   if (f == dpyinfo->x_focus_frame)
1221     dpyinfo->x_focus_frame = 0;
1222   if (f == dpyinfo->x_highlight_frame)
1223     dpyinfo->x_highlight_frame = 0;
1224   if (f == hlinfo->mouse_face_mouse_frame)
1225     reset_mouse_highlight (hlinfo);
1227   if (f->output_data.ns->miniimage != nil)
1228     [f->output_data.ns->miniimage release];
1230   [[view window] close];
1231   [view release];
1233   xfree (f->output_data.ns);
1235   unblock_input ();
1238 void
1239 x_destroy_window (struct frame *f)
1240 /* --------------------------------------------------------------------------
1241      External: Delete the window
1242    -------------------------------------------------------------------------- */
1244   NSTRACE (x_destroy_window);
1245   check_window_system (f);
1246   x_free_frame_resources (f);
1247   ns_window_num--;
1251 void
1252 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1253 /* --------------------------------------------------------------------------
1254      External: Position the window
1255    -------------------------------------------------------------------------- */
1257   NSView *view = FRAME_NS_VIEW (f);
1258   NSArray *screens = [NSScreen screens];
1259   NSScreen *fscreen = [screens objectAtIndex: 0];
1260   NSScreen *screen = [[view window] screen];
1262   NSTRACE (x_set_offset);
1264   block_input ();
1266   f->left_pos = xoff;
1267   f->top_pos = yoff;
1269   if (view != nil && screen && fscreen)
1270     {
1271       f->left_pos = f->size_hint_flags & XNegative
1272         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1273         : f->left_pos;
1274       /* We use visibleFrame here to take menu bar into account.
1275          Ideally we should also adjust left/top with visibleFrame.origin.  */
1277       f->top_pos = f->size_hint_flags & YNegative
1278         ? ([screen visibleFrame].size.height + f->top_pos
1279            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1280            - FRAME_TOOLBAR_HEIGHT (f))
1281         : f->top_pos;
1282 #ifdef NS_IMPL_GNUSTEP
1283       if (f->left_pos < 100)
1284         f->left_pos = 100;  /* don't overlap menu */
1285 #endif
1286       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1287          menu bar.  */
1288       [[view window] setFrameTopLeftPoint:
1289                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1290                                     SCREENMAXBOUND ([fscreen frame].size.height
1291                                                     - NS_TOP_POS (f)))];
1292       f->size_hint_flags &= ~(XNegative|YNegative);
1293     }
1295   unblock_input ();
1299 void
1300 x_set_window_size (struct frame *f,
1301                    int change_grav,
1302                    int width,
1303                    int height,
1304                    bool pixelwise)
1305 /* --------------------------------------------------------------------------
1306      Adjust window pixel size based on given character grid size
1307      Impl is a bit more complex than other terms, need to do some
1308      internal clipping.
1309    -------------------------------------------------------------------------- */
1311   EmacsView *view = FRAME_NS_VIEW (f);
1312   NSWindow *window = [view window];
1313   NSRect wr = [window frame];
1314   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1315   int pixelwidth, pixelheight;
1316   int rows, cols;
1318   NSTRACE (x_set_window_size);
1320   if (view == nil)
1321     return;
1323 /*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));*/
1325   block_input ();
1327   check_frame_size (f, &width, &height, pixelwise);
1329   compute_fringe_widths (f, 0);
1331   if (pixelwise)
1332     {
1333       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1334       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1335       cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
1336       rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
1337     }
1338   else
1339     {
1340       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1341       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1342       cols = width;
1343       rows = height;
1344     }
1346   /* If we have a toolbar, take its height into account. */
1347   if (tb && ! [view isFullscreen])
1348     {
1349     /* NOTE: previously this would generate wrong result if toolbar not
1350              yet displayed and fixing toolbar_height=32 helped, but
1351              now (200903) seems no longer needed */
1352     FRAME_TOOLBAR_HEIGHT (f) =
1353       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1354         - FRAME_NS_TITLEBAR_HEIGHT (f);
1355 #ifdef NS_IMPL_GNUSTEP
1356       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1357 #endif
1358     }
1359   else
1360     FRAME_TOOLBAR_HEIGHT (f) = 0;
1362   wr.size.width = pixelwidth + f->border_width;
1363   wr.size.height = pixelheight;
1364   if (! [view isFullscreen])
1365     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1366       + FRAME_TOOLBAR_HEIGHT (f);
1368   /* Do not try to constrain to this screen.  We may have multiple
1369      screens, and want Emacs to span those.  Constraining to screen
1370      prevents that, and that is not nice to the user.  */
1371  if (f->output_data.ns->zooming)
1372    f->output_data.ns->zooming = 0;
1373  else
1374    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1376   [view setRows: rows andColumns: cols];
1377   [window setFrame: wr display: YES];
1379   /* This is a trick to compensate for Emacs' managing the scrollbar area
1380      as a fixed number of standard character columns.  Instead of leaving
1381      blank space for the extra, we chopped it off above.  Now for
1382      left-hand scrollbars, we shift all rendering to the left by the
1383      difference between the real width and Emacs' imagined one.  For
1384      right-hand bars, don't worry about it since the extra is never used.
1385      (Obviously doesn't work for vertically split windows tho..) */
1386   {
1387     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1388       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1389                      - NS_SCROLL_BAR_WIDTH (f), 0)
1390       : NSMakePoint (0, 0);
1391     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1392     [view setBoundsOrigin: origin];
1393   }
1395   change_frame_size (f, width, height, 0, 1, 0, pixelwise);
1396 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1398   mark_window_cursors_off (XWINDOW (f->root_window));
1399   cancel_mouse_face (f);
1401   unblock_input ();
1405 static void
1406 ns_fullscreen_hook (struct frame *f)
1408   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1410   if (!FRAME_VISIBLE_P (f))
1411     return;
1413    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1414     {
1415       /* Old style fs don't initiate correctly if created from
1416          init/default-frame alist, so use a timer (not nice...).
1417       */
1418       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1419                                      selector: @selector (handleFS)
1420                                      userInfo: nil repeats: NO];
1421       return;
1422     }
1424   block_input ();
1425   [view handleFS];
1426   unblock_input ();
1429 /* ==========================================================================
1431     Color management
1433    ========================================================================== */
1436 NSColor *
1437 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1439   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1440   if (idx < 1 || idx >= color_table->avail)
1441     return nil;
1442   return color_table->colors[idx];
1446 unsigned long
1447 ns_index_color (NSColor *color, struct frame *f)
1449   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1450   ptrdiff_t idx;
1451   ptrdiff_t i;
1453   if (!color_table->colors)
1454     {
1455       color_table->size = NS_COLOR_CAPACITY;
1456       color_table->avail = 1; /* skip idx=0 as marker */
1457       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1458       color_table->colors[0] = nil;
1459       color_table->empty_indices = [[NSMutableSet alloc] init];
1460     }
1462   /* Do we already have this color?  */
1463   for (i = 1; i < color_table->avail; i++)
1464     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1465       return i;
1467   if ([color_table->empty_indices count] > 0)
1468     {
1469       NSNumber *index = [color_table->empty_indices anyObject];
1470       [color_table->empty_indices removeObject: index];
1471       idx = [index unsignedLongValue];
1472     }
1473   else
1474     {
1475       if (color_table->avail == color_table->size)
1476         color_table->colors =
1477           xpalloc (color_table->colors, &color_table->size, 1,
1478                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1479       idx = color_table->avail++;
1480     }
1482   color_table->colors[idx] = color;
1483   [color retain];
1484 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1485   return idx;
1489 void
1490 ns_free_indexed_color (unsigned long idx, struct frame *f)
1492   struct ns_color_table *color_table;
1493   NSColor *color;
1494   NSNumber *index;
1496   if (!f)
1497     return;
1499   color_table = FRAME_DISPLAY_INFO (f)->color_table;
1501   if (idx <= 0 || idx >= color_table->size) {
1502     message1 ("ns_free_indexed_color: Color index out of range.\n");
1503     return;
1504   }
1506   index = [NSNumber numberWithUnsignedInt: idx];
1507   if ([color_table->empty_indices containsObject: index]) {
1508     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1509     return;
1510   }
1512   color = color_table->colors[idx];
1513   [color release];
1514   color_table->colors[idx] = nil;
1515   [color_table->empty_indices addObject: index];
1516 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1520 static int
1521 ns_get_color (const char *name, NSColor **col)
1522 /* --------------------------------------------------------------------------
1523      Parse a color name
1524    -------------------------------------------------------------------------- */
1525 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1526    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1527    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1529   NSColor *new = nil;
1530   static char hex[20];
1531   int scaling;
1532   float r = -1.0, g, b;
1533   NSString *nsname = [NSString stringWithUTF8String: name];
1535 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1536   block_input ();
1538   if ([nsname isEqualToString: @"ns_selection_bg_color"])
1539     {
1540 #ifdef NS_IMPL_COCOA
1541       NSString *defname = [[NSUserDefaults standardUserDefaults]
1542                             stringForKey: @"AppleHighlightColor"];
1543       if (defname != nil)
1544         nsname = defname;
1545       else
1546 #endif
1547       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1548         {
1549           *col = [new colorUsingDefaultColorSpace];
1550           unblock_input ();
1551           return 0;
1552         }
1553       else
1554         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1556       name = [nsname UTF8String];
1557     }
1558   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1559     {
1560       /* NOTE: OSX applications normally don't set foreground selection, but
1561          text may be unreadable if we don't.
1562       */
1563       if ((new = [NSColor selectedTextColor]) != nil)
1564         {
1565           *col = [new colorUsingDefaultColorSpace];
1566           unblock_input ();
1567           return 0;
1568         }
1570       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1571       name = [nsname UTF8String];
1572     }
1574   /* First, check for some sort of numeric specification. */
1575   hex[0] = '\0';
1577   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1578     {
1579       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1580       [scanner scanFloat: &r];
1581       [scanner scanFloat: &g];
1582       [scanner scanFloat: &b];
1583     }
1584   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1585     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1586   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1587     {
1588       int len = (strlen(name) - 1);
1589       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1590       int i;
1591       scaling = strlen(name+start) / 3;
1592       for (i = 0; i < 3; i++)
1593         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1594                  name + start + i * scaling);
1595       hex[3 * (scaling + 1) - 1] = '\0';
1596     }
1598   if (hex[0])
1599     {
1600       int rr, gg, bb;
1601       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1602       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1603         {
1604           r = rr / fscale;
1605           g = gg / fscale;
1606           b = bb / fscale;
1607         }
1608     }
1610   if (r >= 0.0F)
1611     {
1612       *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
1613       unblock_input ();
1614       return 0;
1615     }
1617   /* Otherwise, color is expected to be from a list */
1618   {
1619     NSEnumerator *lenum, *cenum;
1620     NSString *name;
1621     NSColorList *clist;
1623 #ifdef NS_IMPL_GNUSTEP
1624     /* XXX: who is wrong, the requestor or the implementation? */
1625     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1626         == NSOrderedSame)
1627       nsname = @"highlightColor";
1628 #endif
1630     lenum = [[NSColorList availableColorLists] objectEnumerator];
1631     while ( (clist = [lenum nextObject]) && new == nil)
1632       {
1633         cenum = [[clist allKeys] objectEnumerator];
1634         while ( (name = [cenum nextObject]) && new == nil )
1635           {
1636             if ([name compare: nsname
1637                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1638               new = [clist colorWithKey: name];
1639           }
1640       }
1641   }
1643   if (new)
1644     *col = [new colorUsingDefaultColorSpace];
1645   unblock_input ();
1646   return new ? 0 : 1;
1651 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1652 /* --------------------------------------------------------------------------
1653      Convert a Lisp string object to a NS color
1654    -------------------------------------------------------------------------- */
1656   NSTRACE (ns_lisp_to_color);
1657   if (STRINGP (color))
1658     return ns_get_color (SSDATA (color), col);
1659   else if (SYMBOLP (color))
1660     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1661   return 1;
1665 Lisp_Object
1666 ns_color_to_lisp (NSColor *col)
1667 /* --------------------------------------------------------------------------
1668      Convert a color to a lisp string with the RGB equivalent
1669    -------------------------------------------------------------------------- */
1671   EmacsCGFloat red, green, blue, alpha, gray;
1672   char buf[1024];
1673   const char *str;
1674   NSTRACE (ns_color_to_lisp);
1676   block_input ();
1677   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1679       if ((str =[[col colorNameComponent] UTF8String]))
1680         {
1681           unblock_input ();
1682           return build_string ((char *)str);
1683         }
1685     [[col colorUsingDefaultColorSpace]
1686         getRed: &red green: &green blue: &blue alpha: &alpha];
1687   if (red == green && red == blue)
1688     {
1689       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1690             getWhite: &gray alpha: &alpha];
1691       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1692                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1693       unblock_input ();
1694       return build_string (buf);
1695     }
1697   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1698             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1700   unblock_input ();
1701   return build_string (buf);
1705 void
1706 ns_query_color(void *col, XColor *color_def, int setPixel)
1707 /* --------------------------------------------------------------------------
1708          Get ARGB values out of NSColor col and put them into color_def.
1709          If setPixel, set the pixel to a concatenated version.
1710          and set color_def pixel to the resulting index.
1711    -------------------------------------------------------------------------- */
1713   EmacsCGFloat r, g, b, a;
1715   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1716   color_def->red   = r * 65535;
1717   color_def->green = g * 65535;
1718   color_def->blue  = b * 65535;
1720   if (setPixel == YES)
1721     color_def->pixel
1722       = ARGB_TO_ULONG((int)(a*255),
1723                       (int)(r*255), (int)(g*255), (int)(b*255));
1727 bool
1728 ns_defined_color (struct frame *f,
1729                   const char *name,
1730                   XColor *color_def,
1731                   bool alloc,
1732                   bool makeIndex)
1733 /* --------------------------------------------------------------------------
1734          Return true if named color found, and set color_def rgb accordingly.
1735          If makeIndex and alloc are nonzero put the color in the color_table,
1736          and set color_def pixel to the resulting index.
1737          If makeIndex is zero, set color_def pixel to ARGB.
1738          Return false if not found
1739    -------------------------------------------------------------------------- */
1741   NSColor *col;
1742   NSTRACE (ns_defined_color);
1744   block_input ();
1745   if (ns_get_color (name, &col) != 0) /* Color not found  */
1746     {
1747       unblock_input ();
1748       return 0;
1749     }
1750   if (makeIndex && alloc)
1751     color_def->pixel = ns_index_color (col, f);
1752   ns_query_color (col, color_def, !makeIndex);
1753   unblock_input ();
1754   return 1;
1758 void
1759 x_set_frame_alpha (struct frame *f)
1760 /* --------------------------------------------------------------------------
1761      change the entire-frame transparency
1762    -------------------------------------------------------------------------- */
1764   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1765   double alpha = 1.0;
1766   double alpha_min = 1.0;
1768   if (dpyinfo->x_highlight_frame == f)
1769     alpha = f->alpha[0];
1770   else
1771     alpha = f->alpha[1];
1773   if (FLOATP (Vframe_alpha_lower_limit))
1774     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1775   else if (INTEGERP (Vframe_alpha_lower_limit))
1776     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1778   if (alpha < 0.0)
1779     return;
1780   else if (1.0 < alpha)
1781     alpha = 1.0;
1782   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1783     alpha = alpha_min;
1785 #ifdef NS_IMPL_COCOA
1786   {
1787     EmacsView *view = FRAME_NS_VIEW (f);
1788   [[view window] setAlphaValue: alpha];
1789   }
1790 #endif
1794 /* ==========================================================================
1796     Mouse handling
1798    ========================================================================== */
1801 void
1802 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1803 /* --------------------------------------------------------------------------
1804      Programmatically reposition mouse pointer in pixel coordinates
1805    -------------------------------------------------------------------------- */
1807   NSTRACE (x_set_mouse_pixel_position);
1808   ns_raise_frame (f);
1809 #if 0
1810   /* FIXME: this does not work, and what about GNUstep? */
1811 #ifdef NS_IMPL_COCOA
1812   [FRAME_NS_VIEW (f) lockFocus];
1813   PSsetmouse ((float)pix_x, (float)pix_y);
1814   [FRAME_NS_VIEW (f) unlockFocus];
1815 #endif
1816 #endif
1820 void
1821 x_set_mouse_position (struct frame *f, int h, int v)
1822 /* --------------------------------------------------------------------------
1823      Programmatically reposition mouse pointer in character coordinates
1824    -------------------------------------------------------------------------- */
1826   int pix_x, pix_y;
1828   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1829   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1831   if (pix_x < 0) pix_x = 0;
1832   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1834   if (pix_y < 0) pix_y = 0;
1835   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1837   x_set_mouse_pixel_position (f, pix_x, pix_y);
1841 static int
1842 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1843 /*   ------------------------------------------------------------------------
1844      Called by EmacsView on mouseMovement events.  Passes on
1845      to emacs mainstream code if we moved off of a rect of interest
1846      known as last_mouse_glyph.
1847      ------------------------------------------------------------------------ */
1849   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1850   NSRect *r;
1852 //  NSTRACE (note_mouse_movement);
1854   dpyinfo->last_mouse_motion_frame = frame;
1855   r = &dpyinfo->last_mouse_glyph;
1857   /* Note, this doesn't get called for enter/leave, since we don't have a
1858      position.  Those are taken care of in the corresponding NSView methods. */
1860   /* has movement gone beyond last rect we were tracking? */
1861   if (x < r->origin.x || x >= r->origin.x + r->size.width
1862       || y < r->origin.y || y >= r->origin.y + r->size.height)
1863     {
1864       ns_update_begin (frame);
1865       frame->mouse_moved = 1;
1866       note_mouse_highlight (frame, x, y);
1867       remember_mouse_glyph (frame, x, y, r);
1868       ns_update_end (frame);
1869       return 1;
1870     }
1872   return 0;
1876 static void
1877 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1878                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1879                    Time *time)
1880 /* --------------------------------------------------------------------------
1881     External (hook): inform emacs about mouse position and hit parts.
1882     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1883     x & y should be position in the scrollbar (the whole bar, not the handle)
1884     and length of scrollbar respectively
1885    -------------------------------------------------------------------------- */
1887   id view;
1888   NSPoint position;
1889   Lisp_Object frame, tail;
1890   struct frame *f;
1891   struct ns_display_info *dpyinfo;
1893   NSTRACE (ns_mouse_position);
1895   if (*fp == NULL)
1896     {
1897       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1898       return;
1899     }
1901   dpyinfo = FRAME_DISPLAY_INFO (*fp);
1903   block_input ();
1905   if (dpyinfo->last_mouse_scroll_bar != nil && insist == 0)
1906     {
1907       /* TODO: we do not use this path at the moment because drag events will
1908            go directly to the EmacsScroller.  Leaving code in for now. */
1909       [dpyinfo->last_mouse_scroll_bar
1910           getMouseMotionPart: (int *)part window: bar_window x: x y: y];
1911       if (time)
1912         *time = dpyinfo->last_mouse_movement_time;
1913       dpyinfo->last_mouse_scroll_bar = nil;
1914     }
1915   else
1916     {
1917       /* Clear the mouse-moved flag for every frame on this display.  */
1918       FOR_EACH_FRAME (tail, frame)
1919         if (FRAME_NS_P (XFRAME (frame))
1920             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1921           XFRAME (frame)->mouse_moved = 0;
1923       dpyinfo->last_mouse_scroll_bar = nil;
1924       if (dpyinfo->last_mouse_frame
1925           && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
1926         f = dpyinfo->last_mouse_frame;
1927       else
1928         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1929                                     : SELECTED_FRAME ();
1931       if (f && FRAME_NS_P (f))
1932         {
1933           view = FRAME_NS_VIEW (*fp);
1935           position = [[view window] mouseLocationOutsideOfEventStream];
1936           position = [view convertPoint: position fromView: nil];
1937           remember_mouse_glyph (f, position.x, position.y,
1938                                 &dpyinfo->last_mouse_glyph);
1939 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1941           if (bar_window) *bar_window = Qnil;
1942           if (part) *part = 0; /*scroll_bar_handle; */
1944           if (x) XSETINT (*x, lrint (position.x));
1945           if (y) XSETINT (*y, lrint (position.y));
1946           if (time)
1947             *time = dpyinfo->last_mouse_movement_time;
1948           *fp = f;
1949         }
1950     }
1952   unblock_input ();
1956 static void
1957 ns_frame_up_to_date (struct frame *f)
1958 /* --------------------------------------------------------------------------
1959     External (hook): Fix up mouse highlighting right after a full update.
1960     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1961    -------------------------------------------------------------------------- */
1963   NSTRACE (ns_frame_up_to_date);
1965   if (FRAME_NS_P (f))
1966     {
1967       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1968       if (f == hlinfo->mouse_face_mouse_frame)
1969         {
1970           block_input ();
1971           ns_update_begin(f);
1972           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1973                                 hlinfo->mouse_face_mouse_x,
1974                                 hlinfo->mouse_face_mouse_y);
1975           ns_update_end(f);
1976           unblock_input ();
1977         }
1978     }
1982 static void
1983 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1984 /* --------------------------------------------------------------------------
1985     External (RIF): set frame mouse pointer type.
1986    -------------------------------------------------------------------------- */
1988   NSTRACE (ns_define_frame_cursor);
1989   if (FRAME_POINTER_TYPE (f) != cursor)
1990     {
1991       EmacsView *view = FRAME_NS_VIEW (f);
1992       FRAME_POINTER_TYPE (f) = cursor;
1993       [[view window] invalidateCursorRectsForView: view];
1994       /* Redisplay assumes this function also draws the changed frame
1995          cursor, but this function doesn't, so do it explicitly.  */
1996       x_update_cursor (f, 1);
1997     }
2002 /* ==========================================================================
2004     Keyboard handling
2006    ========================================================================== */
2009 static unsigned
2010 ns_convert_key (unsigned code)
2011 /* --------------------------------------------------------------------------
2012     Internal call used by NSView-keyDown.
2013    -------------------------------------------------------------------------- */
2015   const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2016   unsigned keysym;
2017   /* An array would be faster, but less easy to read. */
2018   for (keysym = 0; keysym < last_keysym; keysym += 2)
2019     if (code == convert_ns_to_X_keysym[keysym])
2020       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2021   return 0;
2022 /* if decide to use keyCode and Carbon table, use this line:
2023      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2027 char *
2028 x_get_keysym_name (int keysym)
2029 /* --------------------------------------------------------------------------
2030     Called by keyboard.c.  Not sure if the return val is important, except
2031     that it be unique.
2032    -------------------------------------------------------------------------- */
2034   static char value[16];
2035   NSTRACE (x_get_keysym_name);
2036   sprintf (value, "%d", keysym);
2037   return value;
2042 /* ==========================================================================
2044     Block drawing operations
2046    ========================================================================== */
2049 static void
2050 ns_redraw_scroll_bars (struct frame *f)
2052   int i;
2053   id view;
2054   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2055   NSTRACE (ns_redraw_scroll_bars);
2056   for (i =[subviews count]-1; i >= 0; i--)
2057     {
2058       view = [subviews objectAtIndex: i];
2059       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2060       [view display];
2061     }
2065 void
2066 ns_clear_frame (struct frame *f)
2067 /* --------------------------------------------------------------------------
2068       External (hook): Erase the entire frame
2069    -------------------------------------------------------------------------- */
2071   NSView *view = FRAME_NS_VIEW (f);
2072   NSRect r;
2074   NSTRACE (ns_clear_frame);
2076  /* comes on initial frame because we have
2077     after-make-frame-functions = select-frame */
2078  if (!FRAME_DEFAULT_FACE (f))
2079    return;
2081   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2083   r = [view bounds];
2085   block_input ();
2086   ns_focus (f, &r, 1);
2087   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2088   NSRectFill (r);
2089   ns_unfocus (f);
2091   /* as of 2006/11 or so this is now needed */
2092   ns_redraw_scroll_bars (f);
2093   unblock_input ();
2097 static void
2098 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2099 /* --------------------------------------------------------------------------
2100     External (RIF):  Clear section of frame
2101    -------------------------------------------------------------------------- */
2103   NSRect r = NSMakeRect (x, y, width, height);
2104   NSView *view = FRAME_NS_VIEW (f);
2105   struct face *face = FRAME_DEFAULT_FACE (f);
2107   if (!view || !face)
2108     return;
2110   NSTRACE (ns_clear_frame_area);
2112   r = NSIntersectionRect (r, [view frame]);
2113   ns_focus (f, &r, 1);
2114   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2116   NSRectFill (r);
2118   ns_unfocus (f);
2119   return;
2123 static void
2124 ns_scroll_run (struct window *w, struct run *run)
2125 /* --------------------------------------------------------------------------
2126     External (RIF):  Insert or delete n lines at line vpos
2127    -------------------------------------------------------------------------- */
2129   struct frame *f = XFRAME (w->frame);
2130   int x, y, width, height, from_y, to_y, bottom_y;
2132   NSTRACE (ns_scroll_run);
2134   /* begin copy from other terms */
2135   /* Get frame-relative bounding box of the text display area of W,
2136      without mode lines.  Include in this box the left and right
2137      fringe of W.  */
2138   window_box (w, ANY_AREA, &x, &y, &width, &height);
2140   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2141   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2142   bottom_y = y + height;
2144   if (to_y < from_y)
2145     {
2146       /* Scrolling up.  Make sure we don't copy part of the mode
2147          line at the bottom.  */
2148       if (from_y + run->height > bottom_y)
2149         height = bottom_y - from_y;
2150       else
2151         height = run->height;
2152     }
2153   else
2154     {
2155       /* Scrolling down.  Make sure we don't copy over the mode line.
2156          at the bottom.  */
2157       if (to_y + run->height > bottom_y)
2158         height = bottom_y - to_y;
2159       else
2160         height = run->height;
2161     }
2162   /* end copy from other terms */
2164   if (height == 0)
2165       return;
2167   block_input ();
2169   x_clear_cursor (w);
2171   {
2172     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2173     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2174     NSPoint dstOrigin = NSMakePoint (x, to_y);
2176     ns_focus (f, &dstRect, 1);
2177     NSCopyBits (0, srcRect , dstOrigin);
2178     ns_unfocus (f);
2179   }
2181   unblock_input ();
2185 static void
2186 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2187 /* --------------------------------------------------------------------------
2188     External (RIF): preparatory to fringe update after text was updated
2189    -------------------------------------------------------------------------- */
2191   struct frame *f;
2192   int width, height;
2194   NSTRACE (ns_after_update_window_line);
2196   /* begin copy from other terms */
2197   eassert (w);
2199   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2200     desired_row->redraw_fringe_bitmaps_p = 1;
2202   /* When a window has disappeared, make sure that no rest of
2203      full-width rows stays visible in the internal border.  */
2204   if (windows_or_buffers_changed
2205       && desired_row->full_width_p
2206       && (f = XFRAME (w->frame),
2207           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2208           width != 0)
2209       && (height = desired_row->visible_height,
2210           height > 0))
2211     {
2212       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2214       block_input ();
2215       ns_clear_frame_area (f, 0, y, width, height);
2216       ns_clear_frame_area (f,
2217                            FRAME_PIXEL_WIDTH (f) - width,
2218                            y, width, height);
2219       unblock_input ();
2220     }
2224 static void
2225 ns_shift_glyphs_for_insert (struct frame *f,
2226                            int x, int y, int width, int height,
2227                            int shift_by)
2228 /* --------------------------------------------------------------------------
2229     External (RIF): copy an area horizontally, don't worry about clearing src
2230    -------------------------------------------------------------------------- */
2232   NSRect srcRect = NSMakeRect (x, y, width, height);
2233   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2234   NSPoint dstOrigin = dstRect.origin;
2236   NSTRACE (ns_shift_glyphs_for_insert);
2238   ns_focus (f, &dstRect, 1);
2239   NSCopyBits (0, srcRect, dstOrigin);
2240   ns_unfocus (f);
2245 /* ==========================================================================
2247     Character encoding and metrics
2249    ========================================================================== */
2252 static void
2253 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2254 /* --------------------------------------------------------------------------
2255      External (RIF); compute left/right overhang of whole string and set in s
2256    -------------------------------------------------------------------------- */
2258   struct font *font = s->font;
2260   if (s->char2b)
2261     {
2262       struct font_metrics metrics;
2263       unsigned int codes[2];
2264       codes[0] = *(s->char2b);
2265       codes[1] = *(s->char2b + s->nchars - 1);
2267       font->driver->text_extents (font, codes, 2, &metrics);
2268       s->left_overhang = -metrics.lbearing;
2269       s->right_overhang
2270         = metrics.rbearing > metrics.width
2271         ? metrics.rbearing - metrics.width : 0;
2272     }
2273   else
2274     {
2275       s->left_overhang = 0;
2276       if (EQ (font->driver->type, Qns))
2277         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2278           FONT_HEIGHT (font) * 0.2 : 0;
2279       else
2280         s->right_overhang = 0;
2281     }
2286 /* ==========================================================================
2288     Fringe and cursor drawing
2290    ========================================================================== */
2293 extern int max_used_fringe_bitmap;
2294 static void
2295 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2296                       struct draw_fringe_bitmap_params *p)
2297 /* --------------------------------------------------------------------------
2298     External (RIF); fringe-related
2299    -------------------------------------------------------------------------- */
2301   struct frame *f = XFRAME (WINDOW_FRAME (w));
2302   struct face *face = p->face;
2303   static EmacsImage **bimgs = NULL;
2304   static int nBimgs = 0;
2306   /* grow bimgs if needed */
2307   if (nBimgs < max_used_fringe_bitmap)
2308     {
2309       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2310       memset (bimgs + nBimgs, 0,
2311               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2312       nBimgs = max_used_fringe_bitmap;
2313     }
2315   /* Must clip because of partially visible lines.  */
2316   ns_clip_to_row (w, row, ANY_AREA, YES);
2318   if (!p->overlay_p)
2319     {
2320       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2322       /* If the fringe is adjacent to the left (right) scroll bar of a
2323          leftmost (rightmost, respectively) window, then extend its
2324          background to the gap between the fringe and the bar.  */
2325       if ((WINDOW_LEFTMOST_P (w)
2326            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2327           || (WINDOW_RIGHTMOST_P (w)
2328               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2329         {
2330           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2332           if (sb_width > 0)
2333             {
2334               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2335               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2336                                     * FRAME_COLUMN_WIDTH (f));
2338               if (bx < 0)
2339                 {
2340                   /* Bitmap fills the fringe.  */
2341                   if (bar_area_x + bar_area_width == p->x)
2342                     bx = bar_area_x + sb_width;
2343                   else if (p->x + p->wd == bar_area_x)
2344                     bx = bar_area_x;
2345                   if (bx >= 0)
2346                     {
2347                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2349                       nx = bar_area_width - sb_width;
2350                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2351                                                             row->y));
2352                       ny = row->visible_height;
2353                     }
2354                 }
2355               else
2356                 {
2357                   if (bar_area_x + bar_area_width == bx)
2358                     {
2359                       bx = bar_area_x + sb_width;
2360                       nx += bar_area_width - sb_width;
2361                     }
2362                   else if (bx + nx == bar_area_x)
2363                     nx += bar_area_width - sb_width;
2364                 }
2365             }
2366         }
2368       if (bx >= 0 && nx > 0)
2369         {
2370           NSRect r = NSMakeRect (bx, by, nx, ny);
2371           NSRectClip (r);
2372           [ns_lookup_indexed_color (face->background, f) set];
2373           NSRectFill (r);
2374         }
2375     }
2377   if (p->which)
2378     {
2379       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2380       EmacsImage *img = bimgs[p->which - 1];
2382       if (!img)
2383         {
2384           unsigned short *bits = p->bits + p->dh;
2385           int len = p->h;
2386           int i;
2387           unsigned char *cbits = xmalloc (len);
2389           for (i = 0; i < len; i++)
2390             cbits[i] = ~(bits[i] & 0xff);
2391           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2392                                            flip: NO];
2393           bimgs[p->which - 1] = img;
2394           xfree (cbits);
2395         }
2397       NSRectClip (r);
2398       /* Since we composite the bitmap instead of just blitting it, we need
2399          to erase the whole background. */
2400       [ns_lookup_indexed_color(face->background, f) set];
2401       NSRectFill (r);
2402       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2403 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2404       [img drawInRect: r
2405               fromRect: NSZeroRect
2406              operation: NSCompositeSourceOver
2407               fraction: 1.0
2408            respectFlipped: YES
2409                 hints: nil];
2410 #else
2411       {
2412         NSPoint pt = r.origin;
2413         pt.y += p->h;
2414         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2415       }
2416 #endif
2417     }
2418   ns_unfocus (f);
2422 static void
2423 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2424                        int x, int y, enum text_cursor_kinds cursor_type,
2425                        int cursor_width, bool on_p, bool active_p)
2426 /* --------------------------------------------------------------------------
2427      External call (RIF): draw cursor.
2428      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2429    -------------------------------------------------------------------------- */
2431   NSRect r, s;
2432   int fx, fy, h, cursor_height;
2433   struct frame *f = WINDOW_XFRAME (w);
2434   struct glyph *phys_cursor_glyph;
2435   struct glyph *cursor_glyph;
2436   struct face *face;
2437   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2439   /* If cursor is out of bounds, don't draw garbage.  This can happen
2440      in mini-buffer windows when switching between echo area glyphs
2441      and mini-buffer.  */
2443   NSTRACE (dumpcursor);
2445   if (!on_p)
2446     return;
2448   w->phys_cursor_type = cursor_type;
2449   w->phys_cursor_on_p = on_p;
2451   if (cursor_type == NO_CURSOR)
2452     {
2453       w->phys_cursor_width = 0;
2454       return;
2455     }
2457   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2458     {
2459       if (glyph_row->exact_window_width_line_p
2460           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2461         {
2462           glyph_row->cursor_in_fringe_p = 1;
2463           draw_fringe_bitmap (w, glyph_row, 0);
2464         }
2465       return;
2466     }
2468   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2469      (other terminals do it the other way round).  We must set
2470      w->phys_cursor_width to the cursor width.  For bar cursors, that
2471      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2472   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2474   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2475      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2476   if (cursor_type == BAR_CURSOR)
2477     {
2478       if (cursor_width < 1)
2479         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2480       w->phys_cursor_width = cursor_width;
2481     }
2482   /* If we have an HBAR, "cursor_width" MAY specify height. */
2483   else if (cursor_type == HBAR_CURSOR)
2484     {
2485       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2486       fy += h - cursor_height;
2487       h = cursor_height;
2488     }
2490   r.origin.x = fx, r.origin.y = fy;
2491   r.size.height = h;
2492   r.size.width = w->phys_cursor_width;
2494   /* TODO: only needed in rare cases with last-resort font in HELLO..
2495      should we do this more efficiently? */
2496   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2499   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2500   if (face && NS_FACE_BACKGROUND (face)
2501       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2502     {
2503       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2504       hollow_color = FRAME_CURSOR_COLOR (f);
2505     }
2506   else
2507     [FRAME_CURSOR_COLOR (f) set];
2509 #ifdef NS_IMPL_COCOA
2510   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2511            atomic.  Cleaner ways of doing this should be investigated.
2512            One way would be to set a global variable DRAWING_CURSOR
2513            when making the call to draw_phys..(), don't focus in that
2514            case, then move the ns_unfocus() here after that call. */
2515   NSDisableScreenUpdates ();
2516 #endif
2518   switch (cursor_type)
2519     {
2520     case NO_CURSOR:
2521       break;
2522     case FILLED_BOX_CURSOR:
2523       NSRectFill (r);
2524       break;
2525     case HOLLOW_BOX_CURSOR:
2526       NSRectFill (r);
2527       [hollow_color set];
2528       NSRectFill (NSInsetRect (r, 1, 1));
2529       [FRAME_CURSOR_COLOR (f) set];
2530       break;
2531     case HBAR_CURSOR:
2532       NSRectFill (r);
2533       break;
2534     case BAR_CURSOR:
2535       s = r;
2536       /* If the character under cursor is R2L, draw the bar cursor
2537          on the right of its glyph, rather than on the left.  */
2538       cursor_glyph = get_phys_cursor_glyph (w);
2539       if ((cursor_glyph->resolved_level & 1) != 0)
2540         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2542       NSRectFill (s);
2543       break;
2544     }
2545   ns_unfocus (f);
2547   /* draw the character under the cursor */
2548   if (cursor_type != NO_CURSOR)
2549     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2551 #ifdef NS_IMPL_COCOA
2552   NSEnableScreenUpdates ();
2553 #endif
2558 static void
2559 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2560 /* --------------------------------------------------------------------------
2561      External (RIF): Draw a vertical line.
2562    -------------------------------------------------------------------------- */
2564   struct frame *f = XFRAME (WINDOW_FRAME (w));
2565   struct face *face;
2566   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2568   NSTRACE (ns_draw_vertical_window_border);
2570   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2571   if (face)
2572       [ns_lookup_indexed_color(face->foreground, f) set];
2574   ns_focus (f, &r, 1);
2575   NSRectFill(r);
2576   ns_unfocus (f);
2580 static void
2581 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2582 /* --------------------------------------------------------------------------
2583      External (RIF): Draw a window divider.
2584    -------------------------------------------------------------------------- */
2586   struct frame *f = XFRAME (WINDOW_FRAME (w));
2587   struct face *face;
2588   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2590   NSTRACE (ns_draw_window_divider);
2592   face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2593   if (face)
2594       [ns_lookup_indexed_color(face->foreground, f) set];
2596   ns_focus (f, &r, 1);
2597   NSRectFill(r);
2598   ns_unfocus (f);
2602 void
2603 show_hourglass (struct atimer *timer)
2605   if (hourglass_shown_p)
2606     return;
2608   block_input ();
2610   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2612   hourglass_shown_p = 1;
2613   unblock_input ();
2617 void
2618 hide_hourglass (void)
2620   if (!hourglass_shown_p)
2621     return;
2623   block_input ();
2625   /* TODO: remove NSProgressIndicator from all frames */
2627   hourglass_shown_p = 0;
2628   unblock_input ();
2633 /* ==========================================================================
2635     Glyph drawing operations
2637    ========================================================================== */
2639 static int
2640 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2641 /* --------------------------------------------------------------------------
2642     Wrapper utility to account for internal border width on full-width lines,
2643     and allow top full-width rows to hit the frame top.  nr should be pointer
2644     to two successive NSRects.  Number of rects actually used is returned.
2645    -------------------------------------------------------------------------- */
2647   int n = get_glyph_string_clip_rects (s, nr, 2);
2648   return n;
2651 /* --------------------------------------------------------------------
2652    Draw a wavy line under glyph string s. The wave fills wave_height
2653    pixels from y.
2655                     x          wave_length = 2
2656                                  --
2657                 y    *   *   *   *   *
2658                      |* * * * * * * * *
2659     wave_height = 3  | *   *   *   *
2660   --------------------------------------------------------------------- */
2662 static void
2663 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2665   int wave_height = 3, wave_length = 2;
2666   int y, dx, dy, odd, xmax;
2667   NSPoint a, b;
2668   NSRect waveClip;
2670   dx = wave_length;
2671   dy = wave_height - 1;
2672   y =  s->ybase - wave_height + 3;
2673   xmax = x + width;
2675   /* Find and set clipping rectangle */
2676   waveClip = NSMakeRect (x, y, width, wave_height);
2677   [[NSGraphicsContext currentContext] saveGraphicsState];
2678   NSRectClip (waveClip);
2680   /* Draw the waves */
2681   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2682   b.x = a.x + dx;
2683   odd = (int)(a.x/dx) % 2;
2684   a.y = b.y = y + 0.5;
2686   if (odd)
2687     a.y += dy;
2688   else
2689     b.y += dy;
2691   while (a.x <= xmax)
2692     {
2693       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2694       a.x = b.x, a.y = b.y;
2695       b.x += dx, b.y = y + 0.5 + odd*dy;
2696       odd = !odd;
2697     }
2699   /* Restore previous clipping rectangle(s) */
2700   [[NSGraphicsContext currentContext] restoreGraphicsState];
2705 void
2706 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2707                          NSColor *defaultCol, CGFloat width, CGFloat x)
2708 /* --------------------------------------------------------------------------
2709    Draw underline, overline, and strike-through on glyph string s.
2710    -------------------------------------------------------------------------- */
2712   if (s->for_overlaps)
2713     return;
2715   /* Do underline. */
2716   if (face->underline_p)
2717     {
2718       if (s->face->underline_type == FACE_UNDER_WAVE)
2719         {
2720           if (face->underline_defaulted_p)
2721             [defaultCol set];
2722           else
2723             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2725           ns_draw_underwave (s, width, x);
2726         }
2727       else if (s->face->underline_type == FACE_UNDER_LINE)
2728         {
2730           NSRect r;
2731           unsigned long thickness, position;
2733           /* If the prev was underlined, match its appearance. */
2734           if (s->prev && s->prev->face->underline_p
2735               && s->prev->face->underline_type == FACE_UNDER_LINE
2736               && s->prev->underline_thickness > 0)
2737             {
2738               thickness = s->prev->underline_thickness;
2739               position = s->prev->underline_position;
2740             }
2741           else
2742             {
2743               struct font *font;
2744               unsigned long descent;
2746               font=s->font;
2747               descent = s->y + s->height - s->ybase;
2749               /* Use underline thickness of font, defaulting to 1. */
2750               thickness = (font && font->underline_thickness > 0)
2751                 ? font->underline_thickness : 1;
2753               /* Determine the offset of underlining from the baseline. */
2754               if (x_underline_at_descent_line)
2755                 position = descent - thickness;
2756               else if (x_use_underline_position_properties
2757                        && font && font->underline_position >= 0)
2758                 position = font->underline_position;
2759               else if (font)
2760                 position = lround (font->descent / 2);
2761               else
2762                 position = underline_minimum_offset;
2764               position = max (position, underline_minimum_offset);
2766               /* Ensure underlining is not cropped. */
2767               if (descent <= position)
2768                 {
2769                   position = descent - 1;
2770                   thickness = 1;
2771                 }
2772               else if (descent < position + thickness)
2773                 thickness = 1;
2774             }
2776           s->underline_thickness = thickness;
2777           s->underline_position = position;
2779           r = NSMakeRect (x, s->ybase + position, width, thickness);
2781           if (face->underline_defaulted_p)
2782             [defaultCol set];
2783           else
2784             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2785           NSRectFill (r);
2786         }
2787     }
2788   /* Do overline. We follow other terms in using a thickness of 1
2789      and ignoring overline_margin. */
2790   if (face->overline_p)
2791     {
2792       NSRect r;
2793       r = NSMakeRect (x, s->y, width, 1);
2795       if (face->overline_color_defaulted_p)
2796         [defaultCol set];
2797       else
2798         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2799       NSRectFill (r);
2800     }
2802   /* Do strike-through.  We follow other terms for thickness and
2803      vertical position.*/
2804   if (face->strike_through_p)
2805     {
2806       NSRect r;
2807       unsigned long dy;
2809       dy = lrint ((s->height - 1) / 2);
2810       r = NSMakeRect (x, s->y + dy, width, 1);
2812       if (face->strike_through_color_defaulted_p)
2813         [defaultCol set];
2814       else
2815         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2816       NSRectFill (r);
2817     }
2820 static void
2821 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2822              char left_p, char right_p)
2823 /* --------------------------------------------------------------------------
2824     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2825     Note we can't just use an NSDrawRect command, because of the possibility
2826     of some sides not being drawn, and because the rect will be filled.
2827    -------------------------------------------------------------------------- */
2829   NSRect s = r;
2830   [col set];
2832   /* top, bottom */
2833   s.size.height = thickness;
2834   NSRectFill (s);
2835   s.origin.y += r.size.height - thickness;
2836   NSRectFill (s);
2838   s.size.height = r.size.height;
2839   s.origin.y = r.origin.y;
2841   /* left, right (optional) */
2842   s.size.width = thickness;
2843   if (left_p)
2844     NSRectFill (s);
2845   if (right_p)
2846     {
2847       s.origin.x += r.size.width - thickness;
2848       NSRectFill (s);
2849     }
2853 static void
2854 ns_draw_relief (NSRect r, int thickness, char raised_p,
2855                char top_p, char bottom_p, char left_p, char right_p,
2856                struct glyph_string *s)
2857 /* --------------------------------------------------------------------------
2858     Draw a relief rect inside r, optionally leaving some sides open.
2859     Note we can't just use an NSDrawBezel command, because of the possibility
2860     of some sides not being drawn, and because the rect will be filled.
2861    -------------------------------------------------------------------------- */
2863   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2864   NSColor *newBaseCol = nil;
2865   NSRect sr = r;
2867   NSTRACE (ns_draw_relief);
2869   /* set up colors */
2871   if (s->face->use_box_color_for_shadows_p)
2872     {
2873       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2874     }
2875 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2876            && s->img->pixmap
2877            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2878        {
2879          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2880        } */
2881   else
2882     {
2883       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2884     }
2886   if (newBaseCol == nil)
2887     newBaseCol = [NSColor grayColor];
2889   if (newBaseCol != baseCol)  /* TODO: better check */
2890     {
2891       [baseCol release];
2892       baseCol = [newBaseCol retain];
2893       [lightCol release];
2894       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2895       [darkCol release];
2896       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2897     }
2899   [(raised_p ? lightCol : darkCol) set];
2901   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2903   /* top */
2904   sr.size.height = thickness;
2905   if (top_p) NSRectFill (sr);
2907   /* left */
2908   sr.size.height = r.size.height;
2909   sr.size.width = thickness;
2910   if (left_p) NSRectFill (sr);
2912   [(raised_p ? darkCol : lightCol) set];
2914   /* bottom */
2915   sr.size.width = r.size.width;
2916   sr.size.height = thickness;
2917   sr.origin.y += r.size.height - thickness;
2918   if (bottom_p) NSRectFill (sr);
2920   /* right */
2921   sr.size.height = r.size.height;
2922   sr.origin.y = r.origin.y;
2923   sr.size.width = thickness;
2924   sr.origin.x += r.size.width - thickness;
2925   if (right_p) NSRectFill (sr);
2929 static void
2930 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2931 /* --------------------------------------------------------------------------
2932       Function modeled after x_draw_glyph_string_box ().
2933       Sets up parameters for drawing.
2934    -------------------------------------------------------------------------- */
2936   int right_x, last_x;
2937   char left_p, right_p;
2938   struct glyph *last_glyph;
2939   NSRect r;
2940   int thickness;
2941   struct face *face;
2943   if (s->hl == DRAW_MOUSE_FACE)
2944     {
2945       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2946       if (!face)
2947         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2948     }
2949   else
2950     face = s->face;
2952   thickness = face->box_line_width;
2954   NSTRACE (ns_dumpglyphs_box_or_relief);
2956   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2957             ? WINDOW_RIGHT_EDGE_X (s->w)
2958             : window_box_right (s->w, s->area));
2959   last_glyph = (s->cmp || s->img
2960                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2962   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2963               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2965   left_p = (s->first_glyph->left_box_line_p
2966             || (s->hl == DRAW_MOUSE_FACE
2967                 && (s->prev == NULL || s->prev->hl != s->hl)));
2968   right_p = (last_glyph->right_box_line_p
2969              || (s->hl == DRAW_MOUSE_FACE
2970                  && (s->next == NULL || s->next->hl != s->hl)));
2972   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2974   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2975   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2976     {
2977       ns_draw_box (r, abs (thickness),
2978                    ns_lookup_indexed_color (face->box_color, s->f),
2979                   left_p, right_p);
2980     }
2981   else
2982     {
2983       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2984                      1, 1, left_p, right_p, s);
2985     }
2989 static void
2990 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2991 /* --------------------------------------------------------------------------
2992       Modeled after x_draw_glyph_string_background, which draws BG in
2993       certain cases.  Others are left to the text rendering routine.
2994    -------------------------------------------------------------------------- */
2996   NSTRACE (ns_maybe_dumpglyphs_background);
2998   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2999     {
3000       int box_line_width = max (s->face->box_line_width, 0);
3001       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3002           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3003         {
3004           struct face *face;
3005           if (s->hl == DRAW_MOUSE_FACE)
3006             {
3007               face = FACE_FROM_ID (s->f,
3008                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3009               if (!face)
3010                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3011             }
3012           else
3013             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3014           if (!face->stipple)
3015             [(NS_FACE_BACKGROUND (face) != 0
3016               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3017               : FRAME_BACKGROUND_COLOR (s->f)) set];
3018           else
3019             {
3020               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3021               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3022             }
3024           if (s->hl != DRAW_CURSOR)
3025             {
3026               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3027                                     s->background_width,
3028                                     s->height-2*box_line_width);
3029               NSRectFill (r);
3030             }
3032           s->background_filled_p = 1;
3033         }
3034     }
3038 static void
3039 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3040 /* --------------------------------------------------------------------------
3041       Renders an image and associated borders.
3042    -------------------------------------------------------------------------- */
3044   EmacsImage *img = s->img->pixmap;
3045   int box_line_vwidth = max (s->face->box_line_width, 0);
3046   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3047   int bg_x, bg_y, bg_height;
3048   int th;
3049   char raised_p;
3050   NSRect br;
3051   struct face *face;
3052   NSColor *tdCol;
3054   NSTRACE (ns_dumpglyphs_image);
3056   if (s->face->box != FACE_NO_BOX
3057       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3058     x += abs (s->face->box_line_width);
3060   bg_x = x;
3061   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3062   bg_height = s->height;
3063   /* other terms have this, but was causing problems w/tabbar mode */
3064   /* - 2 * box_line_vwidth; */
3066   if (s->slice.x == 0) x += s->img->hmargin;
3067   if (s->slice.y == 0) y += s->img->vmargin;
3069   /* Draw BG: if we need larger area than image itself cleared, do that,
3070      otherwise, since we composite the image under NS (instead of mucking
3071      with its background color), we must clear just the image area. */
3072   if (s->hl == DRAW_MOUSE_FACE)
3073     {
3074       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3075       if (!face)
3076        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3077     }
3078   else
3079     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3081   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3083   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3084       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3085     {
3086       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3087       s->background_filled_p = 1;
3088     }
3089   else
3090     {
3091       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3092     }
3094   NSRectFill (br);
3096   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3097   if (img != nil)
3098     {
3099 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
3100       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3101       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3102                               s->slice.width, s->slice.height);
3103       [img drawInRect: dr
3104              fromRect: ir
3105              operation: NSCompositeSourceOver
3106               fraction: 1.0
3107            respectFlipped: YES
3108                 hints: nil];
3109 #else
3110       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3111                   operation: NSCompositeSourceOver];
3112 #endif
3113     }
3115   if (s->hl == DRAW_CURSOR)
3116     {
3117     [FRAME_CURSOR_COLOR (s->f) set];
3118     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3119       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3120     else
3121       /* Currently on NS img->mask is always 0. Since
3122          get_window_cursor_type specifies a hollow box cursor when on
3123          a non-masked image we never reach this clause. But we put it
3124          in in anticipation of better support for image masks on
3125          NS. */
3126       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3127     }
3128   else
3129     {
3130       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3131     }
3133   /* Draw underline, overline, strike-through. */
3134   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3136   /* Draw relief, if requested */
3137   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3138     {
3139       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3140         {
3141           th = tool_bar_button_relief >= 0 ?
3142             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3143           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3144         }
3145       else
3146         {
3147           th = abs (s->img->relief);
3148           raised_p = (s->img->relief > 0);
3149         }
3151       r.origin.x = x - th;
3152       r.origin.y = y - th;
3153       r.size.width = s->slice.width + 2*th-1;
3154       r.size.height = s->slice.height + 2*th-1;
3155       ns_draw_relief (r, th, raised_p,
3156                       s->slice.y == 0,
3157                       s->slice.y + s->slice.height == s->img->height,
3158                       s->slice.x == 0,
3159                       s->slice.x + s->slice.width == s->img->width, s);
3160     }
3162   /* If there is no mask, the background won't be seen,
3163      so draw a rectangle on the image for the cursor.
3164      Do this for all images, getting transparency right is not reliable.  */
3165   if (s->hl == DRAW_CURSOR)
3166     {
3167       int thickness = abs (s->img->relief);
3168       if (thickness == 0) thickness = 1;
3169       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3170     }
3174 static void
3175 ns_dumpglyphs_stretch (struct glyph_string *s)
3177   NSRect r[2];
3178   int n, i;
3179   struct face *face;
3180   NSColor *fgCol, *bgCol;
3182   if (!s->background_filled_p)
3183     {
3184       n = ns_get_glyph_string_clip_rect (s, r);
3185       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3187       ns_focus (s->f, r, n);
3189       if (s->hl == DRAW_MOUSE_FACE)
3190        {
3191          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3192          if (!face)
3193            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3194        }
3195       else
3196        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3198       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3199       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3201       for (i = 0; i < n; ++i)
3202         {
3203           if (!s->row->full_width_p)
3204             {
3205               int overrun, leftoverrun;
3207               /* truncate to avoid overwriting fringe and/or scrollbar */
3208               overrun = max (0, (s->x + s->background_width)
3209                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3210                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3211               r[i].size.width -= overrun;
3213               /* truncate to avoid overwriting to left of the window box */
3214               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3215                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3217               if (leftoverrun > 0)
3218                 {
3219                   r[i].origin.x += leftoverrun;
3220                   r[i].size.width -= leftoverrun;
3221                 }
3223               /* XXX: Try to work between problem where a stretch glyph on
3224                  a partially-visible bottom row will clear part of the
3225                  modeline, and another where list-buffers headers and similar
3226                  rows erroneously have visible_height set to 0.  Not sure
3227                  where this is coming from as other terms seem not to show. */
3228               r[i].size.height = min (s->height, s->row->visible_height);
3229             }
3231           [bgCol set];
3233           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3234              overwriting cursor (usually when cursor on a tab) */
3235           if (s->hl == DRAW_CURSOR)
3236             {
3237               CGFloat x, width;
3239               x = r[i].origin.x;
3240               width = s->w->phys_cursor_width;
3241               r[i].size.width -= width;
3242               r[i].origin.x += width;
3244               NSRectFill (r[i]);
3246               /* Draw overlining, etc. on the cursor. */
3247               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3248                 ns_draw_text_decoration (s, face, bgCol, width, x);
3249               else
3250                 ns_draw_text_decoration (s, face, fgCol, width, x);
3251             }
3252           else
3253             {
3254               NSRectFill (r[i]);
3255             }
3257           /* Draw overlining, etc. on the stretch glyph (or the part
3258              of the stretch glyph after the cursor). */
3259           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3260                                    r[i].origin.x);
3261         }
3262       ns_unfocus (s->f);
3263       s->background_filled_p = 1;
3264     }
3268 static void
3269 ns_draw_glyph_string (struct glyph_string *s)
3270 /* --------------------------------------------------------------------------
3271       External (RIF): Main draw-text call.
3272    -------------------------------------------------------------------------- */
3274   /* TODO (optimize): focus for box and contents draw */
3275   NSRect r[2];
3276   int n, flags;
3277   char box_drawn_p = 0;
3278   struct font *font = s->face->font;
3279   if (! font) font = FRAME_FONT (s->f);
3281   NSTRACE (ns_draw_glyph_string);
3283   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3284     {
3285       int width;
3286       struct glyph_string *next;
3288       for (width = 0, next = s->next;
3289            next && width < s->right_overhang;
3290            width += next->width, next = next->next)
3291         if (next->first_glyph->type != IMAGE_GLYPH)
3292           {
3293             if (next->first_glyph->type != STRETCH_GLYPH)
3294               {
3295                 n = ns_get_glyph_string_clip_rect (s->next, r);
3296                 ns_focus (s->f, r, n);
3297                 ns_maybe_dumpglyphs_background (s->next, 1);
3298                 ns_unfocus (s->f);
3299               }
3300             else
3301               {
3302                 ns_dumpglyphs_stretch (s->next);
3303               }
3304             next->num_clips = 0;
3305           }
3306     }
3308   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3309         && (s->first_glyph->type == CHAR_GLYPH
3310             || s->first_glyph->type == COMPOSITE_GLYPH))
3311     {
3312       n = ns_get_glyph_string_clip_rect (s, r);
3313       ns_focus (s->f, r, n);
3314       ns_maybe_dumpglyphs_background (s, 1);
3315       ns_dumpglyphs_box_or_relief (s);
3316       ns_unfocus (s->f);
3317       box_drawn_p = 1;
3318     }
3320   switch (s->first_glyph->type)
3321     {
3323     case IMAGE_GLYPH:
3324       n = ns_get_glyph_string_clip_rect (s, r);
3325       ns_focus (s->f, r, n);
3326       ns_dumpglyphs_image (s, r[0]);
3327       ns_unfocus (s->f);
3328       break;
3330     case STRETCH_GLYPH:
3331       ns_dumpglyphs_stretch (s);
3332       break;
3334     case CHAR_GLYPH:
3335     case COMPOSITE_GLYPH:
3336       n = ns_get_glyph_string_clip_rect (s, r);
3337       ns_focus (s->f, r, n);
3339       if (s->for_overlaps || (s->cmp_from > 0
3340                               && ! s->first_glyph->u.cmp.automatic))
3341         s->background_filled_p = 1;
3342       else
3343         ns_maybe_dumpglyphs_background
3344           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3346       flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3347         (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3348          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3349           NS_DUMPGLYPH_NORMAL));
3351       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3352         {
3353           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3354           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3355           NS_FACE_FOREGROUND (s->face) = tmp;
3356         }
3358       font->driver->draw
3359         (s, 0, s->nchars, s->x, s->y,
3360          (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3361          || flags == NS_DUMPGLYPH_MOUSEFACE);
3363       {
3364         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3365                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3366                                                    s->f)
3367                         : FRAME_FOREGROUND_COLOR (s->f));
3368         [col set];
3370         /* Draw underline, overline, strike-through. */
3371         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3372       }
3374       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3375         {
3376           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3377           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3378           NS_FACE_FOREGROUND (s->face) = tmp;
3379         }
3381       ns_unfocus (s->f);
3382       break;
3384     case GLYPHLESS_GLYPH:
3385       n = ns_get_glyph_string_clip_rect (s, r);
3386       ns_focus (s->f, r, n);
3388       if (s->for_overlaps || (s->cmp_from > 0
3389                               && ! s->first_glyph->u.cmp.automatic))
3390         s->background_filled_p = 1;
3391       else
3392         ns_maybe_dumpglyphs_background
3393           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3394       /* ... */
3395       /* Not yet implemented.  */
3396       /* ... */
3397       ns_unfocus (s->f);
3398       break;
3400     default:
3401       emacs_abort ();
3402     }
3404   /* Draw box if not done already. */
3405   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3406     {
3407       n = ns_get_glyph_string_clip_rect (s, r);
3408       ns_focus (s->f, r, n);
3409       ns_dumpglyphs_box_or_relief (s);
3410       ns_unfocus (s->f);
3411     }
3413   s->num_clips = 0;
3418 /* ==========================================================================
3420     Event loop
3422    ========================================================================== */
3425 static void
3426 ns_send_appdefined (int value)
3427 /* --------------------------------------------------------------------------
3428     Internal: post an appdefined event which EmacsApp-sendEvent will
3429               recognize and take as a command to halt the event loop.
3430    -------------------------------------------------------------------------- */
3432   /*NSTRACE (ns_send_appdefined); */
3434 #ifdef NS_IMPL_GNUSTEP
3435   // GNUstep needs postEvent to happen on the main thread.
3436   if (! [[NSThread currentThread] isMainThread])
3437     {
3438       EmacsApp *app = (EmacsApp *)NSApp;
3439       app->nextappdefined = value;
3440       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3441                             withObject:nil
3442                          waitUntilDone:YES];
3443       return;
3444     }
3445 #endif
3447   /* Only post this event if we haven't already posted one.  This will end
3448        the [NXApp run] main loop after having processed all events queued at
3449        this moment.  */
3450   if (send_appdefined)
3451     {
3452       NSEvent *nxev;
3454       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3455       send_appdefined = NO;
3457       /* Don't need wakeup timer any more */
3458       if (timed_entry)
3459         {
3460           [timed_entry invalidate];
3461           [timed_entry release];
3462           timed_entry = nil;
3463         }
3465       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3466                                 location: NSMakePoint (0, 0)
3467                            modifierFlags: 0
3468                                timestamp: 0
3469                             windowNumber: [[NSApp mainWindow] windowNumber]
3470                                  context: [NSApp context]
3471                                  subtype: 0
3472                                    data1: value
3473                                    data2: 0];
3475       /* Post an application defined event on the event queue.  When this is
3476          received the [NXApp run] will return, thus having processed all
3477          events which are currently queued.  */
3478       [NSApp postEvent: nxev atStart: NO];
3479     }
3482 #ifdef HAVE_NATIVE_FS
3483 static void
3484 check_native_fs ()
3486   Lisp_Object frame, tail;
3488   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3489     return;
3491   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3493   FOR_EACH_FRAME (tail, frame)
3494     {
3495       struct frame *f = XFRAME (frame);
3496       if (FRAME_NS_P (f))
3497         {
3498           EmacsView *view = FRAME_NS_VIEW (f);
3499           [view updateCollectionBehavior];
3500         }
3501     }
3503 #endif
3505 /* GNUstep and OSX <= 10.4 does not have cancelTracking.  */
3506 #if defined (NS_IMPL_COCOA) && \
3507   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
3508 /* Check if menu open should be canceled or continued as normal.  */
3509 void
3510 ns_check_menu_open (NSMenu *menu)
3512   /* Click in menu bar? */
3513   NSArray *a = [[NSApp mainMenu] itemArray];
3514   int i;
3515   BOOL found = NO;
3517   if (menu == nil) // Menu tracking ended.
3518     {
3519       if (menu_will_open_state == MENU_OPENING)
3520         menu_will_open_state = MENU_NONE;
3521       return;
3522     }
3524   for (i = 0; ! found && i < [a count]; i++)
3525     found = menu == [[a objectAtIndex:i] submenu];
3526   if (found)
3527     {
3528       if (menu_will_open_state == MENU_NONE && emacs_event)
3529         {
3530           NSEvent *theEvent = [NSApp currentEvent];
3531           struct frame *emacsframe = SELECTED_FRAME ();
3533           [menu cancelTracking];
3534           menu_will_open_state = MENU_PENDING;
3535           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3536           EV_TRAILER (theEvent);
3538           CGEventRef ourEvent = CGEventCreate (NULL);
3539           menu_mouse_point = CGEventGetLocation (ourEvent);
3540           CFRelease (ourEvent);
3541         }
3542       else if (menu_will_open_state == MENU_OPENING)
3543         {
3544           menu_will_open_state = MENU_NONE;
3545         }
3546     }
3549 /* Redo saved menu click if state is MENU_PENDING.  */
3550 void
3551 ns_check_pending_open_menu ()
3553   if (menu_will_open_state == MENU_PENDING)
3554     {
3555       CGEventSourceRef source
3556         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3558       CGEventRef event = CGEventCreateMouseEvent (source,
3559                                                   kCGEventLeftMouseDown,
3560                                                   menu_mouse_point,
3561                                                   kCGMouseButtonLeft);
3562       CGEventSetType (event, kCGEventLeftMouseDown);
3563       CGEventPost (kCGHIDEventTap, event);
3564       CFRelease (event);
3565       CFRelease (source);
3567       menu_will_open_state = MENU_OPENING;
3568     }
3570 #endif /* NS_IMPL_COCOA) && >= MAC_OS_X_VERSION_10_5 */
3572 static int
3573 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3574 /* --------------------------------------------------------------------------
3575      External (hook): Post an event to ourself and keep reading events until
3576      we read it back again.  In effect process all events which were waiting.
3577      From 21+ we have to manage the event buffer ourselves.
3578    -------------------------------------------------------------------------- */
3580   struct input_event ev;
3581   int nevents;
3583 /* NSTRACE (ns_read_socket); */
3585 #ifdef HAVE_NATIVE_FS
3586   check_native_fs ();
3587 #endif
3589   if ([NSApp modalWindow] != nil)
3590     return -1;
3592   if (hold_event_q.nr > 0)
3593     {
3594       int i;
3595       for (i = 0; i < hold_event_q.nr; ++i)
3596         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3597       hold_event_q.nr = 0;
3598       return i;
3599     }
3601   block_input ();
3602   n_emacs_events_pending = 0;
3603   EVENT_INIT (ev);
3604   emacs_event = &ev;
3605   q_event_ptr = hold_quit;
3607   /* we manage autorelease pools by allocate/reallocate each time around
3608      the loop; strict nesting is occasionally violated but seems not to
3609      matter.. earlier methods using full nesting caused major memory leaks */
3610   [outerpool release];
3611   outerpool = [[NSAutoreleasePool alloc] init];
3613   /* If have pending open-file requests, attend to the next one of those. */
3614   if (ns_pending_files && [ns_pending_files count] != 0
3615       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3616     {
3617       [ns_pending_files removeObjectAtIndex: 0];
3618     }
3619   /* Deal with pending service requests. */
3620   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3621     && [(EmacsApp *)
3622          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3623                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3624     {
3625       [ns_pending_service_names removeObjectAtIndex: 0];
3626       [ns_pending_service_args removeObjectAtIndex: 0];
3627     }
3628   else
3629     {
3630       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3631          to ourself, otherwise [NXApp run] will never exit.  */
3632       send_appdefined = YES;
3633       ns_send_appdefined (-1);
3635       if (++apploopnr != 1)
3636         {
3637           emacs_abort ();
3638         }
3639       [NSApp run];
3640       --apploopnr;
3641     }
3643   nevents = n_emacs_events_pending;
3644   n_emacs_events_pending = 0;
3645   emacs_event = q_event_ptr = NULL;
3646   unblock_input ();
3648   return nevents;
3653 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3654            fd_set *exceptfds, struct timespec const *timeout,
3655            sigset_t const *sigmask)
3656 /* --------------------------------------------------------------------------
3657      Replacement for select, checking for events
3658    -------------------------------------------------------------------------- */
3660   int result;
3661   int t, k, nr = 0;
3662   struct input_event event;
3663   char c;
3665 /*  NSTRACE (ns_select); */
3667 #ifdef HAVE_NATIVE_FS
3668   check_native_fs ();
3669 #endif
3671   if (hold_event_q.nr > 0)
3672     {
3673       /* We already have events pending. */
3674       raise (SIGIO);
3675       errno = EINTR;
3676       return -1;
3677     }
3679   for (k = 0; k < nfds+1; k++)
3680     {
3681       if (readfds && FD_ISSET(k, readfds)) ++nr;
3682       if (writefds && FD_ISSET(k, writefds)) ++nr;
3683     }
3685   if (NSApp == nil
3686       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3687     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3689   [outerpool release];
3690   outerpool = [[NSAutoreleasePool alloc] init];
3693   send_appdefined = YES;
3694   if (nr > 0)
3695     {
3696       pthread_mutex_lock (&select_mutex);
3697       select_nfds = nfds;
3698       select_valid = 0;
3699       if (readfds)
3700         {
3701           select_readfds = *readfds;
3702           select_valid += SELECT_HAVE_READ;
3703         }
3704       if (writefds)
3705         {
3706           select_writefds = *writefds;
3707           select_valid += SELECT_HAVE_WRITE;
3708         }
3710       if (timeout)
3711         {
3712           select_timeout = *timeout;
3713           select_valid += SELECT_HAVE_TMO;
3714         }
3716       pthread_mutex_unlock (&select_mutex);
3718       /* Inform fd_handler that select should be called */
3719       c = 'g';
3720       emacs_write_sig (selfds[1], &c, 1);
3721     }
3722   else if (nr == 0 && timeout)
3723     {
3724       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3725       double time = timespectod (*timeout);
3726       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3727                                                       target: NSApp
3728                                                     selector:
3729                                   @selector (timeout_handler:)
3730                                                     userInfo: 0
3731                                                      repeats: NO]
3732                       retain];
3733     }
3734   else /* No timeout and no file descriptors, can this happen?  */
3735     {
3736       /* Send appdefined so we exit from the loop */
3737       ns_send_appdefined (-1);
3738     }
3740   EVENT_INIT (event);
3741   block_input ();
3742   emacs_event = &event;
3743   if (++apploopnr != 1)
3744     {
3745       emacs_abort ();
3746     }
3747   [NSApp run];
3748   --apploopnr;
3749   emacs_event = NULL;
3750   if (nr > 0 && readfds)
3751     {
3752       c = 's';
3753       emacs_write_sig (selfds[1], &c, 1);
3754     }
3755   unblock_input ();
3757   t = last_appdefined_event_data;
3759   if (t != NO_APPDEFINED_DATA)
3760     {
3761       last_appdefined_event_data = NO_APPDEFINED_DATA;
3763       if (t == -2)
3764         {
3765           /* The NX_APPDEFINED event we received was a timeout. */
3766           result = 0;
3767         }
3768       else if (t == -1)
3769         {
3770           /* The NX_APPDEFINED event we received was the result of
3771              at least one real input event arriving.  */
3772           errno = EINTR;
3773           result = -1;
3774         }
3775       else
3776         {
3777           /* Received back from select () in fd_handler; copy the results */
3778           pthread_mutex_lock (&select_mutex);
3779           if (readfds) *readfds = select_readfds;
3780           if (writefds) *writefds = select_writefds;
3781           pthread_mutex_unlock (&select_mutex);
3782           result = t;
3783         }
3784     }
3785   else
3786     {
3787       errno = EINTR;
3788       result = -1;
3789     }
3791   return result;
3796 /* ==========================================================================
3798     Scrollbar handling
3800    ========================================================================== */
3803 static void
3804 ns_set_vertical_scroll_bar (struct window *window,
3805                            int portion, int whole, int position)
3806 /* --------------------------------------------------------------------------
3807       External (hook): Update or add scrollbar
3808    -------------------------------------------------------------------------- */
3810   Lisp_Object win;
3811   NSRect r, v;
3812   struct frame *f = XFRAME (WINDOW_FRAME (window));
3813   EmacsView *view = FRAME_NS_VIEW (f);
3814   int window_y, window_height;
3815   int top, left, height, width, sb_width, sb_left;
3816   EmacsScroller *bar;
3817   BOOL fringe_extended_p;
3819   /* optimization; display engine sends WAY too many of these.. */
3820   if (!NILP (window->vertical_scroll_bar))
3821     {
3822       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3823       if ([bar checkSamePosition: position portion: portion whole: whole])
3824         {
3825           if (view->scrollbarsNeedingUpdate == 0)
3826             {
3827               if (!windows_or_buffers_changed)
3828                   return;
3829             }
3830           else
3831             view->scrollbarsNeedingUpdate--;
3832         }
3833     }
3835   NSTRACE (ns_set_vertical_scroll_bar);
3837   /* Get dimensions.  */
3838   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3839   top = window_y;
3840   height = window_height;
3841   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3842   left = WINDOW_SCROLL_BAR_AREA_X (window);
3844   /* allow for displaying a skinnier scrollbar than char area allotted */
3845   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3846     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3847   sb_left = left;
3849   r = NSMakeRect (sb_left, top, sb_width, height);
3850   /* the parent view is flipped, so we need to flip y value */
3851   v = [view frame];
3852   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3854   fringe_extended_p = WINDOW_FRINGE_EXTENDED_P (window);
3856   XSETWINDOW (win, window);
3857   block_input ();
3859   /* we want at least 5 lines to display a scrollbar */
3860   if (WINDOW_TOTAL_LINES (window) < 5)
3861     {
3862       if (!NILP (window->vertical_scroll_bar))
3863         {
3864           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3865           [bar removeFromSuperview];
3866           wset_vertical_scroll_bar (window, Qnil);
3867         }
3868       ns_clear_frame_area (f, sb_left, top, width, height);
3869       unblock_input ();
3870       return;
3871     }
3873   if (NILP (window->vertical_scroll_bar))
3874     {
3875       if (width > 0 && height > 0)
3876         {
3877           if (fringe_extended_p)
3878             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3879           else
3880             ns_clear_frame_area (f, left, top, width, height);
3881         }
3883       bar = [[EmacsScroller alloc] initFrame: r window: win];
3884       wset_vertical_scroll_bar (window, make_save_ptr (bar));
3885     }
3886   else
3887     {
3888       NSRect oldRect;
3889       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3890       oldRect = [bar frame];
3891       r.size.width = oldRect.size.width;
3892       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3893         {
3894           if (oldRect.origin.x != r.origin.x)
3895               ns_clear_frame_area (f, sb_left, top, width, height);
3896           [bar setFrame: r];
3897         }
3898     }
3900   [bar setPosition: position portion: portion whole: whole];
3901   unblock_input ();
3905 static void
3906 ns_condemn_scroll_bars (struct frame *f)
3907 /* --------------------------------------------------------------------------
3908      External (hook): arrange for all frame's scrollbars to be removed
3909      at next call to judge_scroll_bars, except for those redeemed.
3910    -------------------------------------------------------------------------- */
3912   int i;
3913   id view;
3914   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3916   NSTRACE (ns_condemn_scroll_bars);
3918   for (i =[subviews count]-1; i >= 0; i--)
3919     {
3920       view = [subviews objectAtIndex: i];
3921       if ([view isKindOfClass: [EmacsScroller class]])
3922         [view condemn];
3923     }
3927 static void
3928 ns_redeem_scroll_bar (struct window *window)
3929 /* --------------------------------------------------------------------------
3930      External (hook): arrange to spare this window's scrollbar
3931      at next call to judge_scroll_bars.
3932    -------------------------------------------------------------------------- */
3934   id bar;
3935   NSTRACE (ns_redeem_scroll_bar);
3936   if (!NILP (window->vertical_scroll_bar))
3937     {
3938       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3939       [bar reprieve];
3940     }
3944 static void
3945 ns_judge_scroll_bars (struct frame *f)
3946 /* --------------------------------------------------------------------------
3947      External (hook): destroy all scrollbars on frame that weren't
3948      redeemed after call to condemn_scroll_bars.
3949    -------------------------------------------------------------------------- */
3951   int i;
3952   id view;
3953   EmacsView *eview = FRAME_NS_VIEW (f);
3954   NSArray *subviews = [[eview superview] subviews];
3955   BOOL removed = NO;
3957   NSTRACE (ns_judge_scroll_bars);
3958   for (i = [subviews count]-1; i >= 0; --i)
3959     {
3960       view = [subviews objectAtIndex: i];
3961       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3962       [view judge];
3963       removed = YES;
3964     }
3966   if (removed)
3967     [eview updateFrameSize: NO];
3970 /* ==========================================================================
3972     Initialization
3974    ========================================================================== */
3977 x_display_pixel_height (struct ns_display_info *dpyinfo)
3979   NSArray *screens = [NSScreen screens];
3980   NSEnumerator *enumerator = [screens objectEnumerator];
3981   NSScreen *screen;
3982   NSRect frame;
3984   frame = NSZeroRect;
3985   while ((screen = [enumerator nextObject]) != nil)
3986     frame = NSUnionRect (frame, [screen frame]);
3988   return NSHeight (frame);
3992 x_display_pixel_width (struct ns_display_info *dpyinfo)
3994   NSArray *screens = [NSScreen screens];
3995   NSEnumerator *enumerator = [screens objectEnumerator];
3996   NSScreen *screen;
3997   NSRect frame;
3999   frame = NSZeroRect;
4000   while ((screen = [enumerator nextObject]) != nil)
4001     frame = NSUnionRect (frame, [screen frame]);
4003   return NSWidth (frame);
4007 static Lisp_Object ns_string_to_lispmod (const char *s)
4008 /* --------------------------------------------------------------------------
4009      Convert modifier name to lisp symbol
4010    -------------------------------------------------------------------------- */
4012   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4013     return Qmeta;
4014   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4015     return Qsuper;
4016   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4017     return Qcontrol;
4018   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4019     return Qalt;
4020   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4021     return Qhyper;
4022   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4023     return Qnone;
4024   else
4025     return Qnil;
4029 static void
4030 ns_default (const char *parameter, Lisp_Object *result,
4031            Lisp_Object yesval, Lisp_Object noval,
4032            BOOL is_float, BOOL is_modstring)
4033 /* --------------------------------------------------------------------------
4034       Check a parameter value in user's preferences
4035    -------------------------------------------------------------------------- */
4037   const char *value = ns_get_defaults_value (parameter);
4039   if (value)
4040     {
4041       double f;
4042       char *pos;
4043       if (c_strcasecmp (value, "YES") == 0)
4044         *result = yesval;
4045       else if (c_strcasecmp (value, "NO") == 0)
4046         *result = noval;
4047       else if (is_float && (f = strtod (value, &pos), pos != value))
4048         *result = make_float (f);
4049       else if (is_modstring && value)
4050         *result = ns_string_to_lispmod (value);
4051       else fprintf (stderr,
4052                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4053     }
4057 static void
4058 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4059 /* --------------------------------------------------------------------------
4060       Initialize global info and storage for display.
4061    -------------------------------------------------------------------------- */
4063     NSScreen *screen = [NSScreen mainScreen];
4064     NSWindowDepth depth = [screen depth];
4066     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4067     dpyinfo->resy = 72.27;
4068     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4069                                                   NSColorSpaceFromDepth (depth)]
4070                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4071                                                  NSColorSpaceFromDepth (depth)];
4072     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4073     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4074     dpyinfo->color_table->colors = NULL;
4075     dpyinfo->root_window = 42; /* a placeholder.. */
4076     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4077     dpyinfo->n_fonts = 0;
4078     dpyinfo->smallest_font_height = 1;
4079     dpyinfo->smallest_char_width = 1;
4081     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4085 /* This and next define (many of the) public functions in this file. */
4086 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4087          with using despite presence in the "system dependent" redisplay
4088          interface.  In addition, many of the ns_ methods have code that is
4089          shared with all terms, indicating need for further refactoring. */
4090 extern frame_parm_handler ns_frame_parm_handlers[];
4091 static struct redisplay_interface ns_redisplay_interface =
4093   ns_frame_parm_handlers,
4094   x_produce_glyphs,
4095   x_write_glyphs,
4096   x_insert_glyphs,
4097   x_clear_end_of_line,
4098   ns_scroll_run,
4099   ns_after_update_window_line,
4100   ns_update_window_begin,
4101   ns_update_window_end,
4102   0, /* flush_display */
4103   x_clear_window_mouse_face,
4104   x_get_glyph_overhangs,
4105   x_fix_overlapping_area,
4106   ns_draw_fringe_bitmap,
4107   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4108   0, /* destroy_fringe_bitmap */
4109   ns_compute_glyph_string_overhangs,
4110   ns_draw_glyph_string,
4111   ns_define_frame_cursor,
4112   ns_clear_frame_area,
4113   ns_draw_window_cursor,
4114   ns_draw_vertical_window_border,
4115   ns_draw_window_divider,
4116   ns_shift_glyphs_for_insert
4120 static void
4121 ns_delete_display (struct ns_display_info *dpyinfo)
4123   /* TODO... */
4127 /* This function is called when the last frame on a display is deleted. */
4128 static void
4129 ns_delete_terminal (struct terminal *terminal)
4131   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4133   /* Protect against recursive calls.  delete_frame in
4134      delete_terminal calls us back when it deletes our last frame.  */
4135   if (!terminal->name)
4136     return;
4138   block_input ();
4140   x_destroy_all_bitmaps (dpyinfo);
4141   ns_delete_display (dpyinfo);
4142   unblock_input ();
4146 static struct terminal *
4147 ns_create_terminal (struct ns_display_info *dpyinfo)
4148 /* --------------------------------------------------------------------------
4149       Set up use of NS before we make the first connection.
4150    -------------------------------------------------------------------------- */
4152   struct terminal *terminal;
4154   NSTRACE (ns_create_terminal);
4156   terminal = create_terminal ();
4158   terminal->type = output_ns;
4159   terminal->display_info.ns = dpyinfo;
4160   dpyinfo->terminal = terminal;
4162   terminal->rif = &ns_redisplay_interface;
4164   terminal->clear_frame_hook = ns_clear_frame;
4165   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4166   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
4167   terminal->ring_bell_hook = ns_ring_bell;
4168   terminal->reset_terminal_modes_hook = NULL;
4169   terminal->set_terminal_modes_hook = NULL;
4170   terminal->update_begin_hook = ns_update_begin;
4171   terminal->update_end_hook = ns_update_end;
4172   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4173   terminal->read_socket_hook = ns_read_socket;
4174   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4175   terminal->mouse_position_hook = ns_mouse_position;
4176   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4177   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4179   terminal->fullscreen_hook = ns_fullscreen_hook;
4181   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4182   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4183   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4184   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4186   terminal->delete_frame_hook = x_destroy_window;
4187   terminal->delete_terminal_hook = ns_delete_terminal;
4189   return terminal;
4193 struct ns_display_info *
4194 ns_term_init (Lisp_Object display_name)
4195 /* --------------------------------------------------------------------------
4196      Start the Application and get things rolling.
4197    -------------------------------------------------------------------------- */
4199   struct terminal *terminal;
4200   struct ns_display_info *dpyinfo;
4201   static int ns_initialized = 0;
4202   Lisp_Object tmp;
4204   if (ns_initialized) return x_display_list;
4205   ns_initialized = 1;
4207   NSTRACE (ns_term_init);
4209   [outerpool release];
4210   outerpool = [[NSAutoreleasePool alloc] init];
4212   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4213   /*GSDebugAllocationActive (YES); */
4214   block_input ();
4216   baud_rate = 38400;
4217   Fset_input_interrupt_mode (Qnil);
4219   if (selfds[0] == -1)
4220     {
4221       if (emacs_pipe (selfds) != 0)
4222         {
4223           fprintf (stderr, "Failed to create pipe: %s\n",
4224                    emacs_strerror (errno));
4225           emacs_abort ();
4226         }
4228       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4229       FD_ZERO (&select_readfds);
4230       FD_ZERO (&select_writefds);
4231       pthread_mutex_init (&select_mutex, NULL);
4232     }
4234   ns_pending_files = [[NSMutableArray alloc] init];
4235   ns_pending_service_names = [[NSMutableArray alloc] init];
4236   ns_pending_service_args = [[NSMutableArray alloc] init];
4238 /* Start app and create the main menu, window, view.
4239      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4240      The view will then ask the NSApp to stop and return to Emacs. */
4241   [EmacsApp sharedApplication];
4242   if (NSApp == nil)
4243     return NULL;
4244   [NSApp setDelegate: NSApp];
4246   /* Start the select thread.  */
4247   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4248                            toTarget:NSApp
4249                          withObject:nil];
4251   /* debugging: log all notifications */
4252   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4253                                          selector: @selector (logNotification:)
4254                                              name: nil object: nil]; */
4256   dpyinfo = xzalloc (sizeof *dpyinfo);
4258   ns_initialize_display_info (dpyinfo);
4259   terminal = ns_create_terminal (dpyinfo);
4261   terminal->kboard = allocate_kboard (Qns);
4262   /* Don't let the initial kboard remain current longer than necessary.
4263      That would cause problems if a file loaded on startup tries to
4264      prompt in the mini-buffer.  */
4265   if (current_kboard == initial_kboard)
4266     current_kboard = terminal->kboard;
4267   terminal->kboard->reference_count++;
4269   dpyinfo->next = x_display_list;
4270   x_display_list = dpyinfo;
4272   dpyinfo->name_list_element = Fcons (display_name, Qnil);
4274   terminal->name = xstrdup (SSDATA (display_name));
4276   unblock_input ();
4278   if (!inhibit_x_resources)
4279     {
4280       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4281                  Qt, Qnil, NO, NO);
4282       tmp = Qnil;
4283       /* this is a standard variable */
4284       ns_default ("AppleAntiAliasingThreshold", &tmp,
4285                  make_float (10.0), make_float (6.0), YES, NO);
4286       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4287     }
4289   {
4290     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4292     if ( cl == nil )
4293       {
4294         Lisp_Object color_file, color_map, color;
4295         unsigned long c;
4296         char *name;
4298         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4299                          Fsymbol_value (intern ("data-directory")));
4301         color_map = Fx_load_color_file (color_file);
4302         if (NILP (color_map))
4303           fatal ("Could not read %s.\n", SDATA (color_file));
4305         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4306         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4307           {
4308             color = XCAR (color_map);
4309             name = SSDATA (XCAR (color));
4310             c = XINT (XCDR (color));
4311             [cl setColor:
4312                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4313                                       green: GREEN_FROM_ULONG (c) / 255.0
4314                                        blue: BLUE_FROM_ULONG (c) / 255.0
4315                                       alpha: 1.0]
4316                   forKey: [NSString stringWithUTF8String: name]];
4317           }
4318         [cl writeToFile: nil];
4319       }
4320   }
4322   {
4323 #ifdef NS_IMPL_GNUSTEP
4324     Vwindow_system_version = build_string (gnustep_base_version);
4325 #else
4326     /*PSnextrelease (128, c); */
4327     char c[DBL_BUFSIZE_BOUND];
4328     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4329     Vwindow_system_version = make_unibyte_string (c, len);
4330 #endif
4331   }
4333   delete_keyboard_wait_descriptor (0);
4335   ns_app_name = [[NSProcessInfo processInfo] processName];
4337 /* Set up OS X app menu */
4338 #ifdef NS_IMPL_COCOA
4339   {
4340     NSMenu *appMenu;
4341     NSMenuItem *item;
4342     /* set up the application menu */
4343     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4344     [svcsMenu setAutoenablesItems: NO];
4345     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4346     [appMenu setAutoenablesItems: NO];
4347     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4348     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4350     [appMenu insertItemWithTitle: @"About Emacs"
4351                           action: @selector (orderFrontStandardAboutPanel:)
4352                    keyEquivalent: @""
4353                          atIndex: 0];
4354     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4355     [appMenu insertItemWithTitle: @"Preferences..."
4356                           action: @selector (showPreferencesWindow:)
4357                    keyEquivalent: @","
4358                          atIndex: 2];
4359     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4360     item = [appMenu insertItemWithTitle: @"Services"
4361                                  action: @selector (menuDown:)
4362                           keyEquivalent: @""
4363                                 atIndex: 4];
4364     [appMenu setSubmenu: svcsMenu forItem: item];
4365     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4366     [appMenu insertItemWithTitle: @"Hide Emacs"
4367                           action: @selector (hide:)
4368                    keyEquivalent: @"h"
4369                          atIndex: 6];
4370     item =  [appMenu insertItemWithTitle: @"Hide Others"
4371                           action: @selector (hideOtherApplications:)
4372                    keyEquivalent: @"h"
4373                          atIndex: 7];
4374     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4375     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4376     [appMenu insertItemWithTitle: @"Quit Emacs"
4377                           action: @selector (terminate:)
4378                    keyEquivalent: @"q"
4379                          atIndex: 9];
4381     item = [mainMenu insertItemWithTitle: ns_app_name
4382                                   action: @selector (menuDown:)
4383                            keyEquivalent: @""
4384                                  atIndex: 0];
4385     [mainMenu setSubmenu: appMenu forItem: item];
4386     [dockMenu insertItemWithTitle: @"New Frame"
4387                            action: @selector (newFrame:)
4388                     keyEquivalent: @""
4389                           atIndex: 0];
4391     [NSApp setMainMenu: mainMenu];
4392     [NSApp setAppleMenu: appMenu];
4393     [NSApp setServicesMenu: svcsMenu];
4394     /* Needed at least on Cocoa, to get dock menu to show windows */
4395     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4397     [[NSNotificationCenter defaultCenter]
4398       addObserver: mainMenu
4399          selector: @selector (trackingNotification:)
4400              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4401     [[NSNotificationCenter defaultCenter]
4402       addObserver: mainMenu
4403          selector: @selector (trackingNotification:)
4404              name: NSMenuDidEndTrackingNotification object: mainMenu];
4405   }
4406 #endif /* MAC OS X menu setup */
4408   /* Register our external input/output types, used for determining
4409      applicable services and also drag/drop eligibility. */
4410   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4411   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4412                       retain];
4413   ns_drag_types = [[NSArray arrayWithObjects:
4414                             NSStringPboardType,
4415                             NSTabularTextPboardType,
4416                             NSFilenamesPboardType,
4417                             NSURLPboardType, nil] retain];
4419   /* If fullscreen is in init/default-frame-alist, focus isn't set
4420      right for fullscreen windows, so set this.  */
4421   [NSApp activateIgnoringOtherApps:YES];
4423   [NSApp run];
4424   ns_do_open_file = YES;
4426 #ifdef NS_IMPL_GNUSTEP
4427   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4428      We must re-catch it so subprocess works.  */
4429   catch_child_signal ();
4430 #endif
4431   return dpyinfo;
4435 void
4436 ns_term_shutdown (int sig)
4438   [[NSUserDefaults standardUserDefaults] synchronize];
4440   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4441   if (STRINGP (Vauto_save_list_file_name))
4442     unlink (SSDATA (Vauto_save_list_file_name));
4444   if (sig == 0 || sig == SIGTERM)
4445     {
4446       [NSApp terminate: NSApp];
4447     }
4448   else // force a stack trace to happen
4449     {
4450       emacs_abort ();
4451     }
4455 /* ==========================================================================
4457     EmacsApp implementation
4459    ========================================================================== */
4462 @implementation EmacsApp
4464 - (id)init
4466   if (self = [super init])
4467     {
4468 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
4469       self->isFirst = YES;
4470 #endif
4471 #ifdef NS_IMPL_GNUSTEP
4472       self->applicationDidFinishLaunchingCalled = NO;
4473 #endif
4474     }
4476   return self;
4479 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
4480 - (void)run
4482     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4484     if (isFirst) [self finishLaunching];
4485     isFirst = NO;
4487     shouldKeepRunning = YES;
4488     do
4489       {
4490         [pool release];
4491         pool = [[NSAutoreleasePool alloc] init];
4493         NSEvent *event =
4494           [self nextEventMatchingMask:NSAnyEventMask
4495                             untilDate:[NSDate distantFuture]
4496                                inMode:NSDefaultRunLoopMode
4497                               dequeue:YES];
4498         [self sendEvent:event];
4499         [self updateWindows];
4500     } while (shouldKeepRunning);
4502     [pool release];
4505 - (void)stop: (id)sender
4507     shouldKeepRunning = NO;
4508     // Stop possible dialog also.  Noop if no dialog present.
4509     // The file dialog still leaks 7k - 10k on 10.9 though.
4510     [super stop:sender];
4512 #endif
4514 - (void)logNotification: (NSNotification *)notification
4516   const char *name = [[notification name] UTF8String];
4517   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4518       && !strstr (name, "WindowNumber"))
4519     NSLog (@"notification: '%@'", [notification name]);
4523 - (void)sendEvent: (NSEvent *)theEvent
4524 /* --------------------------------------------------------------------------
4525      Called when NSApp is running for each event received.  Used to stop
4526      the loop when we choose, since there's no way to just run one iteration.
4527    -------------------------------------------------------------------------- */
4529   int type = [theEvent type];
4530   NSWindow *window = [theEvent window];
4532 /*  NSTRACE (sendEvent); */
4533 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4535 #ifdef NS_IMPL_GNUSTEP
4536   // Keyboard events aren't propagated to file dialogs for some reason.
4537   if ([NSApp modalWindow] != nil &&
4538       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4539     {
4540       [[NSApp modalWindow] sendEvent: theEvent];
4541       return;
4542     }
4543 #endif
4545   if (type == NSApplicationDefined)
4546     {
4547       switch ([theEvent data2])
4548         {
4549 #ifdef NS_IMPL_COCOA
4550         case NSAPP_DATA2_RUNASSCRIPT:
4551           ns_run_ascript ();
4552           [self stop: self];
4553           return;
4554 #endif
4555         case NSAPP_DATA2_RUNFILEDIALOG:
4556           ns_run_file_dialog ();
4557           [self stop: self];
4558           return;
4559         }
4560     }
4562   if (type == NSCursorUpdate && window == nil)
4563     {
4564       fprintf (stderr, "Dropping external cursor update event.\n");
4565       return;
4566     }
4568   if (type == NSApplicationDefined)
4569     {
4570       /* Events posted by ns_send_appdefined interrupt the run loop here.
4571          But, if a modal window is up, an appdefined can still come through,
4572          (e.g., from a makeKeyWindow event) but stopping self also stops the
4573          modal loop. Just defer it until later. */
4574       if ([NSApp modalWindow] == nil)
4575         {
4576           last_appdefined_event_data = [theEvent data1];
4577           [self stop: self];
4578         }
4579       else
4580         {
4581           send_appdefined = YES;
4582         }
4583     }
4586 #ifdef NS_IMPL_COCOA
4587   /* If no dialog and none of our frames have focus and it is a move, skip it.
4588      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4589      such as Wifi, sound, date or similar.
4590      This prevents "spooky" highlighting in the frame under the menu.  */
4591   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4592     {
4593       struct ns_display_info *di;
4594       BOOL has_focus = NO;
4595       for (di = x_display_list; ! has_focus && di; di = di->next)
4596         has_focus = di->x_focus_frame != 0;
4597       if (! has_focus)
4598         return;
4599     }
4600 #endif
4602   [super sendEvent: theEvent];
4606 - (void)showPreferencesWindow: (id)sender
4608   struct frame *emacsframe = SELECTED_FRAME ();
4609   NSEvent *theEvent = [NSApp currentEvent];
4611   if (!emacs_event)
4612     return;
4613   emacs_event->kind = NS_NONKEY_EVENT;
4614   emacs_event->code = KEY_NS_SHOW_PREFS;
4615   emacs_event->modifiers = 0;
4616   EV_TRAILER (theEvent);
4620 - (void)newFrame: (id)sender
4622   struct frame *emacsframe = SELECTED_FRAME ();
4623   NSEvent *theEvent = [NSApp currentEvent];
4625   if (!emacs_event)
4626     return;
4627   emacs_event->kind = NS_NONKEY_EVENT;
4628   emacs_event->code = KEY_NS_NEW_FRAME;
4629   emacs_event->modifiers = 0;
4630   EV_TRAILER (theEvent);
4634 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4635 - (BOOL) openFile: (NSString *)fileName
4637   struct frame *emacsframe = SELECTED_FRAME ();
4638   NSEvent *theEvent = [NSApp currentEvent];
4640   if (!emacs_event)
4641     return NO;
4643   emacs_event->kind = NS_NONKEY_EVENT;
4644   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4645   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4646   ns_input_line = Qnil; /* can be start or cons start,end */
4647   emacs_event->modifiers =0;
4648   EV_TRAILER (theEvent);
4650   return YES;
4654 /* **************************************************************************
4656       EmacsApp delegate implementation
4658    ************************************************************************** */
4660 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4661 /* --------------------------------------------------------------------------
4662      When application is loaded, terminate event loop in ns_term_init
4663    -------------------------------------------------------------------------- */
4665   NSTRACE (applicationDidFinishLaunching);
4666 #ifdef NS_IMPL_GNUSTEP
4667   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
4668 #endif
4669   [NSApp setServicesProvider: NSApp];
4670   ns_send_appdefined (-2);
4674 /* Termination sequences:
4675     C-x C-c:
4676     Cmd-Q:
4677     MenuBar | File | Exit:
4678     Select Quit from App menubar:
4679         -terminate
4680         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4681         ns_term_shutdown()
4683     Select Quit from Dock menu:
4684     Logout attempt:
4685         -appShouldTerminate
4686           Cancel -> Nothing else
4687           Accept ->
4689           -terminate
4690           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4691           ns_term_shutdown()
4695 - (void) terminate: (id)sender
4697   struct frame *emacsframe = SELECTED_FRAME ();
4699   if (!emacs_event)
4700     return;
4702   emacs_event->kind = NS_NONKEY_EVENT;
4703   emacs_event->code = KEY_NS_POWER_OFF;
4704   emacs_event->arg = Qt; /* mark as non-key event */
4705   EV_TRAILER ((id)nil);
4709 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4711   int ret;
4713   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4714     return NSTerminateNow;
4716     ret = NSRunAlertPanel(ns_app_name,
4717                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4718                           @"Save Buffers and Exit", @"Cancel", nil);
4720     if (ret == NSAlertDefaultReturn)
4721         return NSTerminateNow;
4722     else if (ret == NSAlertAlternateReturn)
4723         return NSTerminateCancel;
4724     return NSTerminateNow;  /* just in case */
4727 static int
4728 not_in_argv (NSString *arg)
4730   int k;
4731   const char *a = [arg UTF8String];
4732   for (k = 1; k < initial_argc; ++k)
4733     if (strcmp (a, initial_argv[k]) == 0) return 0;
4734   return 1;
4737 /*   Notification from the Workspace to open a file */
4738 - (BOOL)application: sender openFile: (NSString *)file
4740   if (ns_do_open_file || not_in_argv (file))
4741     [ns_pending_files addObject: file];
4742   return YES;
4746 /*   Open a file as a temporary file */
4747 - (BOOL)application: sender openTempFile: (NSString *)file
4749   if (ns_do_open_file || not_in_argv (file))
4750     [ns_pending_files addObject: file];
4751   return YES;
4755 /*   Notification from the Workspace to open a file noninteractively (?) */
4756 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4758   if (ns_do_open_file || not_in_argv (file))
4759     [ns_pending_files addObject: file];
4760   return YES;
4763 /*   Notification from the Workspace to open multiple files */
4764 - (void)application: sender openFiles: (NSArray *)fileList
4766   NSEnumerator *files = [fileList objectEnumerator];
4767   NSString *file;
4768   /* Don't open files from the command line unconditionally,
4769      Cocoa parses the command line wrong, --option value tries to open value
4770      if --option is the last option.  */
4771   while ((file = [files nextObject]) != nil)
4772     if (ns_do_open_file || not_in_argv (file))
4773       [ns_pending_files addObject: file];
4775   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4780 /* Handle dock menu requests.  */
4781 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4783   return dockMenu;
4787 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4788 - (void)applicationWillBecomeActive: (NSNotification *)notification
4790   //ns_app_active=YES;
4792 - (void)applicationDidBecomeActive: (NSNotification *)notification
4794   NSTRACE (applicationDidBecomeActive);
4796 #ifdef NS_IMPL_GNUSTEP
4797   if (! applicationDidFinishLaunchingCalled)
4798     [self applicationDidFinishLaunching:notification];
4799 #endif
4800   //ns_app_active=YES;
4802   ns_update_auto_hide_menu_bar ();
4803   // No constraining takes place when the application is not active.
4804   ns_constrain_all_frames ();
4806 - (void)applicationDidResignActive: (NSNotification *)notification
4808   //ns_app_active=NO;
4809   ns_send_appdefined (-1);
4814 /* ==========================================================================
4816     EmacsApp aux handlers for managing event loop
4818    ========================================================================== */
4821 - (void)timeout_handler: (NSTimer *)timedEntry
4822 /* --------------------------------------------------------------------------
4823      The timeout specified to ns_select has passed.
4824    -------------------------------------------------------------------------- */
4826   /*NSTRACE (timeout_handler); */
4827   ns_send_appdefined (-2);
4830 #ifdef NS_IMPL_GNUSTEP
4831 - (void)sendFromMainThread:(id)unused
4833   ns_send_appdefined (nextappdefined);
4835 #endif
4837 - (void)fd_handler:(id)unused
4838 /* --------------------------------------------------------------------------
4839      Check data waiting on file descriptors and terminate if so
4840    -------------------------------------------------------------------------- */
4842   int result;
4843   int waiting = 1, nfds;
4844   char c;
4846   fd_set readfds, writefds, *wfds;
4847   struct timespec timeout, *tmo;
4848   NSAutoreleasePool *pool = nil;
4850   /* NSTRACE (fd_handler); */
4852   for (;;)
4853     {
4854       [pool release];
4855       pool = [[NSAutoreleasePool alloc] init];
4857       if (waiting)
4858         {
4859           fd_set fds;
4860           FD_ZERO (&fds);
4861           FD_SET (selfds[0], &fds);
4862           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4863           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4864             waiting = 0;
4865         }
4866       else
4867         {
4868           pthread_mutex_lock (&select_mutex);
4869           nfds = select_nfds;
4871           if (select_valid & SELECT_HAVE_READ)
4872             readfds = select_readfds;
4873           else
4874             FD_ZERO (&readfds);
4876           if (select_valid & SELECT_HAVE_WRITE)
4877             {
4878               writefds = select_writefds;
4879               wfds = &writefds;
4880             }
4881           else
4882             wfds = NULL;
4883           if (select_valid & SELECT_HAVE_TMO)
4884             {
4885               timeout = select_timeout;
4886               tmo = &timeout;
4887             }
4888           else
4889             tmo = NULL;
4891           pthread_mutex_unlock (&select_mutex);
4893           FD_SET (selfds[0], &readfds);
4894           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4896           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4898           if (result == 0)
4899             ns_send_appdefined (-2);
4900           else if (result > 0)
4901             {
4902               if (FD_ISSET (selfds[0], &readfds))
4903                 {
4904                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4905                     waiting = 1;
4906                 }
4907               else
4908                 {
4909                   pthread_mutex_lock (&select_mutex);
4910                   if (select_valid & SELECT_HAVE_READ)
4911                     select_readfds = readfds;
4912                   if (select_valid & SELECT_HAVE_WRITE)
4913                     select_writefds = writefds;
4914                   if (select_valid & SELECT_HAVE_TMO)
4915                     select_timeout = timeout;
4916                   pthread_mutex_unlock (&select_mutex);
4918                   ns_send_appdefined (result);
4919                 }
4920             }
4921           waiting = 1;
4922         }
4923     }
4928 /* ==========================================================================
4930     Service provision
4932    ========================================================================== */
4934 /* called from system: queue for next pass through event loop */
4935 - (void)requestService: (NSPasteboard *)pboard
4936               userData: (NSString *)userData
4937                  error: (NSString **)error
4939   [ns_pending_service_names addObject: userData];
4940   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4941       SSDATA (ns_string_from_pasteboard (pboard))]];
4945 /* called from ns_read_socket to clear queue */
4946 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4948   struct frame *emacsframe = SELECTED_FRAME ();
4949   NSEvent *theEvent = [NSApp currentEvent];
4951   if (!emacs_event)
4952     return NO;
4954   emacs_event->kind = NS_NONKEY_EVENT;
4955   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4956   ns_input_spi_name = build_string ([name UTF8String]);
4957   ns_input_spi_arg = build_string ([arg UTF8String]);
4958   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4959   EV_TRAILER (theEvent);
4961   return YES;
4965 @end  /* EmacsApp */
4969 /* ==========================================================================
4971     EmacsView implementation
4973    ========================================================================== */
4976 @implementation EmacsView
4978 /* needed to inform when window closed from LISP */
4979 - (void) setWindowClosing: (BOOL)closing
4981   windowClosing = closing;
4985 - (void)dealloc
4987   NSTRACE (EmacsView_dealloc);
4988   [toolbar release];
4989   if (fs_state == FULLSCREEN_BOTH)
4990     [nonfs_window release];
4991   [super dealloc];
4995 /* called on font panel selection */
4996 - (void)changeFont: (id)sender
4998   NSEvent *e = [[self window] currentEvent];
4999   struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5000   struct font *font = face->font;
5001   id newFont;
5002   CGFloat size;
5003   NSFont *nsfont;
5005   NSTRACE (changeFont);
5007   if (!emacs_event)
5008     return;
5010   if (EQ (font->driver->type, Qns))
5011     nsfont = ((struct nsfont_info *)font)->nsfont;
5012 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
5013   else
5014     nsfont = (NSFont *) macfont_get_nsctfont (font);
5015 #endif
5017   if ((newFont = [sender convertFont: nsfont]))
5018     {
5019       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5021       emacs_event->kind = NS_NONKEY_EVENT;
5022       emacs_event->modifiers = 0;
5023       emacs_event->code = KEY_NS_CHANGE_FONT;
5025       size = [newFont pointSize];
5026       ns_input_fontsize = make_number (lrint (size));
5027       ns_input_font = build_string ([[newFont familyName] UTF8String]);
5028       EV_TRAILER (e);
5029     }
5033 - (BOOL)acceptsFirstResponder
5035   NSTRACE (acceptsFirstResponder);
5036   return YES;
5040 - (void)resetCursorRects
5042   NSRect visible = [self visibleRect];
5043   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5044   NSTRACE (resetCursorRects);
5046   if (currentCursor == nil)
5047     currentCursor = [NSCursor arrowCursor];
5049   if (!NSIsEmptyRect (visible))
5050     [self addCursorRect: visible cursor: currentCursor];
5051   [currentCursor setOnMouseEntered: YES];
5056 /*****************************************************************************/
5057 /* Keyboard handling. */
5058 #define NS_KEYLOG 0
5060 - (void)keyDown: (NSEvent *)theEvent
5062   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5063   int code;
5064   unsigned fnKeysym = 0;
5065   static NSMutableArray *nsEvArray;
5066 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5067   static BOOL firstTime = YES;
5068 #endif
5069   int left_is_none;
5070   unsigned int flags = [theEvent modifierFlags];
5072   NSTRACE (keyDown);
5074   /* Rhapsody and OS X give up and down events for the arrow keys */
5075   if (ns_fake_keydown == YES)
5076     ns_fake_keydown = NO;
5077   else if ([theEvent type] != NSKeyDown)
5078     return;
5080   if (!emacs_event)
5081     return;
5083  if (![[self window] isKeyWindow]
5084      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5085      /* we must avoid an infinite loop here. */
5086      && (EmacsView *)[[theEvent window] delegate] != self)
5087    {
5088      /* XXX: There is an occasional condition in which, when Emacs display
5089          updates a different frame from the current one, and temporarily
5090          selects it, then processes some interrupt-driven input
5091          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5092          for some reason that window has its first responder set to the NSView
5093          most recently updated (I guess), which is not the correct one. */
5094      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5095      return;
5096    }
5098   if (nsEvArray == nil)
5099     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5101   [NSCursor setHiddenUntilMouseMoves: YES];
5103   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5104     {
5105       clear_mouse_face (hlinfo);
5106       hlinfo->mouse_face_hidden = 1;
5107     }
5109   if (!processingCompose)
5110     {
5111       /* When using screen sharing, no left or right information is sent,
5112          so use Left key in those cases.  */
5113       int is_left_key, is_right_key;
5115       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5116         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5118       /* (Carbon way: [theEvent keyCode]) */
5120       /* is it a "function key"? */
5121       /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5122          flag set (this is probably a bug in the OS).
5123       */
5124       if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5125         {
5126           fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5127         }
5128       if (fnKeysym == 0)
5129         {
5130           fnKeysym = ns_convert_key (code);
5131         }
5133       if (fnKeysym)
5134         {
5135           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5136              because Emacs treats Delete and KP-Delete same (in simple.el). */
5137           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5138 #ifdef NS_IMPL_GNUSTEP
5139               /*  GNUstep uses incompatible keycodes, even for those that are
5140                   supposed to be hardware independent.  Just check for delete.
5141                   Keypad delete does not have keysym 0xFFFF.
5142                   See http://savannah.gnu.org/bugs/?25395
5143               */
5144               || (fnKeysym == 0xFFFF && code == 127)
5145 #endif
5146             )
5147             code = 0xFF08; /* backspace */
5148           else
5149             code = fnKeysym;
5150         }
5152       /* are there modifiers? */
5153       emacs_event->modifiers = 0;
5155       if (flags & NSHelpKeyMask)
5156           emacs_event->modifiers |= hyper_modifier;
5158       if (flags & NSShiftKeyMask)
5159         emacs_event->modifiers |= shift_modifier;
5161       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5162       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5163         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5165       if (is_right_key)
5166         emacs_event->modifiers |= parse_solitary_modifier
5167           (EQ (ns_right_command_modifier, Qleft)
5168            ? ns_command_modifier
5169            : ns_right_command_modifier);
5171       if (is_left_key)
5172         {
5173           emacs_event->modifiers |= parse_solitary_modifier
5174             (ns_command_modifier);
5176           /* if super (default), take input manager's word so things like
5177              dvorak / qwerty layout work */
5178           if (EQ (ns_command_modifier, Qsuper)
5179               && !fnKeysym
5180               && [[theEvent characters] length] != 0)
5181             {
5182               /* XXX: the code we get will be unshifted, so if we have
5183                  a shift modifier, must convert ourselves */
5184               if (!(flags & NSShiftKeyMask))
5185                 code = [[theEvent characters] characterAtIndex: 0];
5186 #if 0
5187               /* this is ugly and also requires linking w/Carbon framework
5188                  (for LMGetKbdType) so for now leave this rare (?) case
5189                  undealt with.. in future look into CGEvent methods */
5190               else
5191                 {
5192                   long smv = GetScriptManagerVariable (smKeyScript);
5193                   Handle uchrHandle = GetResource
5194                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5195                   UInt32 dummy = 0;
5196                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5197                                  [[theEvent characters] characterAtIndex: 0],
5198                                  kUCKeyActionDisplay,
5199                                  (flags & ~NSCommandKeyMask) >> 8,
5200                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5201                                  &dummy, 1, &dummy, &code);
5202                   code &= 0xFF;
5203                 }
5204 #endif
5205             }
5206         }
5208       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5209       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5210         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5212       if (is_right_key)
5213           emacs_event->modifiers |= parse_solitary_modifier
5214               (EQ (ns_right_control_modifier, Qleft)
5215                ? ns_control_modifier
5216                : ns_right_control_modifier);
5218       if (is_left_key)
5219         emacs_event->modifiers |= parse_solitary_modifier
5220           (ns_control_modifier);
5222       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5223           emacs_event->modifiers |=
5224             parse_solitary_modifier (ns_function_modifier);
5226       left_is_none = NILP (ns_alternate_modifier)
5227         || EQ (ns_alternate_modifier, Qnone);
5229       is_right_key = (flags & NSRightAlternateKeyMask)
5230         == NSRightAlternateKeyMask;
5231       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5232         || (! is_right_key
5233             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5235       if (is_right_key)
5236         {
5237           if ((NILP (ns_right_alternate_modifier)
5238                || EQ (ns_right_alternate_modifier, Qnone)
5239                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5240               && !fnKeysym)
5241             {   /* accept pre-interp alt comb */
5242               if ([[theEvent characters] length] > 0)
5243                 code = [[theEvent characters] characterAtIndex: 0];
5244               /*HACK: clear lone shift modifier to stop next if from firing */
5245               if (emacs_event->modifiers == shift_modifier)
5246                 emacs_event->modifiers = 0;
5247             }
5248           else
5249             emacs_event->modifiers |= parse_solitary_modifier
5250               (EQ (ns_right_alternate_modifier, Qleft)
5251                ? ns_alternate_modifier
5252                : ns_right_alternate_modifier);
5253         }
5255       if (is_left_key) /* default = meta */
5256         {
5257           if (left_is_none && !fnKeysym)
5258             {   /* accept pre-interp alt comb */
5259               if ([[theEvent characters] length] > 0)
5260                 code = [[theEvent characters] characterAtIndex: 0];
5261               /*HACK: clear lone shift modifier to stop next if from firing */
5262               if (emacs_event->modifiers == shift_modifier)
5263                 emacs_event->modifiers = 0;
5264             }
5265           else
5266               emacs_event->modifiers |=
5267                 parse_solitary_modifier (ns_alternate_modifier);
5268         }
5270   if (NS_KEYLOG)
5271     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5272              code, fnKeysym, flags, emacs_event->modifiers);
5274       /* if it was a function key or had modifiers, pass it directly to emacs */
5275       if (fnKeysym || (emacs_event->modifiers
5276                        && (emacs_event->modifiers != shift_modifier)
5277                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5278 /*[[theEvent characters] length] */
5279         {
5280           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5281           if (code < 0x20)
5282             code |= (1<<28)|(3<<16);
5283           else if (code == 0x7f)
5284             code |= (1<<28)|(3<<16);
5285           else if (!fnKeysym)
5286             emacs_event->kind = code > 0xFF
5287               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5289           emacs_event->code = code;
5290           EV_TRAILER (theEvent);
5291           processingCompose = NO;
5292           return;
5293         }
5294     }
5297 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5298   /* if we get here we should send the key for input manager processing */
5299   /* Disable warning, there is nothing a user can do about it anyway, and
5300      it does not seem to matter.  */
5301 #if 0
5302   if (firstTime && [[NSInputManager currentInputManager]
5303                      wantsToDelayTextChangeNotifications] == NO)
5304     fprintf (stderr,
5305           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5306 #endif
5307   firstTime = NO;
5308 #endif
5309   if (NS_KEYLOG && !processingCompose)
5310     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5312   processingCompose = YES;
5313   [nsEvArray addObject: theEvent];
5314   [self interpretKeyEvents: nsEvArray];
5315   [nsEvArray removeObject: theEvent];
5319 #ifdef NS_IMPL_COCOA
5320 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5321    decided not to send key-down for.
5322    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5323    This only applies on Tiger and earlier.
5324    If it matches one of these, send it on to keyDown. */
5325 -(void)keyUp: (NSEvent *)theEvent
5327   int flags = [theEvent modifierFlags];
5328   int code = [theEvent keyCode];
5329   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5330       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5331     {
5332       if (NS_KEYLOG)
5333         fprintf (stderr, "keyUp: passed test");
5334       ns_fake_keydown = YES;
5335       [self keyDown: theEvent];
5336     }
5338 #endif
5341 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5344 /* <NSTextInput>: called when done composing;
5345    NOTE: also called when we delete over working text, followed immed.
5346          by doCommandBySelector: deleteBackward: */
5347 - (void)insertText: (id)aString
5349   int code;
5350   int len = [(NSString *)aString length];
5351   int i;
5353   if (NS_KEYLOG)
5354     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5355   processingCompose = NO;
5357   if (!emacs_event)
5358     return;
5360   /* first, clear any working text */
5361   if (workingText != nil)
5362     [self deleteWorkingText];
5364   /* now insert the string as keystrokes */
5365   for (i =0; i<len; i++)
5366     {
5367       code = [aString characterAtIndex: i];
5368       /* TODO: still need this? */
5369       if (code == 0x2DC)
5370         code = '~'; /* 0x7E */
5371       if (code != 32) /* Space */
5372         emacs_event->modifiers = 0;
5373       emacs_event->kind
5374         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5375       emacs_event->code = code;
5376       EV_TRAILER ((id)nil);
5377     }
5381 /* <NSTextInput>: inserts display of composing characters */
5382 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5384   NSString *str = [aString respondsToSelector: @selector (string)] ?
5385     [aString string] : aString;
5386   if (NS_KEYLOG)
5387     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5388            str, (unsigned long)[str length],
5389            (unsigned long)selRange.length,
5390            (unsigned long)selRange.location);
5392   if (workingText != nil)
5393     [self deleteWorkingText];
5394   if ([str length] == 0)
5395     return;
5397   if (!emacs_event)
5398     return;
5400   processingCompose = YES;
5401   workingText = [str copy];
5402   ns_working_text = build_string ([workingText UTF8String]);
5404   emacs_event->kind = NS_TEXT_EVENT;
5405   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5406   EV_TRAILER ((id)nil);
5410 /* delete display of composing characters [not in <NSTextInput>] */
5411 - (void)deleteWorkingText
5413   if (workingText == nil)
5414     return;
5415   if (NS_KEYLOG)
5416     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5417   [workingText release];
5418   workingText = nil;
5419   processingCompose = NO;
5421   if (!emacs_event)
5422     return;
5424   emacs_event->kind = NS_TEXT_EVENT;
5425   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5426   EV_TRAILER ((id)nil);
5430 - (BOOL)hasMarkedText
5432   return workingText != nil;
5436 - (NSRange)markedRange
5438   NSRange rng = workingText != nil
5439     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5440   if (NS_KEYLOG)
5441     NSLog (@"markedRange request");
5442   return rng;
5446 - (void)unmarkText
5448   if (NS_KEYLOG)
5449     NSLog (@"unmark (accept) text");
5450   [self deleteWorkingText];
5451   processingCompose = NO;
5455 /* used to position char selection windows, etc. */
5456 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5458   NSRect rect;
5459   NSPoint pt;
5460   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5461   if (NS_KEYLOG)
5462     NSLog (@"firstRectForCharRange request");
5464   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5465   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5466   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5467   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5468                                        +FRAME_LINE_HEIGHT (emacsframe));
5470   pt = [self convertPoint: pt toView: nil];
5471   pt = [[self window] convertBaseToScreen: pt];
5472   rect.origin = pt;
5473   return rect;
5477 - (NSInteger)conversationIdentifier
5479   return (NSInteger)self;
5483 - (void)doCommandBySelector: (SEL)aSelector
5485   if (NS_KEYLOG)
5486     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5488   processingCompose = NO;
5489   if (aSelector == @selector (deleteBackward:))
5490     {
5491       /* happens when user backspaces over an ongoing composition:
5492          throw a 'delete' into the event queue */
5493       if (!emacs_event)
5494         return;
5495       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5496       emacs_event->code = 0xFF08;
5497       EV_TRAILER ((id)nil);
5498     }
5501 - (NSArray *)validAttributesForMarkedText
5503   static NSArray *arr = nil;
5504   if (arr == nil) arr = [NSArray new];
5505  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5506   return arr;
5509 - (NSRange)selectedRange
5511   if (NS_KEYLOG)
5512     NSLog (@"selectedRange request");
5513   return NSMakeRange (NSNotFound, 0);
5516 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5517     GNUSTEP_GUI_MINOR_VERSION > 22
5518 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5519 #else
5520 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5521 #endif
5523   if (NS_KEYLOG)
5524     NSLog (@"characterIndexForPoint request");
5525   return 0;
5528 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5530   static NSAttributedString *str = nil;
5531   if (str == nil) str = [NSAttributedString new];
5532   if (NS_KEYLOG)
5533     NSLog (@"attributedSubstringFromRange request");
5534   return str;
5537 /* End <NSTextInput> impl. */
5538 /*****************************************************************************/
5541 /* This is what happens when the user presses a mouse button.  */
5542 - (void)mouseDown: (NSEvent *)theEvent
5544   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5545   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5547   NSTRACE (mouseDown);
5549   [self deleteWorkingText];
5551   if (!emacs_event)
5552     return;
5554   dpyinfo->last_mouse_frame = emacsframe;
5555   /* appears to be needed to prevent spurious movement events generated on
5556      button clicks */
5557   emacsframe->mouse_moved = 0;
5559   if ([theEvent type] == NSScrollWheel)
5560     {
5561       CGFloat delta = [theEvent deltaY];
5562       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5563       if (delta == 0)
5564         {
5565           delta = [theEvent deltaX];
5566           if (delta == 0)
5567             {
5568               NSTRACE (deltaIsZero);
5569               return;
5570             }
5571           emacs_event->kind = HORIZ_WHEEL_EVENT;
5572         }
5573       else
5574         emacs_event->kind = WHEEL_EVENT;
5576       emacs_event->code = 0;
5577       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5578         ((delta > 0) ? up_modifier : down_modifier);
5579     }
5580   else
5581     {
5582       emacs_event->kind = MOUSE_CLICK_EVENT;
5583       emacs_event->code = EV_BUTTON (theEvent);
5584       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5585                              | EV_UDMODIFIERS (theEvent);
5586     }
5587   XSETINT (emacs_event->x, lrint (p.x));
5588   XSETINT (emacs_event->y, lrint (p.y));
5589   EV_TRAILER (theEvent);
5593 - (void)rightMouseDown: (NSEvent *)theEvent
5595   NSTRACE (rightMouseDown);
5596   [self mouseDown: theEvent];
5600 - (void)otherMouseDown: (NSEvent *)theEvent
5602   NSTRACE (otherMouseDown);
5603   [self mouseDown: theEvent];
5607 - (void)mouseUp: (NSEvent *)theEvent
5609   NSTRACE (mouseUp);
5610   [self mouseDown: theEvent];
5614 - (void)rightMouseUp: (NSEvent *)theEvent
5616   NSTRACE (rightMouseUp);
5617   [self mouseDown: theEvent];
5621 - (void)otherMouseUp: (NSEvent *)theEvent
5623   NSTRACE (otherMouseUp);
5624   [self mouseDown: theEvent];
5628 - (void) scrollWheel: (NSEvent *)theEvent
5630   NSTRACE (scrollWheel);
5631   [self mouseDown: theEvent];
5635 /* Tell emacs the mouse has moved. */
5636 - (void)mouseMoved: (NSEvent *)e
5638   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5639   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5640   Lisp_Object frame;
5641   NSPoint pt;
5643 //  NSTRACE (mouseMoved);
5645   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
5646   pt = [self convertPoint: [e locationInWindow] fromView: nil];
5647   dpyinfo->last_mouse_motion_x = pt.x;
5648   dpyinfo->last_mouse_motion_y = pt.y;
5650   /* update any mouse face */
5651   if (hlinfo->mouse_face_hidden)
5652     {
5653       hlinfo->mouse_face_hidden = 0;
5654       clear_mouse_face (hlinfo);
5655     }
5657   /* tooltip handling */
5658   previous_help_echo_string = help_echo_string;
5659   help_echo_string = Qnil;
5661   if (!NILP (Vmouse_autoselect_window))
5662     {
5663       NSTRACE (mouse_autoselect_window);
5664       static Lisp_Object last_mouse_window;
5665       Lisp_Object window
5666         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
5668       if (WINDOWP (window)
5669           && !EQ (window, last_mouse_window)
5670           && !EQ (window, selected_window)
5671           && (focus_follows_mouse
5672               || (EQ (XWINDOW (window)->frame,
5673                       XWINDOW (selected_window)->frame))))
5674         {
5675           NSTRACE (in_window);
5676           emacs_event->kind = SELECT_WINDOW_EVENT;
5677           emacs_event->frame_or_window = window;
5678           EV_TRAILER2 (e);
5679         }
5680       /* Remember the last window where we saw the mouse.  */
5681       last_mouse_window = window;
5682     }
5684   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
5685     help_echo_string = previous_help_echo_string;
5687   XSETFRAME (frame, emacsframe);
5688   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5689     {
5690       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5691          (note_mouse_highlight), which is called through the
5692          note_mouse_movement () call above */
5693       gen_help_event (help_echo_string, frame, help_echo_window,
5694                       help_echo_object, help_echo_pos);
5695     }
5696   else
5697     {
5698       help_echo_string = Qnil;
5699       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5700     }
5702   if (emacsframe->mouse_moved && send_appdefined)
5703     ns_send_appdefined (-1);
5707 - (void)mouseDragged: (NSEvent *)e
5709   NSTRACE (mouseDragged);
5710   [self mouseMoved: e];
5714 - (void)rightMouseDragged: (NSEvent *)e
5716   NSTRACE (rightMouseDragged);
5717   [self mouseMoved: e];
5721 - (void)otherMouseDragged: (NSEvent *)e
5723   NSTRACE (otherMouseDragged);
5724   [self mouseMoved: e];
5728 - (BOOL)windowShouldClose: (id)sender
5730   NSEvent *e =[[self window] currentEvent];
5732   NSTRACE (windowShouldClose);
5733   windowClosing = YES;
5734   if (!emacs_event)
5735     return NO;
5736   emacs_event->kind = DELETE_WINDOW_EVENT;
5737   emacs_event->modifiers = 0;
5738   emacs_event->code = 0;
5739   EV_TRAILER (e);
5740   /* Don't close this window, let this be done from lisp code.  */
5741   return NO;
5744 - (void) updateFrameSize: (BOOL) delay;
5746   NSWindow *window = [self window];
5747   NSRect wr = [window frame];
5748   int extra = 0;
5749   int oldc = cols, oldr = rows;
5750   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
5751   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5752   int neww, newh;
5754   NSTRACE (updateFrameSize);
5755   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
5757   if (! [self isFullscreen])
5758     {
5759 #ifdef NS_IMPL_GNUSTEP
5760       // GNUstep does not always update the tool bar height.  Force it.
5761       if (toolbar) update_frame_tool_bar (emacsframe);
5762 #endif
5764       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5765         + FRAME_TOOLBAR_HEIGHT (emacsframe);
5766     }
5768   if (wait_for_tool_bar)
5769     {
5770       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
5771         return;
5772       wait_for_tool_bar = NO;
5773     }
5775   neww = (int)wr.size.width - emacsframe->border_width;
5776   newh = (int)wr.size.height - extra;
5778   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
5779   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
5781   if (cols < MINWIDTH)
5782     cols = MINWIDTH;
5784   if (rows < MINHEIGHT)
5785     rows = MINHEIGHT;
5787   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5788     {
5789       NSView *view = FRAME_NS_VIEW (emacsframe);
5790       NSWindow *win = [view window];
5791       NSSize sz = [win resizeIncrements];
5793       change_frame_size (emacsframe,
5794                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
5795                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
5796                          0, delay, 0, 1);
5797       SET_FRAME_GARBAGED (emacsframe);
5798       cancel_mouse_face (emacsframe);
5800       // Did resize increments change because of a font change?
5801       if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5802           sz.height != FRAME_LINE_HEIGHT (emacsframe))
5803         {
5804           sz.width = FRAME_COLUMN_WIDTH (emacsframe);
5805           sz.height = FRAME_LINE_HEIGHT (emacsframe);
5806           [win setResizeIncrements: sz];
5808           NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
5809         }
5811       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5812       [self windowDidMove:nil];   // Update top/left.
5813     }
5816 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5817 /* normalize frame to gridded text size */
5819   int extra = 0;
5821   NSTRACE (windowWillResize);
5822   NSTRACE_SIZE ("Original size", frameSize);
5823 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5825   if (fs_state == FULLSCREEN_MAXIMIZED
5826       && (maximized_width != (int)frameSize.width
5827           || maximized_height != (int)frameSize.height))
5828     [self setFSValue: FULLSCREEN_NONE];
5829   else if (fs_state == FULLSCREEN_WIDTH
5830            && maximized_width != (int)frameSize.width)
5831     [self setFSValue: FULLSCREEN_NONE];
5832   else if (fs_state == FULLSCREEN_HEIGHT
5833            && maximized_height != (int)frameSize.height)
5834     [self setFSValue: FULLSCREEN_NONE];
5835   if (fs_state == FULLSCREEN_NONE)
5836     maximized_width = maximized_height = -1;
5838   if (! [self isFullscreen])
5839     {
5840       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5841         + FRAME_TOOLBAR_HEIGHT (emacsframe);
5842     }
5844   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
5845   if (cols < MINWIDTH)
5846     cols = MINWIDTH;
5848   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5849                                            frameSize.height - extra);
5850   if (rows < MINHEIGHT)
5851     rows = MINHEIGHT;
5852 #ifdef NS_IMPL_COCOA
5853   {
5854     /* this sets window title to have size in it; the wm does this under GS */
5855     NSRect r = [[self window] frame];
5856     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5857       {
5858         if (old_title != 0)
5859           {
5860             xfree (old_title);
5861             old_title = 0;
5862           }
5863       }
5864     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5865       {
5866         char *size_title;
5867         NSWindow *window = [self window];
5868         if (old_title == 0)
5869           {
5870             char *t = strdup ([[[self window] title] UTF8String]);
5871             char *pos = strstr (t, "  â€”  ");
5872             if (pos)
5873               *pos = '\0';
5874             old_title = t;
5875           }
5876         size_title = xmalloc (strlen (old_title) + 40);
5877         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5878         [window setTitle: [NSString stringWithUTF8String: size_title]];
5879         [window display];
5880         xfree (size_title);
5881       }
5882   }
5883 #endif /* NS_IMPL_COCOA */
5884 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5886   return frameSize;
5890 - (void)windowDidResize: (NSNotification *)notification
5892   if (! [self fsIsNative])
5893     {
5894       NSWindow *theWindow = [notification object];
5895       /* We can get notification on the non-FS window when in
5896          fullscreen mode.  */
5897       if ([self window] != theWindow) return;
5898     }
5900 #ifdef NS_IMPL_GNUSTEP
5901   NSWindow *theWindow = [notification object];
5903    /* In GNUstep, at least currently, it's possible to get a didResize
5904       without getting a willResize.. therefore we need to act as if we got
5905       the willResize now */
5906   NSSize sz = [theWindow frame].size;
5907   sz = [self windowWillResize: theWindow toSize: sz];
5908 #endif /* NS_IMPL_GNUSTEP */
5910   NSTRACE (windowDidResize);
5911 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5913 if (cols > 0 && rows > 0)
5914     {
5915       [self updateFrameSize: YES];
5916     }
5918   ns_send_appdefined (-1);
5921 #ifdef NS_IMPL_COCOA
5922 - (void)viewDidEndLiveResize
5924   [super viewDidEndLiveResize];
5925   if (old_title != 0)
5926     {
5927       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
5928       xfree (old_title);
5929       old_title = 0;
5930     }
5931   maximizing_resize = NO;
5933 #endif /* NS_IMPL_COCOA */
5936 - (void)windowDidBecomeKey: (NSNotification *)notification
5937 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5939   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5940   struct frame *old_focus = dpyinfo->x_focus_frame;
5942   NSTRACE (windowDidBecomeKey);
5944   if (emacsframe != old_focus)
5945     dpyinfo->x_focus_frame = emacsframe;
5947   ns_frame_rehighlight (emacsframe);
5949   if (emacs_event)
5950     {
5951       emacs_event->kind = FOCUS_IN_EVENT;
5952       EV_TRAILER ((id)nil);
5953     }
5957 - (void)windowDidResignKey: (NSNotification *)notification
5958 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5960   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5961   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
5962   NSTRACE (windowDidResignKey);
5964   if (is_focus_frame)
5965     dpyinfo->x_focus_frame = 0;
5967   emacsframe->mouse_moved = 0;
5968   ns_frame_rehighlight (emacsframe);
5970   /* FIXME: for some reason needed on second and subsequent clicks away
5971             from sole-frame Emacs to get hollow box to show */
5972   if (!windowClosing && [[self window] isVisible] == YES)
5973     {
5974       x_update_cursor (emacsframe, 1);
5975       x_set_frame_alpha (emacsframe);
5976     }
5978   if (emacs_event && is_focus_frame)
5979     {
5980       [self deleteWorkingText];
5981       emacs_event->kind = FOCUS_OUT_EVENT;
5982       EV_TRAILER ((id)nil);
5983     }
5987 - (void)windowWillMiniaturize: sender
5989   NSTRACE (windowWillMiniaturize);
5993 - (BOOL)isFlipped
5995   return YES;
5999 - (BOOL)isOpaque
6001   return NO;
6005 - initFrameFromEmacs: (struct frame *)f
6007   NSRect r, wr;
6008   Lisp_Object tem;
6009   NSWindow *win;
6010   NSSize sz;
6011   NSColor *col;
6012   NSString *name;
6014   NSTRACE (initFrameFromEmacs);
6016   windowClosing = NO;
6017   processingCompose = NO;
6018   scrollbarsNeedingUpdate = 0;
6019   fs_state = FULLSCREEN_NONE;
6020   fs_before_fs = next_maximized = -1;
6021 #ifdef HAVE_NATIVE_FS
6022   fs_is_native = ns_use_native_fullscreen;
6023 #else
6024   fs_is_native = NO;
6025 #endif
6026   maximized_width = maximized_height = -1;
6027   nonfs_window = nil;
6029 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
6031   ns_userRect = NSMakeRect (0, 0, 0, 0);
6032   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6033                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6034   [self initWithFrame: r];
6035   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6037   FRAME_NS_VIEW (f) = self;
6038   emacsframe = f;
6039 #ifdef NS_IMPL_COCOA
6040   old_title = 0;
6041   maximizing_resize = NO;
6042 #endif
6044   win = [[EmacsWindow alloc]
6045             initWithContentRect: r
6046                       styleMask: (NSResizableWindowMask |
6047 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6048                                   NSTitledWindowMask |
6049 #endif
6050                                   NSMiniaturizableWindowMask |
6051                                   NSClosableWindowMask)
6052                         backing: NSBackingStoreBuffered
6053                           defer: YES];
6055 #ifdef HAVE_NATIVE_FS
6056     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6057 #endif
6059   wr = [win frame];
6060   bwidth = f->border_width = wr.size.width - r.size.width;
6061   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6063   [win setAcceptsMouseMovedEvents: YES];
6064   [win setDelegate: self];
6065   [win useOptimizedDrawing: YES];
6067   sz.width = FRAME_COLUMN_WIDTH (f);
6068   sz.height = FRAME_LINE_HEIGHT (f);
6069   [win setResizeIncrements: sz];
6071   [[win contentView] addSubview: self];
6073   if (ns_drag_types)
6074     [self registerForDraggedTypes: ns_drag_types];
6076   tem = f->name;
6077   name = [NSString stringWithUTF8String:
6078                    NILP (tem) ? "Emacs" : SSDATA (tem)];
6079   [win setTitle: name];
6081   /* toolbar support */
6082   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6083                          [NSString stringWithFormat: @"Emacs Frame %d",
6084                                    ns_window_num]];
6085   [win setToolbar: toolbar];
6086   [toolbar setVisible: NO];
6088   /* Don't set frame garbaged until tool bar is up to date?
6089      This avoids an extra clear and redraw (flicker) at frame creation.  */
6090   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6091   else wait_for_tool_bar = NO;
6094 #ifdef NS_IMPL_COCOA
6095   {
6096     NSButton *toggleButton;
6097   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6098   [toggleButton setTarget: self];
6099   [toggleButton setAction: @selector (toggleToolbar: )];
6100   }
6101 #endif
6102   FRAME_TOOLBAR_HEIGHT (f) = 0;
6104   tem = f->icon_name;
6105   if (!NILP (tem))
6106     [win setMiniwindowTitle:
6107            [NSString stringWithUTF8String: SSDATA (tem)]];
6109   {
6110     NSScreen *screen = [win screen];
6112     if (screen != 0)
6113       [win setFrameTopLeftPoint: NSMakePoint
6114            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6115             IN_BOUND (-SCREENMAX,
6116                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
6117   }
6119   [win makeFirstResponder: self];
6121   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6122                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6123   [win setBackgroundColor: col];
6124   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6125     [win setOpaque: NO];
6127   [self allocateGState];
6129   [NSApp registerServicesMenuSendTypes: ns_send_types
6130                            returnTypes: nil];
6132   ns_window_num++;
6133   return self;
6137 - (void)windowDidMove: sender
6139   NSWindow *win = [self window];
6140   NSRect r = [win frame];
6141   NSArray *screens = [NSScreen screens];
6142   NSScreen *screen = [screens objectAtIndex: 0];
6144   NSTRACE (windowDidMove);
6146   if (!emacsframe->output_data.ns)
6147     return;
6148   if (screen != nil)
6149     {
6150       emacsframe->left_pos = r.origin.x;
6151       emacsframe->top_pos =
6152         [screen frame].size.height - (r.origin.y + r.size.height);
6153     }
6157 /* Called AFTER method below, but before our windowWillResize call there leads
6158    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
6159    location so set_window_size moves the frame. */
6160 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6162   emacsframe->output_data.ns->zooming = 1;
6163   return YES;
6167 /* Override to do something slightly nonstandard, but nice.  First click on
6168    zoom button will zoom vertically.  Second will zoom completely.  Third
6169    returns to original. */
6170 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6171                         defaultFrame:(NSRect)defaultFrame
6173   NSRect result = [sender frame];
6175   NSTRACE (windowWillUseStandardFrame);
6177   if (fs_before_fs != -1) /* Entering fullscreen */
6178       {
6179         result = defaultFrame;
6180       }
6181   else if (next_maximized == FULLSCREEN_HEIGHT
6182       || (next_maximized == -1
6183           && abs (defaultFrame.size.height - result.size.height)
6184           > FRAME_LINE_HEIGHT (emacsframe)))
6185     {
6186       /* first click */
6187       ns_userRect = result;
6188       maximized_height = result.size.height = defaultFrame.size.height;
6189       maximized_width = -1;
6190       result.origin.y = defaultFrame.origin.y;
6191       [self setFSValue: FULLSCREEN_HEIGHT];
6192 #ifdef NS_IMPL_COCOA
6193       maximizing_resize = YES;
6194 #endif
6195     }
6196   else if (next_maximized == FULLSCREEN_WIDTH)
6197     {
6198       ns_userRect = result;
6199       maximized_width = result.size.width = defaultFrame.size.width;
6200       maximized_height = -1;
6201       result.origin.x = defaultFrame.origin.x;
6202       [self setFSValue: FULLSCREEN_WIDTH];
6203     }
6204   else if (next_maximized == FULLSCREEN_MAXIMIZED
6205            || (next_maximized == -1
6206                && abs (defaultFrame.size.width - result.size.width)
6207                > FRAME_COLUMN_WIDTH (emacsframe)))
6208     {
6209       result = defaultFrame;  /* second click */
6210       maximized_width = result.size.width;
6211       maximized_height = result.size.height;
6212       [self setFSValue: FULLSCREEN_MAXIMIZED];
6213 #ifdef NS_IMPL_COCOA
6214       maximizing_resize = YES;
6215 #endif
6216     }
6217   else
6218     {
6219       /* restore */
6220       result = ns_userRect.size.height ? ns_userRect : result;
6221       ns_userRect = NSMakeRect (0, 0, 0, 0);
6222 #ifdef NS_IMPL_COCOA
6223       maximizing_resize = fs_state != FULLSCREEN_NONE;
6224 #endif
6225       [self setFSValue: FULLSCREEN_NONE];
6226       maximized_width = maximized_height = -1;
6227     }
6229   if (fs_before_fs == -1) next_maximized = -1;
6230   [self windowWillResize: sender toSize: result.size];
6231   return result;
6235 - (void)windowDidDeminiaturize: sender
6237   NSTRACE (windowDidDeminiaturize);
6238   if (!emacsframe->output_data.ns)
6239     return;
6241   SET_FRAME_ICONIFIED (emacsframe, 0);
6242   SET_FRAME_VISIBLE (emacsframe, 1);
6243   windows_or_buffers_changed = 63;
6245   if (emacs_event)
6246     {
6247       emacs_event->kind = DEICONIFY_EVENT;
6248       EV_TRAILER ((id)nil);
6249     }
6253 - (void)windowDidExpose: sender
6255   NSTRACE (windowDidExpose);
6256   if (!emacsframe->output_data.ns)
6257     return;
6259   SET_FRAME_VISIBLE (emacsframe, 1);
6260   SET_FRAME_GARBAGED (emacsframe);
6262   if (send_appdefined)
6263     ns_send_appdefined (-1);
6267 - (void)windowDidMiniaturize: sender
6269   NSTRACE (windowDidMiniaturize);
6270   if (!emacsframe->output_data.ns)
6271     return;
6273   SET_FRAME_ICONIFIED (emacsframe, 1);
6274   SET_FRAME_VISIBLE (emacsframe, 0);
6276   if (emacs_event)
6277     {
6278       emacs_event->kind = ICONIFY_EVENT;
6279       EV_TRAILER ((id)nil);
6280     }
6283 #ifdef HAVE_NATIVE_FS
6284 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6285       willUseFullScreenPresentationOptions:
6286   (NSApplicationPresentationOptions)proposedOptions
6288   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6290 #endif
6292 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6294   fs_before_fs = fs_state;
6297 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6299   [self setFSValue: FULLSCREEN_BOTH];
6300   if (! [self fsIsNative])
6301     {
6302       [self windowDidBecomeKey:notification];
6303       [nonfs_window orderOut:self];
6304     }
6305   else
6306     {
6307       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
6308 #ifdef NS_IMPL_COCOA
6309 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6310       unsigned val = (unsigned)[NSApp presentationOptions];
6312       // OSX 10.7 bug fix, the menu won't appear without this.
6313       // val is non-zero on other OSX versions.
6314       if (val == 0)
6315         {
6316           NSApplicationPresentationOptions options
6317             = NSApplicationPresentationAutoHideDock
6318             | NSApplicationPresentationAutoHideMenuBar
6319             | NSApplicationPresentationFullScreen
6320             | NSApplicationPresentationAutoHideToolbar;
6322           [NSApp setPresentationOptions: options];
6323         }
6324 #endif
6325 #endif
6326       [toolbar setVisible:tbar_visible];
6327     }
6330 - (void)windowWillExitFullScreen:(NSNotification *)notification
6332   if (next_maximized != -1)
6333     fs_before_fs = next_maximized;
6336 - (void)windowDidExitFullScreen:(NSNotification *)notification
6338   [self setFSValue: fs_before_fs];
6339   fs_before_fs = -1;
6340 #ifdef HAVE_NATIVE_FS
6341   [self updateCollectionBehavior];
6342 #endif
6343   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6344     {
6345       [toolbar setVisible:YES];
6346       update_frame_tool_bar (emacsframe);
6347       [self updateFrameSize:YES];
6348       [[self window] display];
6349     }
6350   else
6351     [toolbar setVisible:NO];
6353   if (next_maximized != -1)
6354     [[self window] performZoom:self];
6357 - (BOOL)fsIsNative
6359   return fs_is_native;
6362 - (BOOL)isFullscreen
6364   if (! fs_is_native) return nonfs_window != nil;
6365 #ifdef HAVE_NATIVE_FS
6366   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6367 #else
6368   return NO;
6369 #endif
6372 #ifdef HAVE_NATIVE_FS
6373 - (void)updateCollectionBehavior
6375   if (! [self isFullscreen])
6376     {
6377       NSWindow *win = [self window];
6378       NSWindowCollectionBehavior b = [win collectionBehavior];
6379       if (ns_use_native_fullscreen)
6380         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6381       else
6382         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6384       [win setCollectionBehavior: b];
6385       fs_is_native = ns_use_native_fullscreen;
6386     }
6388 #endif
6390 - (void)toggleFullScreen: (id)sender
6392   NSWindow *w, *fw;
6393   BOOL onFirstScreen;
6394   struct frame *f;
6395   NSSize sz;
6396   NSRect r, wr;
6397   NSColor *col;
6399   if (fs_is_native)
6400     {
6401 #ifdef HAVE_NATIVE_FS
6402       [[self window] toggleFullScreen:sender];
6403 #endif
6404       return;
6405     }
6407   w = [self window];
6408   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6409   f = emacsframe;
6410   wr = [w frame];
6411   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6412                                  (FRAME_DEFAULT_FACE (f)),
6413                                  f);
6415   sz.width = FRAME_COLUMN_WIDTH (f);
6416   sz.height = FRAME_LINE_HEIGHT (f);
6418   if (fs_state != FULLSCREEN_BOTH)
6419     {
6420       NSScreen *screen = [w screen];
6422 #if defined (NS_IMPL_COCOA) && \
6423   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
6424       /* Hide ghost menu bar on secondary monitor? */
6425       if (! onFirstScreen)
6426         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
6427 #endif
6428       /* Hide dock and menubar if we are on the primary screen.  */
6429       if (onFirstScreen)
6430         {
6431 #if defined (NS_IMPL_COCOA) && \
6432   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6433           NSApplicationPresentationOptions options
6434             = NSApplicationPresentationAutoHideDock
6435             | NSApplicationPresentationAutoHideMenuBar;
6437           [NSApp setPresentationOptions: options];
6438 #else
6439           [NSMenu setMenuBarVisible:NO];
6440 #endif
6441         }
6443       fw = [[EmacsFSWindow alloc]
6444                        initWithContentRect:[w contentRectForFrameRect:wr]
6445                                  styleMask:NSBorderlessWindowMask
6446                                    backing:NSBackingStoreBuffered
6447                                      defer:YES
6448                                     screen:screen];
6450       [fw setContentView:[w contentView]];
6451       [fw setTitle:[w title]];
6452       [fw setDelegate:self];
6453       [fw setAcceptsMouseMovedEvents: YES];
6454       [fw useOptimizedDrawing: YES];
6455       [fw setResizeIncrements: sz];
6456       [fw setBackgroundColor: col];
6457       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6458         [fw setOpaque: NO];
6460       f->border_width = 0;
6461       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6462       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6463       FRAME_TOOLBAR_HEIGHT (f) = 0;
6465       nonfs_window = w;
6467       [self windowWillEnterFullScreen:nil];
6468       [fw makeKeyAndOrderFront:NSApp];
6469       [fw makeFirstResponder:self];
6470       [w orderOut:self];
6471       r = [fw frameRectForContentRect:[screen frame]];
6472       [fw setFrame: r display:YES animate:YES];
6473       [self windowDidEnterFullScreen:nil];
6474       [fw display];
6475     }
6476   else
6477     {
6478       fw = w;
6479       w = nonfs_window;
6480       nonfs_window = nil;
6482       if (onFirstScreen)
6483         {
6484 #if defined (NS_IMPL_COCOA) && \
6485   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6486           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6487 #else
6488           [NSMenu setMenuBarVisible:YES];
6489 #endif
6490         }
6492       [w setContentView:[fw contentView]];
6493       [w setResizeIncrements: sz];
6494       [w setBackgroundColor: col];
6495       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6496         [w setOpaque: NO];
6498       f->border_width = bwidth;
6499       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6500       if (FRAME_EXTERNAL_TOOL_BAR (f))
6501         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6503       [self windowWillExitFullScreen:nil];
6504       [fw setFrame: [w frame] display:YES animate:YES];
6505       [fw close];
6506       [w makeKeyAndOrderFront:NSApp];
6507       [self windowDidExitFullScreen:nil];
6508       [self updateFrameSize:YES];
6509     }
6512 - (void)handleFS
6514   if (fs_state != emacsframe->want_fullscreen)
6515     {
6516       if (fs_state == FULLSCREEN_BOTH)
6517         {
6518           [self toggleFullScreen:self];
6519         }
6521       switch (emacsframe->want_fullscreen)
6522         {
6523         case FULLSCREEN_BOTH:
6524           [self toggleFullScreen:self];
6525           break;
6526         case FULLSCREEN_WIDTH:
6527           next_maximized = FULLSCREEN_WIDTH;
6528           if (fs_state != FULLSCREEN_BOTH)
6529             [[self window] performZoom:self];
6530           break;
6531         case FULLSCREEN_HEIGHT:
6532           next_maximized = FULLSCREEN_HEIGHT;
6533           if (fs_state != FULLSCREEN_BOTH)
6534             [[self window] performZoom:self];
6535           break;
6536         case FULLSCREEN_MAXIMIZED:
6537           next_maximized = FULLSCREEN_MAXIMIZED;
6538           if (fs_state != FULLSCREEN_BOTH)
6539             [[self window] performZoom:self];
6540           break;
6541         case FULLSCREEN_NONE:
6542           if (fs_state != FULLSCREEN_BOTH)
6543             {
6544               next_maximized = FULLSCREEN_NONE;
6545               [[self window] performZoom:self];
6546             }
6547           break;
6548         }
6550       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6551     }
6555 - (void) setFSValue: (int)value
6557   Lisp_Object lval = Qnil;
6558   switch (value)
6559     {
6560     case FULLSCREEN_BOTH:
6561       lval = Qfullboth;
6562       break;
6563     case FULLSCREEN_WIDTH:
6564       lval = Qfullwidth;
6565       break;
6566     case FULLSCREEN_HEIGHT:
6567       lval = Qfullheight;
6568       break;
6569     case FULLSCREEN_MAXIMIZED:
6570       lval = Qmaximized;
6571       break;
6572     }
6573   store_frame_param (emacsframe, Qfullscreen, lval);
6574   fs_state = value;
6577 - (void)mouseEntered: (NSEvent *)theEvent
6579   NSTRACE (mouseEntered);
6580   if (emacsframe)
6581     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6582       = EV_TIMESTAMP (theEvent);
6586 - (void)mouseExited: (NSEvent *)theEvent
6588   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6590   NSTRACE (mouseExited);
6592   if (!hlinfo)
6593     return;
6595   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6596     = EV_TIMESTAMP (theEvent);
6598   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6599     {
6600       clear_mouse_face (hlinfo);
6601       hlinfo->mouse_face_mouse_frame = 0;
6602     }
6606 - menuDown: sender
6608   NSTRACE (menuDown);
6609   if (context_menu_value == -1)
6610     context_menu_value = [sender tag];
6611   else
6612     {
6613       NSInteger tag = [sender tag];
6614       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6615                                     emacsframe->menu_bar_vector,
6616                                     (void *)tag);
6617     }
6619   ns_send_appdefined (-1);
6620   return self;
6624 - (EmacsToolbar *)toolbar
6626   return toolbar;
6630 /* this gets called on toolbar button click */
6631 - toolbarClicked: (id)item
6633   NSEvent *theEvent;
6634   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6636   NSTRACE (toolbarClicked);
6638   if (!emacs_event)
6639     return self;
6641   /* send first event (for some reason two needed) */
6642   theEvent = [[self window] currentEvent];
6643   emacs_event->kind = TOOL_BAR_EVENT;
6644   XSETFRAME (emacs_event->arg, emacsframe);
6645   EV_TRAILER (theEvent);
6647   emacs_event->kind = TOOL_BAR_EVENT;
6648 /*   XSETINT (emacs_event->code, 0); */
6649   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6650                            idx + TOOL_BAR_ITEM_KEY);
6651   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6652   EV_TRAILER (theEvent);
6653   return self;
6657 - toggleToolbar: (id)sender
6659   if (!emacs_event)
6660     return self;
6662   emacs_event->kind = NS_NONKEY_EVENT;
6663   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6664   EV_TRAILER ((id)nil);
6665   return self;
6669 - (void)drawRect: (NSRect)rect
6671   int x = NSMinX (rect), y = NSMinY (rect);
6672   int width = NSWidth (rect), height = NSHeight (rect);
6674   NSTRACE (drawRect);
6676   if (!emacsframe || !emacsframe->output_data.ns)
6677     return;
6679   ns_clear_frame_area (emacsframe, x, y, width, height);
6680   expose_frame (emacsframe, x, y, width, height);
6682   /*
6683     drawRect: may be called (at least in OS X 10.5) for invisible
6684     views as well for some reason.  Thus, do not infer visibility
6685     here.
6687     emacsframe->async_visible = 1;
6688     emacsframe->async_iconified = 0;
6689   */
6693 /* NSDraggingDestination protocol methods.  Actually this is not really a
6694    protocol, but a category of Object.  O well...  */
6696 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6698   NSTRACE (draggingEntered);
6699   return NSDragOperationGeneric;
6703 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6705   return YES;
6709 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6711   id pb;
6712   int x, y;
6713   NSString *type;
6714   NSEvent *theEvent = [[self window] currentEvent];
6715   NSPoint position;
6716   NSDragOperation op = [sender draggingSourceOperationMask];
6717   int modifiers = 0;
6719   NSTRACE (performDragOperation);
6721   if (!emacs_event)
6722     return NO;
6724   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6725   x = lrint (position.x);  y = lrint (position.y);
6727   pb = [sender draggingPasteboard];
6728   type = [pb availableTypeFromArray: ns_drag_types];
6730   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
6731       // URL drags contain all operations (0xf), don't allow all to be set.
6732       (op & 0xf) != 0xf)
6733     {
6734       if (op & NSDragOperationLink)
6735         modifiers |= NSControlKeyMask;
6736       if (op & NSDragOperationCopy)
6737         modifiers |= NSAlternateKeyMask;
6738       if (op & NSDragOperationGeneric)
6739         modifiers |= NSCommandKeyMask;
6740     }
6742   modifiers = EV_MODIFIERS2 (modifiers);
6743   if (type == 0)
6744     {
6745       return NO;
6746     }
6747   else if ([type isEqualToString: NSFilenamesPboardType])
6748     {
6749       NSArray *files;
6750       NSEnumerator *fenum;
6751       NSString *file;
6753       if (!(files = [pb propertyListForType: type]))
6754         return NO;
6756       fenum = [files objectEnumerator];
6757       while ( (file = [fenum nextObject]) )
6758         {
6759           emacs_event->kind = DRAG_N_DROP_EVENT;
6760           XSETINT (emacs_event->x, x);
6761           XSETINT (emacs_event->y, y);
6762           ns_input_file = append2 (ns_input_file,
6763                                    build_string ([file UTF8String]));
6764           emacs_event->modifiers = modifiers;
6765           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
6766           EV_TRAILER (theEvent);
6767         }
6768       return YES;
6769     }
6770   else if ([type isEqualToString: NSURLPboardType])
6771     {
6772       NSURL *url = [NSURL URLFromPasteboard: pb];
6773       if (url == nil) return NO;
6775       emacs_event->kind = DRAG_N_DROP_EVENT;
6776       XSETINT (emacs_event->x, x);
6777       XSETINT (emacs_event->y, y);
6778       emacs_event->modifiers = modifiers;
6779       emacs_event->arg =  list2 (Qurl,
6780                                  build_string ([[url absoluteString]
6781                                                  UTF8String]));
6782       EV_TRAILER (theEvent);
6784       if ([url isFileURL] != NO)
6785         {
6786           NSString *file = [url path];
6787           ns_input_file = append2 (ns_input_file,
6788                                    build_string ([file UTF8String]));
6789         }
6790       return YES;
6791     }
6792   else if ([type isEqualToString: NSStringPboardType]
6793            || [type isEqualToString: NSTabularTextPboardType])
6794     {
6795       NSString *data;
6797       if (! (data = [pb stringForType: type]))
6798         return NO;
6800       emacs_event->kind = DRAG_N_DROP_EVENT;
6801       XSETINT (emacs_event->x, x);
6802       XSETINT (emacs_event->y, y);
6803       emacs_event->modifiers = modifiers;
6804       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
6805       EV_TRAILER (theEvent);
6806       return YES;
6807     }
6808   else
6809     {
6810       error ("Invalid data type in dragging pasteboard");
6811       return NO;
6812     }
6816 - (id) validRequestorForSendType: (NSString *)typeSent
6817                       returnType: (NSString *)typeReturned
6819   NSTRACE (validRequestorForSendType);
6820   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6821       && typeReturned == nil)
6822     {
6823       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6824         return self;
6825     }
6827   return [super validRequestorForSendType: typeSent
6828                                returnType: typeReturned];
6832 /* The next two methods are part of NSServicesRequests informal protocol,
6833    supposedly called when a services menu item is chosen from this app.
6834    But this should not happen because we override the services menu with our
6835    own entries which call ns-perform-service.
6836    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6837    So let's at least stub them out until further investigation can be done. */
6839 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6841   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6842      be written into the buffer in place of the existing selection..
6843      ordinary service calls go through functions defined in ns-win.el */
6844   return NO;
6847 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6849   NSArray *typesDeclared;
6850   Lisp_Object val;
6852   /* We only support NSStringPboardType */
6853   if ([types containsObject:NSStringPboardType] == NO) {
6854     return NO;
6855   }
6857   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6858   if (CONSP (val) && SYMBOLP (XCAR (val)))
6859     {
6860       val = XCDR (val);
6861       if (CONSP (val) && NILP (XCDR (val)))
6862         val = XCAR (val);
6863     }
6864   if (! STRINGP (val))
6865     return NO;
6867   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6868   [pb declareTypes:typesDeclared owner:nil];
6869   ns_string_to_pasteboard (pb, val);
6870   return YES;
6874 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6875    (gives a miniaturized version of the window); currently we use the latter for
6876    frames whose active buffer doesn't correspond to any file
6877    (e.g., '*scratch*') */
6878 - setMiniwindowImage: (BOOL) setMini
6880   id image = [[self window] miniwindowImage];
6881   NSTRACE (setMiniwindowImage);
6883   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6884      about "AppleDockIconEnabled" notwithstanding, however the set message
6885      below has its effect nonetheless. */
6886   if (image != emacsframe->output_data.ns->miniimage)
6887     {
6888       if (image && [image isKindOfClass: [EmacsImage class]])
6889         [image release];
6890       [[self window] setMiniwindowImage:
6891                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6892     }
6894   return self;
6898 - (void) setRows: (int) r andColumns: (int) c
6900   rows = r;
6901   cols = c;
6904 @end  /* EmacsView */
6908 /* ==========================================================================
6910     EmacsWindow implementation
6912    ========================================================================== */
6914 @implementation EmacsWindow
6916 #ifdef NS_IMPL_COCOA
6917 - (id)accessibilityAttributeValue:(NSString *)attribute
6919   Lisp_Object str = Qnil;
6920   struct frame *f = SELECTED_FRAME ();
6921   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
6923   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6924     return NSAccessibilityTextFieldRole;
6926   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6927       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6928     {
6929       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6930     }
6931   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6932     {
6933       if (! NILP (BVAR (curbuf, mark_active)))
6934           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6936       if (NILP (str))
6937         {
6938           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6939           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6940           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6942           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6943             str = make_uninit_multibyte_string (range, byte_range);
6944           else
6945             str = make_uninit_string (range);
6946           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6947              Is this a problem?  */
6948           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6949         }
6950     }
6953   if (! NILP (str))
6954     {
6955       if (CONSP (str) && SYMBOLP (XCAR (str)))
6956         {
6957           str = XCDR (str);
6958           if (CONSP (str) && NILP (XCDR (str)))
6959             str = XCAR (str);
6960         }
6961       if (STRINGP (str))
6962         {
6963           const char *utfStr = SSDATA (str);
6964           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6965           return nsStr;
6966         }
6967     }
6969   return [super accessibilityAttributeValue:attribute];
6971 #endif /* NS_IMPL_COCOA */
6973 /* If we have multiple monitors, one above the other, we don't want to
6974    restrict the height to just one monitor.  So we override this.  */
6975 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6977   /* When making the frame visible for the first time or if there is just
6978      one screen, we want to constrain.  Other times not.  */
6979   NSArray *screens = [NSScreen screens];
6980   NSUInteger nr_screens = [screens count], nr_eff_screens = 0, i;
6981   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6982   NSTRACE (constrainFrameRect);
6983   NSTRACE_RECT ("input", frameRect);
6985   if (ns_menu_bar_should_be_hidden ())
6986     return frameRect;
6988   if (nr_screens == 1)
6989     return [super constrainFrameRect:frameRect toScreen:screen];
6991 #ifdef NS_IMPL_COCOA
6992 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
6993   // If separate spaces is on, it is like each screen is independent.  There is
6994   // no spanning of frames across screens.
6995   if ([NSScreen screensHaveSeparateSpaces])
6996     return [super constrainFrameRect:frameRect toScreen:screen];
6997 #endif
6998 #endif
7000   for (i = 0; i < nr_screens; ++i) 
7001     {
7002       NSScreen *s = [screens objectAtIndex: i];
7003       NSRect scrrect = [s frame];
7004       NSRect intersect = NSIntersectionRect (frameRect, scrrect);
7006       if (intersect.size.width > 0 || intersect.size.height > 0)
7007         ++nr_eff_screens;
7008     }
7010   if (nr_eff_screens == 1)
7011     return [super constrainFrameRect:frameRect toScreen:screen];
7012   
7013   /* The default implementation does two things 1) ensure that the top
7014      of the rectangle is below the menu bar (or below the top of the
7015      screen) and 2) resizes windows larger than the screen. As we
7016      don't want the latter, a smaller rectangle is used. */
7017 #define FAKE_HEIGHT 64
7018   float old_top = frameRect.origin.y + frameRect.size.height;
7019   NSRect r;
7020   r.size.height = FAKE_HEIGHT;
7021   r.size.width = frameRect.size.width;
7022   r.origin.x = frameRect.origin.x;
7023   r.origin.y = old_top - FAKE_HEIGHT;
7025   NSTRACE_RECT ("input to super", r);
7027   r = [super constrainFrameRect:r toScreen:screen];
7029   NSTRACE_RECT ("output from super", r);
7031   float new_top = r.origin.y + FAKE_HEIGHT;
7032   if (new_top < old_top)
7033   {
7034     frameRect.origin.y = new_top - frameRect.size.height;
7035   }
7037   NSTRACE_RECT ("output", frameRect);
7039   return frameRect;
7040 #undef FAKE_HEIGHT
7043 @end /* EmacsWindow */
7046 @implementation EmacsFSWindow
7048 - (BOOL)canBecomeKeyWindow
7050   return YES;
7053 - (BOOL)canBecomeMainWindow
7055   return YES;
7058 @end
7060 /* ==========================================================================
7062     EmacsScroller implementation
7064    ========================================================================== */
7067 @implementation EmacsScroller
7069 /* for repeat button push */
7070 #define SCROLL_BAR_FIRST_DELAY 0.5
7071 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
7073 + (CGFloat) scrollerWidth
7075   /* TODO: if we want to allow variable widths, this is the place to do it,
7076            however neither GNUstep nor Cocoa support it very well */
7077   return [NSScroller scrollerWidth];
7081 - initFrame: (NSRect )r window: (Lisp_Object)nwin
7083   NSTRACE (EmacsScroller_initFrame);
7085   r.size.width = [EmacsScroller scrollerWidth];
7086   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
7087   [self setContinuous: YES];
7088   [self setEnabled: YES];
7090   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
7091      locked against the top and bottom edges, and right edge on OS X, where
7092      scrollers are on right. */
7093 #ifdef NS_IMPL_GNUSTEP
7094   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
7095 #else
7096   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
7097 #endif
7099   win = nwin;
7100   condemned = NO;
7101   pixel_height = NSHeight (r);
7102   if (pixel_height == 0) pixel_height = 1;
7103   min_portion = 20 / pixel_height;
7105   frame = XFRAME (XWINDOW (win)->frame);
7106   if (FRAME_LIVE_P (frame))
7107     {
7108       int i;
7109       EmacsView *view = FRAME_NS_VIEW (frame);
7110       NSView *sview = [[view window] contentView];
7111       NSArray *subs = [sview subviews];
7113       /* disable optimization stopping redraw of other scrollbars */
7114       view->scrollbarsNeedingUpdate = 0;
7115       for (i =[subs count]-1; i >= 0; i--)
7116         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
7117           view->scrollbarsNeedingUpdate++;
7118       [sview addSubview: self];
7119     }
7121 /*  [self setFrame: r]; */
7123   return self;
7127 - (void)setFrame: (NSRect)newRect
7129   NSTRACE (EmacsScroller_setFrame);
7130 /*  block_input (); */
7131   pixel_height = NSHeight (newRect);
7132   if (pixel_height == 0) pixel_height = 1;
7133   min_portion = 20 / pixel_height;
7134   [super setFrame: newRect];
7135   [self display];
7136 /*  unblock_input (); */
7140 - (void)dealloc
7142   NSTRACE (EmacsScroller_dealloc);
7143   if (!NILP (win))
7144     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
7145   [super dealloc];
7149 - condemn
7151   NSTRACE (condemn);
7152   condemned =YES;
7153   return self;
7157 - reprieve
7159   NSTRACE (reprieve);
7160   condemned =NO;
7161   return self;
7165 - judge
7167   NSTRACE (judge);
7168   if (condemned)
7169     {
7170       EmacsView *view;
7171       block_input ();
7172       /* ensure other scrollbar updates after deletion */
7173       view = (EmacsView *)FRAME_NS_VIEW (frame);
7174       if (view != nil)
7175         view->scrollbarsNeedingUpdate++;
7176       [self removeFromSuperview];
7177       [self release];
7178       unblock_input ();
7179     }
7180   return self;
7184 - (void)resetCursorRects
7186   NSRect visible = [self visibleRect];
7187   NSTRACE (resetCursorRects);
7189   if (!NSIsEmptyRect (visible))
7190     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
7191   [[NSCursor arrowCursor] setOnMouseEntered: YES];
7195 - (int) checkSamePosition: (int) position portion: (int) portion
7196                     whole: (int) whole
7198   return em_position ==position && em_portion ==portion && em_whole ==whole
7199     && portion != whole; /* needed for resize empty buf */
7203 - setPosition: (int)position portion: (int)portion whole: (int)whole
7205   NSTRACE (setPosition);
7207   em_position = position;
7208   em_portion = portion;
7209   em_whole = whole;
7211   if (portion >= whole)
7212     {
7213 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
7214       [self setKnobProportion: 1.0];
7215       [self setDoubleValue: 1.0];
7216 #else
7217       [self setFloatValue: 0.0 knobProportion: 1.0];
7218 #endif
7219     }
7220   else
7221     {
7222       float pos;
7223       CGFloat por;
7224       portion = max ((float)whole*min_portion/pixel_height, portion);
7225       pos = (float)position / (whole - portion);
7226       por = (CGFloat)portion/whole;
7227 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
7228       [self setKnobProportion: por];
7229       [self setDoubleValue: pos];
7230 #else
7231       [self setFloatValue: pos knobProportion: por];
7232 #endif
7233     }
7235   /* Events may come here even if the event loop is not running.
7236      If we don't enter the event loop, the scroll bar will not update.
7237      So send SIGIO to ourselves.  */
7238   if (apploopnr == 0) raise (SIGIO);
7240   return self;
7243 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
7244      drag events will go directly to the EmacsScroller.  Leaving in for now. */
7245 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
7246                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
7248   *part = last_hit_part;
7249   *window = win;
7250   XSETINT (*y, pixel_height);
7251   if ([self floatValue] > 0.999F)
7252     XSETINT (*x, pixel_height);
7253   else
7254     XSETINT (*x, pixel_height * [self floatValue]);
7258 /* set up emacs_event */
7259 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
7261   if (!emacs_event)
7262     return;
7264   emacs_event->part = last_hit_part;
7265   emacs_event->code = 0;
7266   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
7267   emacs_event->frame_or_window = win;
7268   emacs_event->timestamp = EV_TIMESTAMP (e);
7269   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
7270   emacs_event->arg = Qnil;
7271   XSETINT (emacs_event->x, loc * pixel_height);
7272   XSETINT (emacs_event->y, pixel_height-20);
7274   if (q_event_ptr)
7275     {
7276       n_emacs_events_pending++;
7277       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7278     }
7279   else
7280     hold_event (emacs_event);
7281   EVENT_INIT (*emacs_event);
7282   ns_send_appdefined (-1);
7286 /* called manually thru timer to implement repeated button action w/hold-down */
7287 - repeatScroll: (NSTimer *)scrollEntry
7289   NSEvent *e = [[self window] currentEvent];
7290   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
7291   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7293   /* clear timer if need be */
7294   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7295     {
7296         [scroll_repeat_entry invalidate];
7297         [scroll_repeat_entry release];
7298         scroll_repeat_entry = nil;
7300         if (inKnob)
7301           return self;
7303         scroll_repeat_entry
7304           = [[NSTimer scheduledTimerWithTimeInterval:
7305                         SCROLL_BAR_CONTINUOUS_DELAY
7306                                             target: self
7307                                           selector: @selector (repeatScroll:)
7308                                           userInfo: 0
7309                                            repeats: YES]
7310               retain];
7311     }
7313   [self sendScrollEventAtLoc: 0 fromEvent: e];
7314   return self;
7318 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
7319    mouseDragged events without going into a modal loop. */
7320 - (void)mouseDown: (NSEvent *)e
7322   NSRect sr, kr;
7323   /* hitPart is only updated AFTER event is passed on */
7324   NSScrollerPart part = [self testPart: [e locationInWindow]];
7325   CGFloat inc = 0.0, loc, kloc, pos;
7326   int edge = 0;
7328   NSTRACE (EmacsScroller_mouseDown);
7330   switch (part)
7331     {
7332     case NSScrollerDecrementPage:
7333         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7334     case NSScrollerIncrementPage:
7335         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7336     case NSScrollerDecrementLine:
7337       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7338     case NSScrollerIncrementLine:
7339       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7340     case NSScrollerKnob:
7341       last_hit_part = scroll_bar_handle; break;
7342     case NSScrollerKnobSlot:  /* GNUstep-only */
7343       last_hit_part = scroll_bar_move_ratio; break;
7344     default:  /* NSScrollerNoPart? */
7345       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7346                (long) part);
7347       return;
7348     }
7350   if (inc != 0.0)
7351     {
7352       pos = 0;      /* ignored */
7354       /* set a timer to repeat, as we can't let superclass do this modally */
7355       scroll_repeat_entry
7356         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7357                                             target: self
7358                                           selector: @selector (repeatScroll:)
7359                                           userInfo: 0
7360                                            repeats: YES]
7361             retain];
7362     }
7363   else
7364     {
7365       /* handle, or on GNUstep possibly slot */
7366       NSEvent *fake_event;
7368       /* compute float loc in slot and mouse offset on knob */
7369       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7370                       toView: nil];
7371       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7372       if (loc <= 0.0)
7373         {
7374           loc = 0.0;
7375           edge = -1;
7376         }
7377       else if (loc >= NSHeight (sr))
7378         {
7379           loc = NSHeight (sr);
7380           edge = 1;
7381         }
7383       if (edge)
7384         kloc = 0.5 * edge;
7385       else
7386         {
7387           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7388                           toView: nil];
7389           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7390         }
7391       last_mouse_offset = kloc;
7393       /* if knob, tell emacs a location offset by knob pos
7394          (to indicate top of handle) */
7395       if (part == NSScrollerKnob)
7396           pos = (loc - last_mouse_offset) / NSHeight (sr);
7397       else
7398         /* else this is a slot click on GNUstep: go straight there */
7399         pos = loc / NSHeight (sr);
7401       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7402       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7403                                       location: [e locationInWindow]
7404                                  modifierFlags: [e modifierFlags]
7405                                      timestamp: [e timestamp]
7406                                   windowNumber: [e windowNumber]
7407                                        context: [e context]
7408                                    eventNumber: [e eventNumber]
7409                                     clickCount: [e clickCount]
7410                                       pressure: [e pressure]];
7411       [super mouseUp: fake_event];
7412     }
7414   if (part != NSScrollerKnob)
7415     [self sendScrollEventAtLoc: pos fromEvent: e];
7419 /* Called as we manually track scroller drags, rather than superclass. */
7420 - (void)mouseDragged: (NSEvent *)e
7422     NSRect sr;
7423     double loc, pos;
7425     NSTRACE (EmacsScroller_mouseDragged);
7427       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7428                       toView: nil];
7429       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7431       if (loc <= 0.0)
7432         {
7433           loc = 0.0;
7434         }
7435       else if (loc >= NSHeight (sr) + last_mouse_offset)
7436         {
7437           loc = NSHeight (sr) + last_mouse_offset;
7438         }
7440       pos = (loc - last_mouse_offset) / NSHeight (sr);
7441       [self sendScrollEventAtLoc: pos fromEvent: e];
7445 - (void)mouseUp: (NSEvent *)e
7447   if (scroll_repeat_entry)
7448     {
7449       [scroll_repeat_entry invalidate];
7450       [scroll_repeat_entry release];
7451       scroll_repeat_entry = nil;
7452     }
7453   last_hit_part = 0;
7457 /* treat scrollwheel events in the bar as though they were in the main window */
7458 - (void) scrollWheel: (NSEvent *)theEvent
7460   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7461   [view mouseDown: theEvent];
7464 @end  /* EmacsScroller */
7467 #ifdef NS_IMPL_GNUSTEP
7468 /* Dummy class to get rid of startup warnings.  */
7469 @implementation EmacsDocument
7471 @end
7472 #endif
7475 /* ==========================================================================
7477    Font-related functions; these used to be in nsfaces.m
7479    ========================================================================== */
7482 Lisp_Object
7483 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7485   struct font *font = XFONT_OBJECT (font_object);
7486   EmacsView *view = FRAME_NS_VIEW (f);
7488   if (fontset < 0)
7489     fontset = fontset_from_font (font_object);
7490   FRAME_FONTSET (f) = fontset;
7492   if (FRAME_FONT (f) == font)
7493     /* This font is already set in frame F.  There's nothing more to
7494        do.  */
7495     return font_object;
7497   FRAME_FONT (f) = font;
7499   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7500   FRAME_COLUMN_WIDTH (f) = font->average_width;
7501   FRAME_LINE_HEIGHT (f) = font->height;
7503   compute_fringe_widths (f, 1);
7505   /* Compute the scroll bar width in character columns.  */
7506   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7507     {
7508       int wid = FRAME_COLUMN_WIDTH (f);
7509       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7510         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7511     }
7512   else
7513     {
7514       int wid = FRAME_COLUMN_WIDTH (f);
7515       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7516     }
7518   /* Now make the frame display the given font.  */
7519   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
7520     x_set_window_size (f, 0, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
7521                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 1);
7523   return font_object;
7527 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7528 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7529          in 1.43. */
7531 const char *
7532 ns_xlfd_to_fontname (const char *xlfd)
7533 /* --------------------------------------------------------------------------
7534     Convert an X font name (XLFD) to an NS font name.
7535     Only family is used.
7536     The string returned is temporarily allocated.
7537    -------------------------------------------------------------------------- */
7539   char *name = xmalloc (180);
7540   int i, len;
7541   const char *ret;
7543   if (!strncmp (xlfd, "--", 2))
7544     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7545   else
7546     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7548   /* stopgap for malformed XLFD input */
7549   if (strlen (name) == 0)
7550     strcpy (name, "Monaco");
7552   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7553      also uppercase after '-' or ' ' */
7554   name[0] = c_toupper (name[0]);
7555   for (len =strlen (name), i =0; i<len; i++)
7556     {
7557       if (name[i] == '$')
7558         {
7559           name[i] = '-';
7560           if (i+1<len)
7561             name[i+1] = c_toupper (name[i+1]);
7562         }
7563       else if (name[i] == '_')
7564         {
7565           name[i] = ' ';
7566           if (i+1<len)
7567             name[i+1] = c_toupper (name[i+1]);
7568         }
7569     }
7570 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7571   ret = [[NSString stringWithUTF8String: name] UTF8String];
7572   xfree (name);
7573   return ret;
7577 void
7578 syms_of_nsterm (void)
7580   NSTRACE (syms_of_nsterm);
7582   ns_antialias_threshold = 10.0;
7584   /* from 23+ we need to tell emacs what modifiers there are.. */
7585   DEFSYM (Qmodifier_value, "modifier-value");
7586   DEFSYM (Qalt, "alt");
7587   DEFSYM (Qhyper, "hyper");
7588   DEFSYM (Qmeta, "meta");
7589   DEFSYM (Qsuper, "super");
7590   DEFSYM (Qcontrol, "control");
7591   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7593   DEFSYM (Qfile, "file");
7594   DEFSYM (Qurl, "url");
7596   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7597   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7598   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7599   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7600   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7602   DEFVAR_LISP ("ns-input-file", ns_input_file,
7603               "The file specified in the last NS event.");
7604   ns_input_file =Qnil;
7606   DEFVAR_LISP ("ns-working-text", ns_working_text,
7607               "String for visualizing working composition sequence.");
7608   ns_working_text =Qnil;
7610   DEFVAR_LISP ("ns-input-font", ns_input_font,
7611               "The font specified in the last NS event.");
7612   ns_input_font =Qnil;
7614   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7615               "The fontsize specified in the last NS event.");
7616   ns_input_fontsize =Qnil;
7618   DEFVAR_LISP ("ns-input-line", ns_input_line,
7619                "The line specified in the last NS event.");
7620   ns_input_line =Qnil;
7622   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7623                "The service name specified in the last NS event.");
7624   ns_input_spi_name =Qnil;
7626   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7627                "The service argument specified in the last NS event.");
7628   ns_input_spi_arg =Qnil;
7630   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7631                "This variable describes the behavior of the alternate or option key.\n\
7632 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7633 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7634 at all, allowing it to be used at a lower level for accented character entry.");
7635   ns_alternate_modifier = Qmeta;
7637   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7638                "This variable describes the behavior of the right alternate or option key.\n\
7639 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7640 Set to left means be the same key as `ns-alternate-modifier'.\n\
7641 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7642 at all, allowing it to be used at a lower level for accented character entry.");
7643   ns_right_alternate_modifier = Qleft;
7645   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7646                "This variable describes the behavior of the command key.\n\
7647 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7648   ns_command_modifier = Qsuper;
7650   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7651                "This variable describes the behavior of the right command key.\n\
7652 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7653 Set to left means be the same key as `ns-command-modifier'.\n\
7654 Set to none means that the command / option key is not interpreted by Emacs\n\
7655 at all, allowing it to be used at a lower level for accented character entry.");
7656   ns_right_command_modifier = Qleft;
7658   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7659                "This variable describes the behavior of the control key.\n\
7660 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7661   ns_control_modifier = Qcontrol;
7663   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7664                "This variable describes the behavior of the right control key.\n\
7665 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7666 Set to left means be the same key as `ns-control-modifier'.\n\
7667 Set to none means that the control / option key is not interpreted by Emacs\n\
7668 at all, allowing it to be used at a lower level for accented character entry.");
7669   ns_right_control_modifier = Qleft;
7671   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7672                "This variable describes the behavior of the function key (on laptops).\n\
7673 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7674 Set to none means that the function key is not interpreted by Emacs at all,\n\
7675 allowing it to be used at a lower level for accented character entry.");
7676   ns_function_modifier = Qnone;
7678   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7679                "Non-nil (the default) means to render text antialiased.");
7680   ns_antialias_text = Qt;
7682   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7683                "Whether to confirm application quit using dialog.");
7684   ns_confirm_quit = Qnil;
7686   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7687                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7688 Only works on OSX 10.6 or later.  */);
7689   ns_auto_hide_menu_bar = Qnil;
7691   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7692      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7693 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7694 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7695 Default is t for OSX >= 10.7, nil otherwise.  */);
7696 #ifdef HAVE_NATIVE_FS
7697   ns_use_native_fullscreen = YES;
7698 #else
7699   ns_use_native_fullscreen = NO;
7700 #endif
7701   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7703   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
7704      doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
7705 Note that this does not apply to images.
7706 This variable is ignored on OSX < 10.7 and GNUstep.  */);
7707   ns_use_srgb_colorspace = YES;
7709   /* TODO: move to common code */
7710   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7711                doc: /* Which toolkit scroll bars Emacs uses, if any.
7712 A value of nil means Emacs doesn't use toolkit scroll bars.
7713 With the X Window system, the value is a symbol describing the
7714 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7715 With MS Windows or Nextstep, the value is t.  */);
7716   Vx_toolkit_scroll_bars = Qt;
7718   DEFVAR_BOOL ("x-use-underline-position-properties",
7719                x_use_underline_position_properties,
7720      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7721 A value of nil means ignore them.  If you encounter fonts with bogus
7722 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7723 to 4.1, set this to nil. */);
7724   x_use_underline_position_properties = 0;
7726   DEFVAR_BOOL ("x-underline-at-descent-line",
7727                x_underline_at_descent_line,
7728      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7729 A value of nil means to draw the underline according to the value of the
7730 variable `x-use-underline-position-properties', which is usually at the
7731 baseline level.  The default value is nil.  */);
7732   x_underline_at_descent_line = 0;
7734   /* Tell Emacs about this window system.  */
7735   Fprovide (Qns, Qnil);
7737   DEFSYM (Qcocoa, "cocoa");
7738   DEFSYM (Qgnustep, "gnustep");
7740   syms_of_nsfont ();
7741 #ifdef NS_IMPL_COCOA
7742   Fprovide (Qcocoa, Qnil);
7743 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
7744   syms_of_macfont ();
7745 #endif
7746 #else
7747   Fprovide (Qgnustep, Qnil);
7748 #endif