Auto-commit of loaddefs files.
[emacs.git] / src / nsterm.m
blob45c6214f0d09db78ea99408ee3f796afdcc9553c
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   /* Clear the mouse-moved flag for every frame on this display.  */
1906   FOR_EACH_FRAME (tail, frame)
1907     if (FRAME_NS_P (XFRAME (frame))
1908         && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1909       XFRAME (frame)->mouse_moved = 0;
1911   dpyinfo->last_mouse_scroll_bar = nil;
1912   if (dpyinfo->last_mouse_frame
1913       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
1914     f = dpyinfo->last_mouse_frame;
1915   else
1916     f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
1918   if (f && FRAME_NS_P (f))
1919     {
1920       view = FRAME_NS_VIEW (*fp);
1922       position = [[view window] mouseLocationOutsideOfEventStream];
1923       position = [view convertPoint: position fromView: nil];
1924       remember_mouse_glyph (f, position.x, position.y,
1925                             &dpyinfo->last_mouse_glyph);
1926 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1928       if (bar_window) *bar_window = Qnil;
1929       if (part) *part = 0; /*scroll_bar_handle; */
1931       if (x) XSETINT (*x, lrint (position.x));
1932       if (y) XSETINT (*y, lrint (position.y));
1933       if (time)
1934         *time = dpyinfo->last_mouse_movement_time;
1935       *fp = f;
1936     }
1938   unblock_input ();
1942 static void
1943 ns_frame_up_to_date (struct frame *f)
1944 /* --------------------------------------------------------------------------
1945     External (hook): Fix up mouse highlighting right after a full update.
1946     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1947    -------------------------------------------------------------------------- */
1949   NSTRACE (ns_frame_up_to_date);
1951   if (FRAME_NS_P (f))
1952     {
1953       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1954       if (f == hlinfo->mouse_face_mouse_frame)
1955         {
1956           block_input ();
1957           ns_update_begin(f);
1958           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1959                                 hlinfo->mouse_face_mouse_x,
1960                                 hlinfo->mouse_face_mouse_y);
1961           ns_update_end(f);
1962           unblock_input ();
1963         }
1964     }
1968 static void
1969 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1970 /* --------------------------------------------------------------------------
1971     External (RIF): set frame mouse pointer type.
1972    -------------------------------------------------------------------------- */
1974   NSTRACE (ns_define_frame_cursor);
1975   if (FRAME_POINTER_TYPE (f) != cursor)
1976     {
1977       EmacsView *view = FRAME_NS_VIEW (f);
1978       FRAME_POINTER_TYPE (f) = cursor;
1979       [[view window] invalidateCursorRectsForView: view];
1980       /* Redisplay assumes this function also draws the changed frame
1981          cursor, but this function doesn't, so do it explicitly.  */
1982       x_update_cursor (f, 1);
1983     }
1988 /* ==========================================================================
1990     Keyboard handling
1992    ========================================================================== */
1995 static unsigned
1996 ns_convert_key (unsigned code)
1997 /* --------------------------------------------------------------------------
1998     Internal call used by NSView-keyDown.
1999    -------------------------------------------------------------------------- */
2001   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
2002                                 / sizeof (convert_ns_to_X_keysym[0]));
2003   unsigned keysym;
2004   /* An array would be faster, but less easy to read. */
2005   for (keysym = 0; keysym < last_keysym; keysym += 2)
2006     if (code == convert_ns_to_X_keysym[keysym])
2007       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2008   return 0;
2009 /* if decide to use keyCode and Carbon table, use this line:
2010      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2014 char *
2015 x_get_keysym_name (int keysym)
2016 /* --------------------------------------------------------------------------
2017     Called by keyboard.c.  Not sure if the return val is important, except
2018     that it be unique.
2019    -------------------------------------------------------------------------- */
2021   static char value[16];
2022   NSTRACE (x_get_keysym_name);
2023   sprintf (value, "%d", keysym);
2024   return value;
2029 /* ==========================================================================
2031     Block drawing operations
2033    ========================================================================== */
2036 static void
2037 ns_redraw_scroll_bars (struct frame *f)
2039   int i;
2040   id view;
2041   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2042   NSTRACE (ns_redraw_scroll_bars);
2043   for (i =[subviews count]-1; i >= 0; i--)
2044     {
2045       view = [subviews objectAtIndex: i];
2046       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2047       [view display];
2048     }
2052 void
2053 ns_clear_frame (struct frame *f)
2054 /* --------------------------------------------------------------------------
2055       External (hook): Erase the entire frame
2056    -------------------------------------------------------------------------- */
2058   NSView *view = FRAME_NS_VIEW (f);
2059   NSRect r;
2061   NSTRACE (ns_clear_frame);
2063  /* comes on initial frame because we have
2064     after-make-frame-functions = select-frame */
2065  if (!FRAME_DEFAULT_FACE (f))
2066    return;
2068   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2070   r = [view bounds];
2072   block_input ();
2073   ns_focus (f, &r, 1);
2074   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2075   NSRectFill (r);
2076   ns_unfocus (f);
2078   /* as of 2006/11 or so this is now needed */
2079   ns_redraw_scroll_bars (f);
2080   unblock_input ();
2084 static void
2085 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2086 /* --------------------------------------------------------------------------
2087     External (RIF):  Clear section of frame
2088    -------------------------------------------------------------------------- */
2090   NSRect r = NSMakeRect (x, y, width, height);
2091   NSView *view = FRAME_NS_VIEW (f);
2092   struct face *face = FRAME_DEFAULT_FACE (f);
2094   if (!view || !face)
2095     return;
2097   NSTRACE (ns_clear_frame_area);
2099   r = NSIntersectionRect (r, [view frame]);
2100   ns_focus (f, &r, 1);
2101   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2103   NSRectFill (r);
2105   ns_unfocus (f);
2106   return;
2110 static void
2111 ns_scroll_run (struct window *w, struct run *run)
2112 /* --------------------------------------------------------------------------
2113     External (RIF):  Insert or delete n lines at line vpos
2114    -------------------------------------------------------------------------- */
2116   struct frame *f = XFRAME (w->frame);
2117   int x, y, width, height, from_y, to_y, bottom_y;
2119   NSTRACE (ns_scroll_run);
2121   /* begin copy from other terms */
2122   /* Get frame-relative bounding box of the text display area of W,
2123      without mode lines.  Include in this box the left and right
2124      fringe of W.  */
2125   window_box (w, ANY_AREA, &x, &y, &width, &height);
2127   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2128   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2129   bottom_y = y + height;
2131   if (to_y < from_y)
2132     {
2133       /* Scrolling up.  Make sure we don't copy part of the mode
2134          line at the bottom.  */
2135       if (from_y + run->height > bottom_y)
2136         height = bottom_y - from_y;
2137       else
2138         height = run->height;
2139     }
2140   else
2141     {
2142       /* Scrolling down.  Make sure we don't copy over the mode line.
2143          at the bottom.  */
2144       if (to_y + run->height > bottom_y)
2145         height = bottom_y - to_y;
2146       else
2147         height = run->height;
2148     }
2149   /* end copy from other terms */
2151   if (height == 0)
2152       return;
2154   block_input ();
2156   x_clear_cursor (w);
2158   {
2159     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2160     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2161     NSPoint dstOrigin = NSMakePoint (x, to_y);
2163     ns_focus (f, &dstRect, 1);
2164     NSCopyBits (0, srcRect , dstOrigin);
2165     ns_unfocus (f);
2166   }
2168   unblock_input ();
2172 static void
2173 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2174 /* --------------------------------------------------------------------------
2175     External (RIF): preparatory to fringe update after text was updated
2176    -------------------------------------------------------------------------- */
2178   struct frame *f;
2179   int width, height;
2181   NSTRACE (ns_after_update_window_line);
2183   /* begin copy from other terms */
2184   eassert (w);
2186   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2187     desired_row->redraw_fringe_bitmaps_p = 1;
2189   /* When a window has disappeared, make sure that no rest of
2190      full-width rows stays visible in the internal border.  */
2191   if (windows_or_buffers_changed
2192       && desired_row->full_width_p
2193       && (f = XFRAME (w->frame),
2194           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2195           width != 0)
2196       && (height = desired_row->visible_height,
2197           height > 0))
2198     {
2199       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2201       block_input ();
2202       ns_clear_frame_area (f, 0, y, width, height);
2203       ns_clear_frame_area (f,
2204                            FRAME_PIXEL_WIDTH (f) - width,
2205                            y, width, height);
2206       unblock_input ();
2207     }
2211 static void
2212 ns_shift_glyphs_for_insert (struct frame *f,
2213                            int x, int y, int width, int height,
2214                            int shift_by)
2215 /* --------------------------------------------------------------------------
2216     External (RIF): copy an area horizontally, don't worry about clearing src
2217    -------------------------------------------------------------------------- */
2219   NSRect srcRect = NSMakeRect (x, y, width, height);
2220   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2221   NSPoint dstOrigin = dstRect.origin;
2223   NSTRACE (ns_shift_glyphs_for_insert);
2225   ns_focus (f, &dstRect, 1);
2226   NSCopyBits (0, srcRect, dstOrigin);
2227   ns_unfocus (f);
2232 /* ==========================================================================
2234     Character encoding and metrics
2236    ========================================================================== */
2239 static void
2240 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2241 /* --------------------------------------------------------------------------
2242      External (RIF); compute left/right overhang of whole string and set in s
2243    -------------------------------------------------------------------------- */
2245   struct font *font = s->font;
2247   if (s->char2b)
2248     {
2249       struct font_metrics metrics;
2250       unsigned int codes[2];
2251       codes[0] = *(s->char2b);
2252       codes[1] = *(s->char2b + s->nchars - 1);
2254       font->driver->text_extents (font, codes, 2, &metrics);
2255       s->left_overhang = -metrics.lbearing;
2256       s->right_overhang
2257         = metrics.rbearing > metrics.width
2258         ? metrics.rbearing - metrics.width : 0;
2259     }
2260   else
2261     {
2262       s->left_overhang = 0;
2263       if (EQ (font->driver->type, Qns))
2264         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2265           FONT_HEIGHT (font) * 0.2 : 0;
2266       else
2267         s->right_overhang = 0;
2268     }
2273 /* ==========================================================================
2275     Fringe and cursor drawing
2277    ========================================================================== */
2280 extern int max_used_fringe_bitmap;
2281 static void
2282 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2283                       struct draw_fringe_bitmap_params *p)
2284 /* --------------------------------------------------------------------------
2285     External (RIF); fringe-related
2286    -------------------------------------------------------------------------- */
2288   struct frame *f = XFRAME (WINDOW_FRAME (w));
2289   struct face *face = p->face;
2290   static EmacsImage **bimgs = NULL;
2291   static int nBimgs = 0;
2293   /* grow bimgs if needed */
2294   if (nBimgs < max_used_fringe_bitmap)
2295     {
2296       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2297       memset (bimgs + nBimgs, 0,
2298               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2299       nBimgs = max_used_fringe_bitmap;
2300     }
2302   /* Must clip because of partially visible lines.  */
2303   ns_clip_to_row (w, row, ANY_AREA, YES);
2305   if (!p->overlay_p)
2306     {
2307       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2309       /* If the fringe is adjacent to the left (right) scroll bar of a
2310          leftmost (rightmost, respectively) window, then extend its
2311          background to the gap between the fringe and the bar.  */
2312       if ((WINDOW_LEFTMOST_P (w)
2313            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2314           || (WINDOW_RIGHTMOST_P (w)
2315               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2316         {
2317           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2319           if (sb_width > 0)
2320             {
2321               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2322               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2323                                     * FRAME_COLUMN_WIDTH (f));
2325               if (bx < 0)
2326                 {
2327                   /* Bitmap fills the fringe.  */
2328                   if (bar_area_x + bar_area_width == p->x)
2329                     bx = bar_area_x + sb_width;
2330                   else if (p->x + p->wd == bar_area_x)
2331                     bx = bar_area_x;
2332                   if (bx >= 0)
2333                     {
2334                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2336                       nx = bar_area_width - sb_width;
2337                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2338                                                             row->y));
2339                       ny = row->visible_height;
2340                     }
2341                 }
2342               else
2343                 {
2344                   if (bar_area_x + bar_area_width == bx)
2345                     {
2346                       bx = bar_area_x + sb_width;
2347                       nx += bar_area_width - sb_width;
2348                     }
2349                   else if (bx + nx == bar_area_x)
2350                     nx += bar_area_width - sb_width;
2351                 }
2352             }
2353         }
2355       if (bx >= 0 && nx > 0)
2356         {
2357           NSRect r = NSMakeRect (bx, by, nx, ny);
2358           NSRectClip (r);
2359           [ns_lookup_indexed_color (face->background, f) set];
2360           NSRectFill (r);
2361         }
2362     }
2364   if (p->which)
2365     {
2366       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2367       EmacsImage *img = bimgs[p->which - 1];
2369       if (!img)
2370         {
2371           unsigned short *bits = p->bits + p->dh;
2372           int len = p->h;
2373           int i;
2374           unsigned char *cbits = xmalloc (len);
2376           for (i = 0; i < len; i++)
2377             cbits[i] = ~(bits[i] & 0xff);
2378           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2379                                            flip: NO];
2380           bimgs[p->which - 1] = img;
2381           xfree (cbits);
2382         }
2384       NSRectClip (r);
2385       /* Since we composite the bitmap instead of just blitting it, we need
2386          to erase the whole background. */
2387       [ns_lookup_indexed_color(face->background, f) set];
2388       NSRectFill (r);
2389       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2390 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2391       [img drawInRect: r
2392               fromRect: NSZeroRect
2393              operation: NSCompositeSourceOver
2394               fraction: 1.0
2395            respectFlipped: YES
2396                 hints: nil];
2397 #else
2398       {
2399         NSPoint pt = r.origin;
2400         pt.y += p->h;
2401         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2402       }
2403 #endif
2404     }
2405   ns_unfocus (f);
2409 static void
2410 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2411                        int x, int y, enum text_cursor_kinds cursor_type,
2412                        int cursor_width, bool on_p, bool active_p)
2413 /* --------------------------------------------------------------------------
2414      External call (RIF): draw cursor.
2415      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2416    -------------------------------------------------------------------------- */
2418   NSRect r, s;
2419   int fx, fy, h, cursor_height;
2420   struct frame *f = WINDOW_XFRAME (w);
2421   struct glyph *phys_cursor_glyph;
2422   struct glyph *cursor_glyph;
2423   struct face *face;
2424   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2426   /* If cursor is out of bounds, don't draw garbage.  This can happen
2427      in mini-buffer windows when switching between echo area glyphs
2428      and mini-buffer.  */
2430   NSTRACE (dumpcursor);
2432   if (!on_p)
2433     return;
2435   w->phys_cursor_type = cursor_type;
2436   w->phys_cursor_on_p = on_p;
2438   if (cursor_type == NO_CURSOR)
2439     {
2440       w->phys_cursor_width = 0;
2441       return;
2442     }
2444   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2445     {
2446       if (glyph_row->exact_window_width_line_p
2447           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2448         {
2449           glyph_row->cursor_in_fringe_p = 1;
2450           draw_fringe_bitmap (w, glyph_row, 0);
2451         }
2452       return;
2453     }
2455   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2456      (other terminals do it the other way round).  We must set
2457      w->phys_cursor_width to the cursor width.  For bar cursors, that
2458      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2459   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2461   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2462      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2463   if (cursor_type == BAR_CURSOR)
2464     {
2465       if (cursor_width < 1)
2466         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2467       w->phys_cursor_width = cursor_width;
2468     }
2469   /* If we have an HBAR, "cursor_width" MAY specify height. */
2470   else if (cursor_type == HBAR_CURSOR)
2471     {
2472       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2473       fy += h - cursor_height;
2474       h = cursor_height;
2475     }
2477   r.origin.x = fx, r.origin.y = fy;
2478   r.size.height = h;
2479   r.size.width = w->phys_cursor_width;
2481   /* TODO: only needed in rare cases with last-resort font in HELLO..
2482      should we do this more efficiently? */
2483   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2486   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2487   if (face && NS_FACE_BACKGROUND (face)
2488       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2489     {
2490       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2491       hollow_color = FRAME_CURSOR_COLOR (f);
2492     }
2493   else
2494     [FRAME_CURSOR_COLOR (f) set];
2496 #ifdef NS_IMPL_COCOA
2497   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2498            atomic.  Cleaner ways of doing this should be investigated.
2499            One way would be to set a global variable DRAWING_CURSOR
2500            when making the call to draw_phys..(), don't focus in that
2501            case, then move the ns_unfocus() here after that call. */
2502   NSDisableScreenUpdates ();
2503 #endif
2505   switch (cursor_type)
2506     {
2507     case NO_CURSOR:
2508       break;
2509     case FILLED_BOX_CURSOR:
2510       NSRectFill (r);
2511       break;
2512     case HOLLOW_BOX_CURSOR:
2513       NSRectFill (r);
2514       [hollow_color set];
2515       NSRectFill (NSInsetRect (r, 1, 1));
2516       [FRAME_CURSOR_COLOR (f) set];
2517       break;
2518     case HBAR_CURSOR:
2519       NSRectFill (r);
2520       break;
2521     case BAR_CURSOR:
2522       s = r;
2523       /* If the character under cursor is R2L, draw the bar cursor
2524          on the right of its glyph, rather than on the left.  */
2525       cursor_glyph = get_phys_cursor_glyph (w);
2526       if ((cursor_glyph->resolved_level & 1) != 0)
2527         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2529       NSRectFill (s);
2530       break;
2531     }
2532   ns_unfocus (f);
2534   /* draw the character under the cursor */
2535   if (cursor_type != NO_CURSOR)
2536     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2538 #ifdef NS_IMPL_COCOA
2539   NSEnableScreenUpdates ();
2540 #endif
2545 static void
2546 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2547 /* --------------------------------------------------------------------------
2548      External (RIF): Draw a vertical line.
2549    -------------------------------------------------------------------------- */
2551   struct frame *f = XFRAME (WINDOW_FRAME (w));
2552   struct face *face;
2553   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2555   NSTRACE (ns_draw_vertical_window_border);
2557   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2558   if (face)
2559       [ns_lookup_indexed_color(face->foreground, f) set];
2561   ns_focus (f, &r, 1);
2562   NSRectFill(r);
2563   ns_unfocus (f);
2567 static void
2568 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2569 /* --------------------------------------------------------------------------
2570      External (RIF): Draw a window divider.
2571    -------------------------------------------------------------------------- */
2573   struct frame *f = XFRAME (WINDOW_FRAME (w));
2574   struct face *face;
2575   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2577   NSTRACE (ns_draw_window_divider);
2579   face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2580   if (face)
2581       [ns_lookup_indexed_color(face->foreground, f) set];
2583   ns_focus (f, &r, 1);
2584   NSRectFill(r);
2585   ns_unfocus (f);
2589 void
2590 show_hourglass (struct atimer *timer)
2592   if (hourglass_shown_p)
2593     return;
2595   block_input ();
2597   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2599   hourglass_shown_p = 1;
2600   unblock_input ();
2604 void
2605 hide_hourglass (void)
2607   if (!hourglass_shown_p)
2608     return;
2610   block_input ();
2612   /* TODO: remove NSProgressIndicator from all frames */
2614   hourglass_shown_p = 0;
2615   unblock_input ();
2620 /* ==========================================================================
2622     Glyph drawing operations
2624    ========================================================================== */
2626 static int
2627 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2628 /* --------------------------------------------------------------------------
2629     Wrapper utility to account for internal border width on full-width lines,
2630     and allow top full-width rows to hit the frame top.  nr should be pointer
2631     to two successive NSRects.  Number of rects actually used is returned.
2632    -------------------------------------------------------------------------- */
2634   int n = get_glyph_string_clip_rects (s, nr, 2);
2635   return n;
2638 /* --------------------------------------------------------------------
2639    Draw a wavy line under glyph string s. The wave fills wave_height
2640    pixels from y.
2642                     x          wave_length = 2
2643                                  --
2644                 y    *   *   *   *   *
2645                      |* * * * * * * * *
2646     wave_height = 3  | *   *   *   *
2647   --------------------------------------------------------------------- */
2649 static void
2650 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2652   int wave_height = 3, wave_length = 2;
2653   int y, dx, dy, odd, xmax;
2654   NSPoint a, b;
2655   NSRect waveClip;
2657   dx = wave_length;
2658   dy = wave_height - 1;
2659   y =  s->ybase - wave_height + 3;
2660   xmax = x + width;
2662   /* Find and set clipping rectangle */
2663   waveClip = NSMakeRect (x, y, width, wave_height);
2664   [[NSGraphicsContext currentContext] saveGraphicsState];
2665   NSRectClip (waveClip);
2667   /* Draw the waves */
2668   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2669   b.x = a.x + dx;
2670   odd = (int)(a.x/dx) % 2;
2671   a.y = b.y = y + 0.5;
2673   if (odd)
2674     a.y += dy;
2675   else
2676     b.y += dy;
2678   while (a.x <= xmax)
2679     {
2680       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2681       a.x = b.x, a.y = b.y;
2682       b.x += dx, b.y = y + 0.5 + odd*dy;
2683       odd = !odd;
2684     }
2686   /* Restore previous clipping rectangle(s) */
2687   [[NSGraphicsContext currentContext] restoreGraphicsState];
2692 void
2693 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2694                          NSColor *defaultCol, CGFloat width, CGFloat x)
2695 /* --------------------------------------------------------------------------
2696    Draw underline, overline, and strike-through on glyph string s.
2697    -------------------------------------------------------------------------- */
2699   if (s->for_overlaps)
2700     return;
2702   /* Do underline. */
2703   if (face->underline_p)
2704     {
2705       if (s->face->underline_type == FACE_UNDER_WAVE)
2706         {
2707           if (face->underline_defaulted_p)
2708             [defaultCol set];
2709           else
2710             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2712           ns_draw_underwave (s, width, x);
2713         }
2714       else if (s->face->underline_type == FACE_UNDER_LINE)
2715         {
2717           NSRect r;
2718           unsigned long thickness, position;
2720           /* If the prev was underlined, match its appearance. */
2721           if (s->prev && s->prev->face->underline_p
2722               && s->prev->face->underline_type == FACE_UNDER_LINE
2723               && s->prev->underline_thickness > 0)
2724             {
2725               thickness = s->prev->underline_thickness;
2726               position = s->prev->underline_position;
2727             }
2728           else
2729             {
2730               struct font *font;
2731               unsigned long descent;
2733               font=s->font;
2734               descent = s->y + s->height - s->ybase;
2736               /* Use underline thickness of font, defaulting to 1. */
2737               thickness = (font && font->underline_thickness > 0)
2738                 ? font->underline_thickness : 1;
2740               /* Determine the offset of underlining from the baseline. */
2741               if (x_underline_at_descent_line)
2742                 position = descent - thickness;
2743               else if (x_use_underline_position_properties
2744                        && font && font->underline_position >= 0)
2745                 position = font->underline_position;
2746               else if (font)
2747                 position = lround (font->descent / 2);
2748               else
2749                 position = underline_minimum_offset;
2751               position = max (position, underline_minimum_offset);
2753               /* Ensure underlining is not cropped. */
2754               if (descent <= position)
2755                 {
2756                   position = descent - 1;
2757                   thickness = 1;
2758                 }
2759               else if (descent < position + thickness)
2760                 thickness = 1;
2761             }
2763           s->underline_thickness = thickness;
2764           s->underline_position = position;
2766           r = NSMakeRect (x, s->ybase + position, width, thickness);
2768           if (face->underline_defaulted_p)
2769             [defaultCol set];
2770           else
2771             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2772           NSRectFill (r);
2773         }
2774     }
2775   /* Do overline. We follow other terms in using a thickness of 1
2776      and ignoring overline_margin. */
2777   if (face->overline_p)
2778     {
2779       NSRect r;
2780       r = NSMakeRect (x, s->y, width, 1);
2782       if (face->overline_color_defaulted_p)
2783         [defaultCol set];
2784       else
2785         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2786       NSRectFill (r);
2787     }
2789   /* Do strike-through.  We follow other terms for thickness and
2790      vertical position.*/
2791   if (face->strike_through_p)
2792     {
2793       NSRect r;
2794       unsigned long dy;
2796       dy = lrint ((s->height - 1) / 2);
2797       r = NSMakeRect (x, s->y + dy, width, 1);
2799       if (face->strike_through_color_defaulted_p)
2800         [defaultCol set];
2801       else
2802         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2803       NSRectFill (r);
2804     }
2807 static void
2808 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2809              char left_p, char right_p)
2810 /* --------------------------------------------------------------------------
2811     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2812     Note we can't just use an NSDrawRect command, because of the possibility
2813     of some sides not being drawn, and because the rect will be filled.
2814    -------------------------------------------------------------------------- */
2816   NSRect s = r;
2817   [col set];
2819   /* top, bottom */
2820   s.size.height = thickness;
2821   NSRectFill (s);
2822   s.origin.y += r.size.height - thickness;
2823   NSRectFill (s);
2825   s.size.height = r.size.height;
2826   s.origin.y = r.origin.y;
2828   /* left, right (optional) */
2829   s.size.width = thickness;
2830   if (left_p)
2831     NSRectFill (s);
2832   if (right_p)
2833     {
2834       s.origin.x += r.size.width - thickness;
2835       NSRectFill (s);
2836     }
2840 static void
2841 ns_draw_relief (NSRect r, int thickness, char raised_p,
2842                char top_p, char bottom_p, char left_p, char right_p,
2843                struct glyph_string *s)
2844 /* --------------------------------------------------------------------------
2845     Draw a relief rect inside r, optionally leaving some sides open.
2846     Note we can't just use an NSDrawBezel command, because of the possibility
2847     of some sides not being drawn, and because the rect will be filled.
2848    -------------------------------------------------------------------------- */
2850   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2851   NSColor *newBaseCol = nil;
2852   NSRect sr = r;
2854   NSTRACE (ns_draw_relief);
2856   /* set up colors */
2858   if (s->face->use_box_color_for_shadows_p)
2859     {
2860       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2861     }
2862 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2863            && s->img->pixmap
2864            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2865        {
2866          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2867        } */
2868   else
2869     {
2870       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2871     }
2873   if (newBaseCol == nil)
2874     newBaseCol = [NSColor grayColor];
2876   if (newBaseCol != baseCol)  /* TODO: better check */
2877     {
2878       [baseCol release];
2879       baseCol = [newBaseCol retain];
2880       [lightCol release];
2881       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2882       [darkCol release];
2883       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2884     }
2886   [(raised_p ? lightCol : darkCol) set];
2888   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2890   /* top */
2891   sr.size.height = thickness;
2892   if (top_p) NSRectFill (sr);
2894   /* left */
2895   sr.size.height = r.size.height;
2896   sr.size.width = thickness;
2897   if (left_p) NSRectFill (sr);
2899   [(raised_p ? darkCol : lightCol) set];
2901   /* bottom */
2902   sr.size.width = r.size.width;
2903   sr.size.height = thickness;
2904   sr.origin.y += r.size.height - thickness;
2905   if (bottom_p) NSRectFill (sr);
2907   /* right */
2908   sr.size.height = r.size.height;
2909   sr.origin.y = r.origin.y;
2910   sr.size.width = thickness;
2911   sr.origin.x += r.size.width - thickness;
2912   if (right_p) NSRectFill (sr);
2916 static void
2917 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2918 /* --------------------------------------------------------------------------
2919       Function modeled after x_draw_glyph_string_box ().
2920       Sets up parameters for drawing.
2921    -------------------------------------------------------------------------- */
2923   int right_x, last_x;
2924   char left_p, right_p;
2925   struct glyph *last_glyph;
2926   NSRect r;
2927   int thickness;
2928   struct face *face;
2930   if (s->hl == DRAW_MOUSE_FACE)
2931     {
2932       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2933       if (!face)
2934         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2935     }
2936   else
2937     face = s->face;
2939   thickness = face->box_line_width;
2941   NSTRACE (ns_dumpglyphs_box_or_relief);
2943   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2944             ? WINDOW_RIGHT_EDGE_X (s->w)
2945             : window_box_right (s->w, s->area));
2946   last_glyph = (s->cmp || s->img
2947                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2949   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2950               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2952   left_p = (s->first_glyph->left_box_line_p
2953             || (s->hl == DRAW_MOUSE_FACE
2954                 && (s->prev == NULL || s->prev->hl != s->hl)));
2955   right_p = (last_glyph->right_box_line_p
2956              || (s->hl == DRAW_MOUSE_FACE
2957                  && (s->next == NULL || s->next->hl != s->hl)));
2959   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2961   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2962   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2963     {
2964       ns_draw_box (r, abs (thickness),
2965                    ns_lookup_indexed_color (face->box_color, s->f),
2966                   left_p, right_p);
2967     }
2968   else
2969     {
2970       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2971                      1, 1, left_p, right_p, s);
2972     }
2976 static void
2977 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2978 /* --------------------------------------------------------------------------
2979       Modeled after x_draw_glyph_string_background, which draws BG in
2980       certain cases.  Others are left to the text rendering routine.
2981    -------------------------------------------------------------------------- */
2983   NSTRACE (ns_maybe_dumpglyphs_background);
2985   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2986     {
2987       int box_line_width = max (s->face->box_line_width, 0);
2988       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2989           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2990         {
2991           struct face *face;
2992           if (s->hl == DRAW_MOUSE_FACE)
2993             {
2994               face = FACE_FROM_ID (s->f,
2995                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2996               if (!face)
2997                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2998             }
2999           else
3000             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3001           if (!face->stipple)
3002             [(NS_FACE_BACKGROUND (face) != 0
3003               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3004               : FRAME_BACKGROUND_COLOR (s->f)) set];
3005           else
3006             {
3007               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3008               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3009             }
3011           if (s->hl != DRAW_CURSOR)
3012             {
3013               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3014                                     s->background_width,
3015                                     s->height-2*box_line_width);
3016               NSRectFill (r);
3017             }
3019           s->background_filled_p = 1;
3020         }
3021     }
3025 static void
3026 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3027 /* --------------------------------------------------------------------------
3028       Renders an image and associated borders.
3029    -------------------------------------------------------------------------- */
3031   EmacsImage *img = s->img->pixmap;
3032   int box_line_vwidth = max (s->face->box_line_width, 0);
3033   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3034   int bg_x, bg_y, bg_height;
3035   int th;
3036   char raised_p;
3037   NSRect br;
3038   struct face *face;
3039   NSColor *tdCol;
3041   NSTRACE (ns_dumpglyphs_image);
3043   if (s->face->box != FACE_NO_BOX
3044       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3045     x += abs (s->face->box_line_width);
3047   bg_x = x;
3048   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3049   bg_height = s->height;
3050   /* other terms have this, but was causing problems w/tabbar mode */
3051   /* - 2 * box_line_vwidth; */
3053   if (s->slice.x == 0) x += s->img->hmargin;
3054   if (s->slice.y == 0) y += s->img->vmargin;
3056   /* Draw BG: if we need larger area than image itself cleared, do that,
3057      otherwise, since we composite the image under NS (instead of mucking
3058      with its background color), we must clear just the image area. */
3059   if (s->hl == DRAW_MOUSE_FACE)
3060     {
3061       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3062       if (!face)
3063        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3064     }
3065   else
3066     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3068   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3070   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3071       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3072     {
3073       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3074       s->background_filled_p = 1;
3075     }
3076   else
3077     {
3078       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3079     }
3081   NSRectFill (br);
3083   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3084   if (img != nil)
3085     {
3086 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
3087       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3088       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3089                               s->slice.width, s->slice.height);
3090       [img drawInRect: dr
3091              fromRect: ir
3092              operation: NSCompositeSourceOver
3093               fraction: 1.0
3094            respectFlipped: YES
3095                 hints: nil];
3096 #else
3097       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3098                   operation: NSCompositeSourceOver];
3099 #endif
3100     }
3102   if (s->hl == DRAW_CURSOR)
3103     {
3104     [FRAME_CURSOR_COLOR (s->f) set];
3105     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3106       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3107     else
3108       /* Currently on NS img->mask is always 0. Since
3109          get_window_cursor_type specifies a hollow box cursor when on
3110          a non-masked image we never reach this clause. But we put it
3111          in in anticipation of better support for image masks on
3112          NS. */
3113       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3114     }
3115   else
3116     {
3117       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3118     }
3120   /* Draw underline, overline, strike-through. */
3121   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3123   /* Draw relief, if requested */
3124   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3125     {
3126       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3127         {
3128           th = tool_bar_button_relief >= 0 ?
3129             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3130           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3131         }
3132       else
3133         {
3134           th = abs (s->img->relief);
3135           raised_p = (s->img->relief > 0);
3136         }
3138       r.origin.x = x - th;
3139       r.origin.y = y - th;
3140       r.size.width = s->slice.width + 2*th-1;
3141       r.size.height = s->slice.height + 2*th-1;
3142       ns_draw_relief (r, th, raised_p,
3143                       s->slice.y == 0,
3144                       s->slice.y + s->slice.height == s->img->height,
3145                       s->slice.x == 0,
3146                       s->slice.x + s->slice.width == s->img->width, s);
3147     }
3149   /* If there is no mask, the background won't be seen,
3150      so draw a rectangle on the image for the cursor.
3151      Do this for all images, getting transparency right is not reliable.  */
3152   if (s->hl == DRAW_CURSOR)
3153     {
3154       int thickness = abs (s->img->relief);
3155       if (thickness == 0) thickness = 1;
3156       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3157     }
3161 static void
3162 ns_dumpglyphs_stretch (struct glyph_string *s)
3164   NSRect r[2];
3165   int n, i;
3166   struct face *face;
3167   NSColor *fgCol, *bgCol;
3169   if (!s->background_filled_p)
3170     {
3171       n = ns_get_glyph_string_clip_rect (s, r);
3172       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3174       ns_focus (s->f, r, n);
3176       if (s->hl == DRAW_MOUSE_FACE)
3177        {
3178          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3179          if (!face)
3180            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3181        }
3182       else
3183        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3185       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3186       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3188       for (i = 0; i < n; ++i)
3189         {
3190           if (!s->row->full_width_p)
3191             {
3192               int overrun, leftoverrun;
3194               /* truncate to avoid overwriting fringe and/or scrollbar */
3195               overrun = max (0, (s->x + s->background_width)
3196                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3197                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3198               r[i].size.width -= overrun;
3200               /* truncate to avoid overwriting to left of the window box */
3201               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3202                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3204               if (leftoverrun > 0)
3205                 {
3206                   r[i].origin.x += leftoverrun;
3207                   r[i].size.width -= leftoverrun;
3208                 }
3210               /* XXX: Try to work between problem where a stretch glyph on
3211                  a partially-visible bottom row will clear part of the
3212                  modeline, and another where list-buffers headers and similar
3213                  rows erroneously have visible_height set to 0.  Not sure
3214                  where this is coming from as other terms seem not to show. */
3215               r[i].size.height = min (s->height, s->row->visible_height);
3216             }
3218           [bgCol set];
3220           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3221              overwriting cursor (usually when cursor on a tab) */
3222           if (s->hl == DRAW_CURSOR)
3223             {
3224               CGFloat x, width;
3226               x = r[i].origin.x;
3227               width = s->w->phys_cursor_width;
3228               r[i].size.width -= width;
3229               r[i].origin.x += width;
3231               NSRectFill (r[i]);
3233               /* Draw overlining, etc. on the cursor. */
3234               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3235                 ns_draw_text_decoration (s, face, bgCol, width, x);
3236               else
3237                 ns_draw_text_decoration (s, face, fgCol, width, x);
3238             }
3239           else
3240             {
3241               NSRectFill (r[i]);
3242             }
3244           /* Draw overlining, etc. on the stretch glyph (or the part
3245              of the stretch glyph after the cursor). */
3246           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3247                                    r[i].origin.x);
3248         }
3249       ns_unfocus (s->f);
3250       s->background_filled_p = 1;
3251     }
3255 static void
3256 ns_draw_glyph_string (struct glyph_string *s)
3257 /* --------------------------------------------------------------------------
3258       External (RIF): Main draw-text call.
3259    -------------------------------------------------------------------------- */
3261   /* TODO (optimize): focus for box and contents draw */
3262   NSRect r[2];
3263   int n, flags;
3264   char box_drawn_p = 0;
3265   struct font *font = s->face->font;
3266   if (! font) font = FRAME_FONT (s->f);
3268   NSTRACE (ns_draw_glyph_string);
3270   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3271     {
3272       int width;
3273       struct glyph_string *next;
3275       for (width = 0, next = s->next;
3276            next && width < s->right_overhang;
3277            width += next->width, next = next->next)
3278         if (next->first_glyph->type != IMAGE_GLYPH)
3279           {
3280             if (next->first_glyph->type != STRETCH_GLYPH)
3281               {
3282                 n = ns_get_glyph_string_clip_rect (s->next, r);
3283                 ns_focus (s->f, r, n);
3284                 ns_maybe_dumpglyphs_background (s->next, 1);
3285                 ns_unfocus (s->f);
3286               }
3287             else
3288               {
3289                 ns_dumpglyphs_stretch (s->next);
3290               }
3291             next->num_clips = 0;
3292           }
3293     }
3295   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3296         && (s->first_glyph->type == CHAR_GLYPH
3297             || s->first_glyph->type == COMPOSITE_GLYPH))
3298     {
3299       n = ns_get_glyph_string_clip_rect (s, r);
3300       ns_focus (s->f, r, n);
3301       ns_maybe_dumpglyphs_background (s, 1);
3302       ns_dumpglyphs_box_or_relief (s);
3303       ns_unfocus (s->f);
3304       box_drawn_p = 1;
3305     }
3307   switch (s->first_glyph->type)
3308     {
3310     case IMAGE_GLYPH:
3311       n = ns_get_glyph_string_clip_rect (s, r);
3312       ns_focus (s->f, r, n);
3313       ns_dumpglyphs_image (s, r[0]);
3314       ns_unfocus (s->f);
3315       break;
3317     case STRETCH_GLYPH:
3318       ns_dumpglyphs_stretch (s);
3319       break;
3321     case CHAR_GLYPH:
3322     case COMPOSITE_GLYPH:
3323       n = ns_get_glyph_string_clip_rect (s, r);
3324       ns_focus (s->f, r, n);
3326       if (s->for_overlaps || (s->cmp_from > 0
3327                               && ! s->first_glyph->u.cmp.automatic))
3328         s->background_filled_p = 1;
3329       else
3330         ns_maybe_dumpglyphs_background
3331           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3333       flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3334         (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3335          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3336           NS_DUMPGLYPH_NORMAL));
3338       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3339         {
3340           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3341           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3342           NS_FACE_FOREGROUND (s->face) = tmp;
3343         }
3345       font->driver->draw
3346         (s, 0, s->nchars, s->x, s->y,
3347          (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3348          || flags == NS_DUMPGLYPH_MOUSEFACE);
3350       {
3351         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3352                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3353                                                    s->f)
3354                         : FRAME_FOREGROUND_COLOR (s->f));
3355         [col set];
3357         /* Draw underline, overline, strike-through. */
3358         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3359       }
3361       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3362         {
3363           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3364           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3365           NS_FACE_FOREGROUND (s->face) = tmp;
3366         }
3368       ns_unfocus (s->f);
3369       break;
3371     case GLYPHLESS_GLYPH:
3372       n = ns_get_glyph_string_clip_rect (s, r);
3373       ns_focus (s->f, r, n);
3375       if (s->for_overlaps || (s->cmp_from > 0
3376                               && ! s->first_glyph->u.cmp.automatic))
3377         s->background_filled_p = 1;
3378       else
3379         ns_maybe_dumpglyphs_background
3380           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3381       /* ... */
3382       /* Not yet implemented.  */
3383       /* ... */
3384       ns_unfocus (s->f);
3385       break;
3387     default:
3388       emacs_abort ();
3389     }
3391   /* Draw box if not done already. */
3392   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3393     {
3394       n = ns_get_glyph_string_clip_rect (s, r);
3395       ns_focus (s->f, r, n);
3396       ns_dumpglyphs_box_or_relief (s);
3397       ns_unfocus (s->f);
3398     }
3400   s->num_clips = 0;
3405 /* ==========================================================================
3407     Event loop
3409    ========================================================================== */
3412 static void
3413 ns_send_appdefined (int value)
3414 /* --------------------------------------------------------------------------
3415     Internal: post an appdefined event which EmacsApp-sendEvent will
3416               recognize and take as a command to halt the event loop.
3417    -------------------------------------------------------------------------- */
3419   /*NSTRACE (ns_send_appdefined); */
3421 #ifdef NS_IMPL_GNUSTEP
3422   // GNUstep needs postEvent to happen on the main thread.
3423   if (! [[NSThread currentThread] isMainThread])
3424     {
3425       EmacsApp *app = (EmacsApp *)NSApp;
3426       app->nextappdefined = value;
3427       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3428                             withObject:nil
3429                          waitUntilDone:YES];
3430       return;
3431     }
3432 #endif
3434   /* Only post this event if we haven't already posted one.  This will end
3435        the [NXApp run] main loop after having processed all events queued at
3436        this moment.  */
3437   if (send_appdefined)
3438     {
3439       NSEvent *nxev;
3441       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3442       send_appdefined = NO;
3444       /* Don't need wakeup timer any more */
3445       if (timed_entry)
3446         {
3447           [timed_entry invalidate];
3448           [timed_entry release];
3449           timed_entry = nil;
3450         }
3452       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3453                                 location: NSMakePoint (0, 0)
3454                            modifierFlags: 0
3455                                timestamp: 0
3456                             windowNumber: [[NSApp mainWindow] windowNumber]
3457                                  context: [NSApp context]
3458                                  subtype: 0
3459                                    data1: value
3460                                    data2: 0];
3462       /* Post an application defined event on the event queue.  When this is
3463          received the [NXApp run] will return, thus having processed all
3464          events which are currently queued.  */
3465       [NSApp postEvent: nxev atStart: NO];
3466     }
3469 #ifdef HAVE_NATIVE_FS
3470 static void
3471 check_native_fs ()
3473   Lisp_Object frame, tail;
3475   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3476     return;
3478   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3480   FOR_EACH_FRAME (tail, frame)
3481     {
3482       struct frame *f = XFRAME (frame);
3483       if (FRAME_NS_P (f))
3484         {
3485           EmacsView *view = FRAME_NS_VIEW (f);
3486           [view updateCollectionBehavior];
3487         }
3488     }
3490 #endif
3492 /* GNUstep and OSX <= 10.4 does not have cancelTracking.  */
3493 #if defined (NS_IMPL_COCOA) && \
3494   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
3495 /* Check if menu open should be canceled or continued as normal.  */
3496 void
3497 ns_check_menu_open (NSMenu *menu)
3499   /* Click in menu bar? */
3500   NSArray *a = [[NSApp mainMenu] itemArray];
3501   int i;
3502   BOOL found = NO;
3504   if (menu == nil) // Menu tracking ended.
3505     {
3506       if (menu_will_open_state == MENU_OPENING)
3507         menu_will_open_state = MENU_NONE;
3508       return;
3509     }
3511   for (i = 0; ! found && i < [a count]; i++)
3512     found = menu == [[a objectAtIndex:i] submenu];
3513   if (found)
3514     {
3515       if (menu_will_open_state == MENU_NONE && emacs_event)
3516         {
3517           NSEvent *theEvent = [NSApp currentEvent];
3518           struct frame *emacsframe = SELECTED_FRAME ();
3520           [menu cancelTracking];
3521           menu_will_open_state = MENU_PENDING;
3522           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3523           EV_TRAILER (theEvent);
3525           CGEventRef ourEvent = CGEventCreate (NULL);
3526           menu_mouse_point = CGEventGetLocation (ourEvent);
3527           CFRelease (ourEvent);
3528         }
3529       else if (menu_will_open_state == MENU_OPENING)
3530         {
3531           menu_will_open_state = MENU_NONE;
3532         }
3533     }
3536 /* Redo saved menu click if state is MENU_PENDING.  */
3537 void
3538 ns_check_pending_open_menu ()
3540   if (menu_will_open_state == MENU_PENDING)
3541     {
3542       CGEventSourceRef source
3543         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3545       CGEventRef event = CGEventCreateMouseEvent (source,
3546                                                   kCGEventLeftMouseDown,
3547                                                   menu_mouse_point,
3548                                                   kCGMouseButtonLeft);
3549       CGEventSetType (event, kCGEventLeftMouseDown);
3550       CGEventPost (kCGHIDEventTap, event);
3551       CFRelease (event);
3552       CFRelease (source);
3554       menu_will_open_state = MENU_OPENING;
3555     }
3557 #endif /* NS_IMPL_COCOA) && >= MAC_OS_X_VERSION_10_5 */
3559 static int
3560 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3561 /* --------------------------------------------------------------------------
3562      External (hook): Post an event to ourself and keep reading events until
3563      we read it back again.  In effect process all events which were waiting.
3564      From 21+ we have to manage the event buffer ourselves.
3565    -------------------------------------------------------------------------- */
3567   struct input_event ev;
3568   int nevents;
3570 /* NSTRACE (ns_read_socket); */
3572 #ifdef HAVE_NATIVE_FS
3573   check_native_fs ();
3574 #endif
3576   if ([NSApp modalWindow] != nil)
3577     return -1;
3579   if (hold_event_q.nr > 0)
3580     {
3581       int i;
3582       for (i = 0; i < hold_event_q.nr; ++i)
3583         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3584       hold_event_q.nr = 0;
3585       return i;
3586     }
3588   block_input ();
3589   n_emacs_events_pending = 0;
3590   EVENT_INIT (ev);
3591   emacs_event = &ev;
3592   q_event_ptr = hold_quit;
3594   /* we manage autorelease pools by allocate/reallocate each time around
3595      the loop; strict nesting is occasionally violated but seems not to
3596      matter.. earlier methods using full nesting caused major memory leaks */
3597   [outerpool release];
3598   outerpool = [[NSAutoreleasePool alloc] init];
3600   /* If have pending open-file requests, attend to the next one of those. */
3601   if (ns_pending_files && [ns_pending_files count] != 0
3602       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3603     {
3604       [ns_pending_files removeObjectAtIndex: 0];
3605     }
3606   /* Deal with pending service requests. */
3607   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3608     && [(EmacsApp *)
3609          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3610                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3611     {
3612       [ns_pending_service_names removeObjectAtIndex: 0];
3613       [ns_pending_service_args removeObjectAtIndex: 0];
3614     }
3615   else
3616     {
3617       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3618          to ourself, otherwise [NXApp run] will never exit.  */
3619       send_appdefined = YES;
3620       ns_send_appdefined (-1);
3622       if (++apploopnr != 1)
3623         {
3624           emacs_abort ();
3625         }
3626       [NSApp run];
3627       --apploopnr;
3628     }
3630   nevents = n_emacs_events_pending;
3631   n_emacs_events_pending = 0;
3632   emacs_event = q_event_ptr = NULL;
3633   unblock_input ();
3635   return nevents;
3640 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3641            fd_set *exceptfds, struct timespec const *timeout,
3642            sigset_t const *sigmask)
3643 /* --------------------------------------------------------------------------
3644      Replacement for select, checking for events
3645    -------------------------------------------------------------------------- */
3647   int result;
3648   int t, k, nr = 0;
3649   struct input_event event;
3650   char c;
3652 /*  NSTRACE (ns_select); */
3654 #ifdef HAVE_NATIVE_FS
3655   check_native_fs ();
3656 #endif
3658   if (hold_event_q.nr > 0)
3659     {
3660       /* We already have events pending. */
3661       raise (SIGIO);
3662       errno = EINTR;
3663       return -1;
3664     }
3666   for (k = 0; k < nfds+1; k++)
3667     {
3668       if (readfds && FD_ISSET(k, readfds)) ++nr;
3669       if (writefds && FD_ISSET(k, writefds)) ++nr;
3670     }
3672   if (NSApp == nil
3673       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3674     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3676   [outerpool release];
3677   outerpool = [[NSAutoreleasePool alloc] init];
3680   send_appdefined = YES;
3681   if (nr > 0)
3682     {
3683       pthread_mutex_lock (&select_mutex);
3684       select_nfds = nfds;
3685       select_valid = 0;
3686       if (readfds)
3687         {
3688           select_readfds = *readfds;
3689           select_valid += SELECT_HAVE_READ;
3690         }
3691       if (writefds)
3692         {
3693           select_writefds = *writefds;
3694           select_valid += SELECT_HAVE_WRITE;
3695         }
3697       if (timeout)
3698         {
3699           select_timeout = *timeout;
3700           select_valid += SELECT_HAVE_TMO;
3701         }
3703       pthread_mutex_unlock (&select_mutex);
3705       /* Inform fd_handler that select should be called */
3706       c = 'g';
3707       emacs_write_sig (selfds[1], &c, 1);
3708     }
3709   else if (nr == 0 && timeout)
3710     {
3711       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3712       double time = timespectod (*timeout);
3713       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3714                                                       target: NSApp
3715                                                     selector:
3716                                   @selector (timeout_handler:)
3717                                                     userInfo: 0
3718                                                      repeats: NO]
3719                       retain];
3720     }
3721   else /* No timeout and no file descriptors, can this happen?  */
3722     {
3723       /* Send appdefined so we exit from the loop */
3724       ns_send_appdefined (-1);
3725     }
3727   EVENT_INIT (event);
3728   block_input ();
3729   emacs_event = &event;
3730   if (++apploopnr != 1)
3731     {
3732       emacs_abort ();
3733     }
3734   [NSApp run];
3735   --apploopnr;
3736   emacs_event = NULL;
3737   if (nr > 0 && readfds)
3738     {
3739       c = 's';
3740       emacs_write_sig (selfds[1], &c, 1);
3741     }
3742   unblock_input ();
3744   t = last_appdefined_event_data;
3746   if (t != NO_APPDEFINED_DATA)
3747     {
3748       last_appdefined_event_data = NO_APPDEFINED_DATA;
3750       if (t == -2)
3751         {
3752           /* The NX_APPDEFINED event we received was a timeout. */
3753           result = 0;
3754         }
3755       else if (t == -1)
3756         {
3757           /* The NX_APPDEFINED event we received was the result of
3758              at least one real input event arriving.  */
3759           errno = EINTR;
3760           result = -1;
3761         }
3762       else
3763         {
3764           /* Received back from select () in fd_handler; copy the results */
3765           pthread_mutex_lock (&select_mutex);
3766           if (readfds) *readfds = select_readfds;
3767           if (writefds) *writefds = select_writefds;
3768           pthread_mutex_unlock (&select_mutex);
3769           result = t;
3770         }
3771     }
3772   else
3773     {
3774       errno = EINTR;
3775       result = -1;
3776     }
3778   return result;
3783 /* ==========================================================================
3785     Scrollbar handling
3787    ========================================================================== */
3790 static void
3791 ns_set_vertical_scroll_bar (struct window *window,
3792                            int portion, int whole, int position)
3793 /* --------------------------------------------------------------------------
3794       External (hook): Update or add scrollbar
3795    -------------------------------------------------------------------------- */
3797   Lisp_Object win;
3798   NSRect r, v;
3799   struct frame *f = XFRAME (WINDOW_FRAME (window));
3800   EmacsView *view = FRAME_NS_VIEW (f);
3801   int window_y, window_height;
3802   int top, left, height, width, sb_width, sb_left;
3803   EmacsScroller *bar;
3804   BOOL fringe_extended_p;
3806   /* optimization; display engine sends WAY too many of these.. */
3807   if (!NILP (window->vertical_scroll_bar))
3808     {
3809       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3810       if ([bar checkSamePosition: position portion: portion whole: whole])
3811         {
3812           if (view->scrollbarsNeedingUpdate == 0)
3813             {
3814               if (!windows_or_buffers_changed)
3815                   return;
3816             }
3817           else
3818             view->scrollbarsNeedingUpdate--;
3819         }
3820     }
3822   NSTRACE (ns_set_vertical_scroll_bar);
3824   /* Get dimensions.  */
3825   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3826   top = window_y;
3827   height = window_height;
3828   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3829   left = WINDOW_SCROLL_BAR_AREA_X (window);
3831   /* allow for displaying a skinnier scrollbar than char area allotted */
3832   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3833     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3834   sb_left = left;
3836   r = NSMakeRect (sb_left, top, sb_width, height);
3837   /* the parent view is flipped, so we need to flip y value */
3838   v = [view frame];
3839   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3841   fringe_extended_p = WINDOW_FRINGE_EXTENDED_P (window);
3843   XSETWINDOW (win, window);
3844   block_input ();
3846   /* we want at least 5 lines to display a scrollbar */
3847   if (WINDOW_TOTAL_LINES (window) < 5)
3848     {
3849       if (!NILP (window->vertical_scroll_bar))
3850         {
3851           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3852           [bar removeFromSuperview];
3853           wset_vertical_scroll_bar (window, Qnil);
3854         }
3855       ns_clear_frame_area (f, sb_left, top, width, height);
3856       unblock_input ();
3857       return;
3858     }
3860   if (NILP (window->vertical_scroll_bar))
3861     {
3862       if (width > 0 && height > 0)
3863         {
3864           if (fringe_extended_p)
3865             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3866           else
3867             ns_clear_frame_area (f, left, top, width, height);
3868         }
3870       bar = [[EmacsScroller alloc] initFrame: r window: win];
3871       wset_vertical_scroll_bar (window, make_save_ptr (bar));
3872     }
3873   else
3874     {
3875       NSRect oldRect;
3876       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3877       oldRect = [bar frame];
3878       r.size.width = oldRect.size.width;
3879       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3880         {
3881           if (oldRect.origin.x != r.origin.x)
3882               ns_clear_frame_area (f, sb_left, top, width, height);
3883           [bar setFrame: r];
3884         }
3885     }
3887   [bar setPosition: position portion: portion whole: whole];
3888   unblock_input ();
3892 static void
3893 ns_condemn_scroll_bars (struct frame *f)
3894 /* --------------------------------------------------------------------------
3895      External (hook): arrange for all frame's scrollbars to be removed
3896      at next call to judge_scroll_bars, except for those redeemed.
3897    -------------------------------------------------------------------------- */
3899   int i;
3900   id view;
3901   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3903   NSTRACE (ns_condemn_scroll_bars);
3905   for (i =[subviews count]-1; i >= 0; i--)
3906     {
3907       view = [subviews objectAtIndex: i];
3908       if ([view isKindOfClass: [EmacsScroller class]])
3909         [view condemn];
3910     }
3914 static void
3915 ns_redeem_scroll_bar (struct window *window)
3916 /* --------------------------------------------------------------------------
3917      External (hook): arrange to spare this window's scrollbar
3918      at next call to judge_scroll_bars.
3919    -------------------------------------------------------------------------- */
3921   id bar;
3922   NSTRACE (ns_redeem_scroll_bar);
3923   if (!NILP (window->vertical_scroll_bar))
3924     {
3925       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3926       [bar reprieve];
3927     }
3931 static void
3932 ns_judge_scroll_bars (struct frame *f)
3933 /* --------------------------------------------------------------------------
3934      External (hook): destroy all scrollbars on frame that weren't
3935      redeemed after call to condemn_scroll_bars.
3936    -------------------------------------------------------------------------- */
3938   int i;
3939   id view;
3940   EmacsView *eview = FRAME_NS_VIEW (f);
3941   NSArray *subviews = [[eview superview] subviews];
3942   BOOL removed = NO;
3944   NSTRACE (ns_judge_scroll_bars);
3945   for (i = [subviews count]-1; i >= 0; --i)
3946     {
3947       view = [subviews objectAtIndex: i];
3948       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3949       [view judge];
3950       removed = YES;
3951     }
3953   if (removed)
3954     [eview updateFrameSize: NO];
3957 /* ==========================================================================
3959     Initialization
3961    ========================================================================== */
3964 x_display_pixel_height (struct ns_display_info *dpyinfo)
3966   NSArray *screens = [NSScreen screens];
3967   NSEnumerator *enumerator = [screens objectEnumerator];
3968   NSScreen *screen;
3969   NSRect frame;
3971   frame = NSZeroRect;
3972   while ((screen = [enumerator nextObject]) != nil)
3973     frame = NSUnionRect (frame, [screen frame]);
3975   return NSHeight (frame);
3979 x_display_pixel_width (struct ns_display_info *dpyinfo)
3981   NSArray *screens = [NSScreen screens];
3982   NSEnumerator *enumerator = [screens objectEnumerator];
3983   NSScreen *screen;
3984   NSRect frame;
3986   frame = NSZeroRect;
3987   while ((screen = [enumerator nextObject]) != nil)
3988     frame = NSUnionRect (frame, [screen frame]);
3990   return NSWidth (frame);
3994 static Lisp_Object ns_string_to_lispmod (const char *s)
3995 /* --------------------------------------------------------------------------
3996      Convert modifier name to lisp symbol
3997    -------------------------------------------------------------------------- */
3999   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4000     return Qmeta;
4001   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4002     return Qsuper;
4003   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4004     return Qcontrol;
4005   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4006     return Qalt;
4007   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4008     return Qhyper;
4009   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4010     return Qnone;
4011   else
4012     return Qnil;
4016 static void
4017 ns_default (const char *parameter, Lisp_Object *result,
4018            Lisp_Object yesval, Lisp_Object noval,
4019            BOOL is_float, BOOL is_modstring)
4020 /* --------------------------------------------------------------------------
4021       Check a parameter value in user's preferences
4022    -------------------------------------------------------------------------- */
4024   const char *value = ns_get_defaults_value (parameter);
4026   if (value)
4027     {
4028       double f;
4029       char *pos;
4030       if (c_strcasecmp (value, "YES") == 0)
4031         *result = yesval;
4032       else if (c_strcasecmp (value, "NO") == 0)
4033         *result = noval;
4034       else if (is_float && (f = strtod (value, &pos), pos != value))
4035         *result = make_float (f);
4036       else if (is_modstring && value)
4037         *result = ns_string_to_lispmod (value);
4038       else fprintf (stderr,
4039                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4040     }
4044 static void
4045 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4046 /* --------------------------------------------------------------------------
4047       Initialize global info and storage for display.
4048    -------------------------------------------------------------------------- */
4050     NSScreen *screen = [NSScreen mainScreen];
4051     NSWindowDepth depth = [screen depth];
4053     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4054     dpyinfo->resy = 72.27;
4055     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4056                                                   NSColorSpaceFromDepth (depth)]
4057                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4058                                                  NSColorSpaceFromDepth (depth)];
4059     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4060     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4061     dpyinfo->color_table->colors = NULL;
4062     dpyinfo->root_window = 42; /* a placeholder.. */
4063     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4064     dpyinfo->n_fonts = 0;
4065     dpyinfo->smallest_font_height = 1;
4066     dpyinfo->smallest_char_width = 1;
4068     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4072 /* This and next define (many of the) public functions in this file. */
4073 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4074          with using despite presence in the "system dependent" redisplay
4075          interface.  In addition, many of the ns_ methods have code that is
4076          shared with all terms, indicating need for further refactoring. */
4077 extern frame_parm_handler ns_frame_parm_handlers[];
4078 static struct redisplay_interface ns_redisplay_interface =
4080   ns_frame_parm_handlers,
4081   x_produce_glyphs,
4082   x_write_glyphs,
4083   x_insert_glyphs,
4084   x_clear_end_of_line,
4085   ns_scroll_run,
4086   ns_after_update_window_line,
4087   ns_update_window_begin,
4088   ns_update_window_end,
4089   0, /* flush_display */
4090   x_clear_window_mouse_face,
4091   x_get_glyph_overhangs,
4092   x_fix_overlapping_area,
4093   ns_draw_fringe_bitmap,
4094   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4095   0, /* destroy_fringe_bitmap */
4096   ns_compute_glyph_string_overhangs,
4097   ns_draw_glyph_string,
4098   ns_define_frame_cursor,
4099   ns_clear_frame_area,
4100   ns_draw_window_cursor,
4101   ns_draw_vertical_window_border,
4102   ns_draw_window_divider,
4103   ns_shift_glyphs_for_insert
4107 static void
4108 ns_delete_display (struct ns_display_info *dpyinfo)
4110   /* TODO... */
4114 /* This function is called when the last frame on a display is deleted. */
4115 static void
4116 ns_delete_terminal (struct terminal *terminal)
4118   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4120   /* Protect against recursive calls.  delete_frame in
4121      delete_terminal calls us back when it deletes our last frame.  */
4122   if (!terminal->name)
4123     return;
4125   block_input ();
4127   x_destroy_all_bitmaps (dpyinfo);
4128   ns_delete_display (dpyinfo);
4129   unblock_input ();
4133 static struct terminal *
4134 ns_create_terminal (struct ns_display_info *dpyinfo)
4135 /* --------------------------------------------------------------------------
4136       Set up use of NS before we make the first connection.
4137    -------------------------------------------------------------------------- */
4139   struct terminal *terminal;
4141   NSTRACE (ns_create_terminal);
4143   terminal = create_terminal ();
4145   terminal->type = output_ns;
4146   terminal->display_info.ns = dpyinfo;
4147   dpyinfo->terminal = terminal;
4149   terminal->rif = &ns_redisplay_interface;
4151   terminal->clear_frame_hook = ns_clear_frame;
4152   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4153   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
4154   terminal->ring_bell_hook = ns_ring_bell;
4155   terminal->reset_terminal_modes_hook = NULL;
4156   terminal->set_terminal_modes_hook = NULL;
4157   terminal->update_begin_hook = ns_update_begin;
4158   terminal->update_end_hook = ns_update_end;
4159   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4160   terminal->read_socket_hook = ns_read_socket;
4161   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4162   terminal->mouse_position_hook = ns_mouse_position;
4163   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4164   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4166   terminal->fullscreen_hook = ns_fullscreen_hook;
4168   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4169   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4170   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4171   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4173   terminal->delete_frame_hook = x_destroy_window;
4174   terminal->delete_terminal_hook = ns_delete_terminal;
4176   return terminal;
4180 struct ns_display_info *
4181 ns_term_init (Lisp_Object display_name)
4182 /* --------------------------------------------------------------------------
4183      Start the Application and get things rolling.
4184    -------------------------------------------------------------------------- */
4186   struct terminal *terminal;
4187   struct ns_display_info *dpyinfo;
4188   static int ns_initialized = 0;
4189   Lisp_Object tmp;
4191   if (ns_initialized) return x_display_list;
4192   ns_initialized = 1;
4194   NSTRACE (ns_term_init);
4196   [outerpool release];
4197   outerpool = [[NSAutoreleasePool alloc] init];
4199   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4200   /*GSDebugAllocationActive (YES); */
4201   block_input ();
4203   baud_rate = 38400;
4204   Fset_input_interrupt_mode (Qnil);
4206   if (selfds[0] == -1)
4207     {
4208       if (emacs_pipe (selfds) != 0)
4209         {
4210           fprintf (stderr, "Failed to create pipe: %s\n",
4211                    emacs_strerror (errno));
4212           emacs_abort ();
4213         }
4215       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4216       FD_ZERO (&select_readfds);
4217       FD_ZERO (&select_writefds);
4218       pthread_mutex_init (&select_mutex, NULL);
4219     }
4221   ns_pending_files = [[NSMutableArray alloc] init];
4222   ns_pending_service_names = [[NSMutableArray alloc] init];
4223   ns_pending_service_args = [[NSMutableArray alloc] init];
4225 /* Start app and create the main menu, window, view.
4226      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4227      The view will then ask the NSApp to stop and return to Emacs. */
4228   [EmacsApp sharedApplication];
4229   if (NSApp == nil)
4230     return NULL;
4231   [NSApp setDelegate: NSApp];
4233   /* Start the select thread.  */
4234   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4235                            toTarget:NSApp
4236                          withObject:nil];
4238   /* debugging: log all notifications */
4239   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4240                                          selector: @selector (logNotification:)
4241                                              name: nil object: nil]; */
4243   dpyinfo = xzalloc (sizeof *dpyinfo);
4245   ns_initialize_display_info (dpyinfo);
4246   terminal = ns_create_terminal (dpyinfo);
4248   terminal->kboard = allocate_kboard (Qns);
4249   /* Don't let the initial kboard remain current longer than necessary.
4250      That would cause problems if a file loaded on startup tries to
4251      prompt in the mini-buffer.  */
4252   if (current_kboard == initial_kboard)
4253     current_kboard = terminal->kboard;
4254   terminal->kboard->reference_count++;
4256   dpyinfo->next = x_display_list;
4257   x_display_list = dpyinfo;
4259   dpyinfo->name_list_element = Fcons (display_name, Qnil);
4261   terminal->name = xstrdup (SSDATA (display_name));
4263   unblock_input ();
4265   if (!inhibit_x_resources)
4266     {
4267       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4268                  Qt, Qnil, NO, NO);
4269       tmp = Qnil;
4270       /* this is a standard variable */
4271       ns_default ("AppleAntiAliasingThreshold", &tmp,
4272                  make_float (10.0), make_float (6.0), YES, NO);
4273       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4274     }
4276   {
4277     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4279     if ( cl == nil )
4280       {
4281         Lisp_Object color_file, color_map, color;
4282         unsigned long c;
4283         char *name;
4285         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4286                          Fsymbol_value (intern ("data-directory")));
4288         color_map = Fx_load_color_file (color_file);
4289         if (NILP (color_map))
4290           fatal ("Could not read %s.\n", SDATA (color_file));
4292         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4293         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4294           {
4295             color = XCAR (color_map);
4296             name = SSDATA (XCAR (color));
4297             c = XINT (XCDR (color));
4298             [cl setColor:
4299                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4300                                       green: GREEN_FROM_ULONG (c) / 255.0
4301                                        blue: BLUE_FROM_ULONG (c) / 255.0
4302                                       alpha: 1.0]
4303                   forKey: [NSString stringWithUTF8String: name]];
4304           }
4305         [cl writeToFile: nil];
4306       }
4307   }
4309   {
4310 #ifdef NS_IMPL_GNUSTEP
4311     Vwindow_system_version = build_string (gnustep_base_version);
4312 #else
4313     /*PSnextrelease (128, c); */
4314     char c[DBL_BUFSIZE_BOUND];
4315     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4316     Vwindow_system_version = make_unibyte_string (c, len);
4317 #endif
4318   }
4320   delete_keyboard_wait_descriptor (0);
4322   ns_app_name = [[NSProcessInfo processInfo] processName];
4324 /* Set up OS X app menu */
4325 #ifdef NS_IMPL_COCOA
4326   {
4327     NSMenu *appMenu;
4328     NSMenuItem *item;
4329     /* set up the application menu */
4330     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4331     [svcsMenu setAutoenablesItems: NO];
4332     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4333     [appMenu setAutoenablesItems: NO];
4334     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4335     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4337     [appMenu insertItemWithTitle: @"About Emacs"
4338                           action: @selector (orderFrontStandardAboutPanel:)
4339                    keyEquivalent: @""
4340                          atIndex: 0];
4341     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4342     [appMenu insertItemWithTitle: @"Preferences..."
4343                           action: @selector (showPreferencesWindow:)
4344                    keyEquivalent: @","
4345                          atIndex: 2];
4346     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4347     item = [appMenu insertItemWithTitle: @"Services"
4348                                  action: @selector (menuDown:)
4349                           keyEquivalent: @""
4350                                 atIndex: 4];
4351     [appMenu setSubmenu: svcsMenu forItem: item];
4352     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4353     [appMenu insertItemWithTitle: @"Hide Emacs"
4354                           action: @selector (hide:)
4355                    keyEquivalent: @"h"
4356                          atIndex: 6];
4357     item =  [appMenu insertItemWithTitle: @"Hide Others"
4358                           action: @selector (hideOtherApplications:)
4359                    keyEquivalent: @"h"
4360                          atIndex: 7];
4361     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4362     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4363     [appMenu insertItemWithTitle: @"Quit Emacs"
4364                           action: @selector (terminate:)
4365                    keyEquivalent: @"q"
4366                          atIndex: 9];
4368     item = [mainMenu insertItemWithTitle: ns_app_name
4369                                   action: @selector (menuDown:)
4370                            keyEquivalent: @""
4371                                  atIndex: 0];
4372     [mainMenu setSubmenu: appMenu forItem: item];
4373     [dockMenu insertItemWithTitle: @"New Frame"
4374                            action: @selector (newFrame:)
4375                     keyEquivalent: @""
4376                           atIndex: 0];
4378     [NSApp setMainMenu: mainMenu];
4379     [NSApp setAppleMenu: appMenu];
4380     [NSApp setServicesMenu: svcsMenu];
4381     /* Needed at least on Cocoa, to get dock menu to show windows */
4382     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4384     [[NSNotificationCenter defaultCenter]
4385       addObserver: mainMenu
4386          selector: @selector (trackingNotification:)
4387              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4388     [[NSNotificationCenter defaultCenter]
4389       addObserver: mainMenu
4390          selector: @selector (trackingNotification:)
4391              name: NSMenuDidEndTrackingNotification object: mainMenu];
4392   }
4393 #endif /* MAC OS X menu setup */
4395   /* Register our external input/output types, used for determining
4396      applicable services and also drag/drop eligibility. */
4397   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4398   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4399                       retain];
4400   ns_drag_types = [[NSArray arrayWithObjects:
4401                             NSStringPboardType,
4402                             NSTabularTextPboardType,
4403                             NSFilenamesPboardType,
4404                             NSURLPboardType, nil] retain];
4406   /* If fullscreen is in init/default-frame-alist, focus isn't set
4407      right for fullscreen windows, so set this.  */
4408   [NSApp activateIgnoringOtherApps:YES];
4410   [NSApp run];
4411   ns_do_open_file = YES;
4413 #ifdef NS_IMPL_GNUSTEP
4414   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4415      We must re-catch it so subprocess works.  */
4416   catch_child_signal ();
4417 #endif
4418   return dpyinfo;
4422 void
4423 ns_term_shutdown (int sig)
4425   [[NSUserDefaults standardUserDefaults] synchronize];
4427   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4428   if (STRINGP (Vauto_save_list_file_name))
4429     unlink (SSDATA (Vauto_save_list_file_name));
4431   if (sig == 0 || sig == SIGTERM)
4432     {
4433       [NSApp terminate: NSApp];
4434     }
4435   else // force a stack trace to happen
4436     {
4437       emacs_abort ();
4438     }
4442 /* ==========================================================================
4444     EmacsApp implementation
4446    ========================================================================== */
4449 @implementation EmacsApp
4451 - (id)init
4453   if (self = [super init])
4454     {
4455 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
4456       self->isFirst = YES;
4457 #endif
4458 #ifdef NS_IMPL_GNUSTEP
4459       self->applicationDidFinishLaunchingCalled = NO;
4460 #endif
4461     }
4463   return self;
4466 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
4467 - (void)run
4469     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4471     if (isFirst) [self finishLaunching];
4472     isFirst = NO;
4474     shouldKeepRunning = YES;
4475     do
4476       {
4477         [pool release];
4478         pool = [[NSAutoreleasePool alloc] init];
4480         NSEvent *event =
4481           [self nextEventMatchingMask:NSAnyEventMask
4482                             untilDate:[NSDate distantFuture]
4483                                inMode:NSDefaultRunLoopMode
4484                               dequeue:YES];
4485         [self sendEvent:event];
4486         [self updateWindows];
4487     } while (shouldKeepRunning);
4489     [pool release];
4492 - (void)stop: (id)sender
4494     shouldKeepRunning = NO;
4495     // Stop possible dialog also.  Noop if no dialog present.
4496     // The file dialog still leaks 7k - 10k on 10.9 though.
4497     [super stop:sender];
4499 #endif
4501 - (void)logNotification: (NSNotification *)notification
4503   const char *name = [[notification name] UTF8String];
4504   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4505       && !strstr (name, "WindowNumber"))
4506     NSLog (@"notification: '%@'", [notification name]);
4510 - (void)sendEvent: (NSEvent *)theEvent
4511 /* --------------------------------------------------------------------------
4512      Called when NSApp is running for each event received.  Used to stop
4513      the loop when we choose, since there's no way to just run one iteration.
4514    -------------------------------------------------------------------------- */
4516   int type = [theEvent type];
4517   NSWindow *window = [theEvent window];
4519 /*  NSTRACE (sendEvent); */
4520 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4522 #ifdef NS_IMPL_GNUSTEP
4523   // Keyboard events aren't propagated to file dialogs for some reason.
4524   if ([NSApp modalWindow] != nil &&
4525       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4526     {
4527       [[NSApp modalWindow] sendEvent: theEvent];
4528       return;
4529     }
4530 #endif
4532   if (type == NSApplicationDefined)
4533     {
4534       switch ([theEvent data2])
4535         {
4536 #ifdef NS_IMPL_COCOA
4537         case NSAPP_DATA2_RUNASSCRIPT:
4538           ns_run_ascript ();
4539           [self stop: self];
4540           return;
4541 #endif
4542         case NSAPP_DATA2_RUNFILEDIALOG:
4543           ns_run_file_dialog ();
4544           [self stop: self];
4545           return;
4546         }
4547     }
4549   if (type == NSCursorUpdate && window == nil)
4550     {
4551       fprintf (stderr, "Dropping external cursor update event.\n");
4552       return;
4553     }
4555   if (type == NSApplicationDefined)
4556     {
4557       /* Events posted by ns_send_appdefined interrupt the run loop here.
4558          But, if a modal window is up, an appdefined can still come through,
4559          (e.g., from a makeKeyWindow event) but stopping self also stops the
4560          modal loop. Just defer it until later. */
4561       if ([NSApp modalWindow] == nil)
4562         {
4563           last_appdefined_event_data = [theEvent data1];
4564           [self stop: self];
4565         }
4566       else
4567         {
4568           send_appdefined = YES;
4569         }
4570     }
4573 #ifdef NS_IMPL_COCOA
4574   /* If no dialog and none of our frames have focus and it is a move, skip it.
4575      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4576      such as Wifi, sound, date or similar.
4577      This prevents "spooky" highlighting in the frame under the menu.  */
4578   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4579     {
4580       struct ns_display_info *di;
4581       BOOL has_focus = NO;
4582       for (di = x_display_list; ! has_focus && di; di = di->next)
4583         has_focus = di->x_focus_frame != 0;
4584       if (! has_focus)
4585         return;
4586     }
4587 #endif
4589   [super sendEvent: theEvent];
4593 - (void)showPreferencesWindow: (id)sender
4595   struct frame *emacsframe = SELECTED_FRAME ();
4596   NSEvent *theEvent = [NSApp currentEvent];
4598   if (!emacs_event)
4599     return;
4600   emacs_event->kind = NS_NONKEY_EVENT;
4601   emacs_event->code = KEY_NS_SHOW_PREFS;
4602   emacs_event->modifiers = 0;
4603   EV_TRAILER (theEvent);
4607 - (void)newFrame: (id)sender
4609   struct frame *emacsframe = SELECTED_FRAME ();
4610   NSEvent *theEvent = [NSApp currentEvent];
4612   if (!emacs_event)
4613     return;
4614   emacs_event->kind = NS_NONKEY_EVENT;
4615   emacs_event->code = KEY_NS_NEW_FRAME;
4616   emacs_event->modifiers = 0;
4617   EV_TRAILER (theEvent);
4621 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4622 - (BOOL) openFile: (NSString *)fileName
4624   struct frame *emacsframe = SELECTED_FRAME ();
4625   NSEvent *theEvent = [NSApp currentEvent];
4627   if (!emacs_event)
4628     return NO;
4630   emacs_event->kind = NS_NONKEY_EVENT;
4631   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4632   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4633   ns_input_line = Qnil; /* can be start or cons start,end */
4634   emacs_event->modifiers =0;
4635   EV_TRAILER (theEvent);
4637   return YES;
4641 /* **************************************************************************
4643       EmacsApp delegate implementation
4645    ************************************************************************** */
4647 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4648 /* --------------------------------------------------------------------------
4649      When application is loaded, terminate event loop in ns_term_init
4650    -------------------------------------------------------------------------- */
4652   NSTRACE (applicationDidFinishLaunching);
4653 #ifdef NS_IMPL_GNUSTEP
4654   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
4655 #endif
4656   [NSApp setServicesProvider: NSApp];
4658   [self antialiasThresholdDidChange:nil];
4659 #ifdef NS_IMPL_COCOA
4660 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
4661   [[NSNotificationCenter defaultCenter]
4662     addObserver:self
4663        selector:@selector(antialiasThresholdDidChange:)
4664            name:NSAntialiasThresholdChangedNotification
4665          object:nil];
4666 #endif
4667 #endif
4669   ns_send_appdefined (-2);
4672 - (void)antialiasThresholdDidChange:(NSNotification *)notification
4674 #ifdef NS_IMPL_COCOA
4675 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
4676   macfont_update_antialias_threshold ();
4677 #endif
4678 #endif
4682 /* Termination sequences:
4683     C-x C-c:
4684     Cmd-Q:
4685     MenuBar | File | Exit:
4686     Select Quit from App menubar:
4687         -terminate
4688         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4689         ns_term_shutdown()
4691     Select Quit from Dock menu:
4692     Logout attempt:
4693         -appShouldTerminate
4694           Cancel -> Nothing else
4695           Accept ->
4697           -terminate
4698           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4699           ns_term_shutdown()
4703 - (void) terminate: (id)sender
4705   struct frame *emacsframe = SELECTED_FRAME ();
4707   if (!emacs_event)
4708     return;
4710   emacs_event->kind = NS_NONKEY_EVENT;
4711   emacs_event->code = KEY_NS_POWER_OFF;
4712   emacs_event->arg = Qt; /* mark as non-key event */
4713   EV_TRAILER ((id)nil);
4717 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4719   int ret;
4721   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4722     return NSTerminateNow;
4724     ret = NSRunAlertPanel(ns_app_name,
4725                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4726                           @"Save Buffers and Exit", @"Cancel", nil);
4728     if (ret == NSAlertDefaultReturn)
4729         return NSTerminateNow;
4730     else if (ret == NSAlertAlternateReturn)
4731         return NSTerminateCancel;
4732     return NSTerminateNow;  /* just in case */
4735 static int
4736 not_in_argv (NSString *arg)
4738   int k;
4739   const char *a = [arg UTF8String];
4740   for (k = 1; k < initial_argc; ++k)
4741     if (strcmp (a, initial_argv[k]) == 0) return 0;
4742   return 1;
4745 /*   Notification from the Workspace to open a file */
4746 - (BOOL)application: sender openFile: (NSString *)file
4748   if (ns_do_open_file || not_in_argv (file))
4749     [ns_pending_files addObject: file];
4750   return YES;
4754 /*   Open a file as a temporary file */
4755 - (BOOL)application: sender openTempFile: (NSString *)file
4757   if (ns_do_open_file || not_in_argv (file))
4758     [ns_pending_files addObject: file];
4759   return YES;
4763 /*   Notification from the Workspace to open a file noninteractively (?) */
4764 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4766   if (ns_do_open_file || not_in_argv (file))
4767     [ns_pending_files addObject: file];
4768   return YES;
4771 /*   Notification from the Workspace to open multiple files */
4772 - (void)application: sender openFiles: (NSArray *)fileList
4774   NSEnumerator *files = [fileList objectEnumerator];
4775   NSString *file;
4776   /* Don't open files from the command line unconditionally,
4777      Cocoa parses the command line wrong, --option value tries to open value
4778      if --option is the last option.  */
4779   while ((file = [files nextObject]) != nil)
4780     if (ns_do_open_file || not_in_argv (file))
4781       [ns_pending_files addObject: file];
4783   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4788 /* Handle dock menu requests.  */
4789 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4791   return dockMenu;
4795 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4796 - (void)applicationWillBecomeActive: (NSNotification *)notification
4798   //ns_app_active=YES;
4800 - (void)applicationDidBecomeActive: (NSNotification *)notification
4802   NSTRACE (applicationDidBecomeActive);
4804 #ifdef NS_IMPL_GNUSTEP
4805   if (! applicationDidFinishLaunchingCalled)
4806     [self applicationDidFinishLaunching:notification];
4807 #endif
4808   //ns_app_active=YES;
4810   ns_update_auto_hide_menu_bar ();
4811   // No constraining takes place when the application is not active.
4812   ns_constrain_all_frames ();
4814 - (void)applicationDidResignActive: (NSNotification *)notification
4816   //ns_app_active=NO;
4817   ns_send_appdefined (-1);
4822 /* ==========================================================================
4824     EmacsApp aux handlers for managing event loop
4826    ========================================================================== */
4829 - (void)timeout_handler: (NSTimer *)timedEntry
4830 /* --------------------------------------------------------------------------
4831      The timeout specified to ns_select has passed.
4832    -------------------------------------------------------------------------- */
4834   /*NSTRACE (timeout_handler); */
4835   ns_send_appdefined (-2);
4838 #ifdef NS_IMPL_GNUSTEP
4839 - (void)sendFromMainThread:(id)unused
4841   ns_send_appdefined (nextappdefined);
4843 #endif
4845 - (void)fd_handler:(id)unused
4846 /* --------------------------------------------------------------------------
4847      Check data waiting on file descriptors and terminate if so
4848    -------------------------------------------------------------------------- */
4850   int result;
4851   int waiting = 1, nfds;
4852   char c;
4854   fd_set readfds, writefds, *wfds;
4855   struct timespec timeout, *tmo;
4856   NSAutoreleasePool *pool = nil;
4858   /* NSTRACE (fd_handler); */
4860   for (;;)
4861     {
4862       [pool release];
4863       pool = [[NSAutoreleasePool alloc] init];
4865       if (waiting)
4866         {
4867           fd_set fds;
4868           FD_ZERO (&fds);
4869           FD_SET (selfds[0], &fds);
4870           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4871           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4872             waiting = 0;
4873         }
4874       else
4875         {
4876           pthread_mutex_lock (&select_mutex);
4877           nfds = select_nfds;
4879           if (select_valid & SELECT_HAVE_READ)
4880             readfds = select_readfds;
4881           else
4882             FD_ZERO (&readfds);
4884           if (select_valid & SELECT_HAVE_WRITE)
4885             {
4886               writefds = select_writefds;
4887               wfds = &writefds;
4888             }
4889           else
4890             wfds = NULL;
4891           if (select_valid & SELECT_HAVE_TMO)
4892             {
4893               timeout = select_timeout;
4894               tmo = &timeout;
4895             }
4896           else
4897             tmo = NULL;
4899           pthread_mutex_unlock (&select_mutex);
4901           FD_SET (selfds[0], &readfds);
4902           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4904           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4906           if (result == 0)
4907             ns_send_appdefined (-2);
4908           else if (result > 0)
4909             {
4910               if (FD_ISSET (selfds[0], &readfds))
4911                 {
4912                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4913                     waiting = 1;
4914                 }
4915               else
4916                 {
4917                   pthread_mutex_lock (&select_mutex);
4918                   if (select_valid & SELECT_HAVE_READ)
4919                     select_readfds = readfds;
4920                   if (select_valid & SELECT_HAVE_WRITE)
4921                     select_writefds = writefds;
4922                   if (select_valid & SELECT_HAVE_TMO)
4923                     select_timeout = timeout;
4924                   pthread_mutex_unlock (&select_mutex);
4926                   ns_send_appdefined (result);
4927                 }
4928             }
4929           waiting = 1;
4930         }
4931     }
4936 /* ==========================================================================
4938     Service provision
4940    ========================================================================== */
4942 /* called from system: queue for next pass through event loop */
4943 - (void)requestService: (NSPasteboard *)pboard
4944               userData: (NSString *)userData
4945                  error: (NSString **)error
4947   [ns_pending_service_names addObject: userData];
4948   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4949       SSDATA (ns_string_from_pasteboard (pboard))]];
4953 /* called from ns_read_socket to clear queue */
4954 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4956   struct frame *emacsframe = SELECTED_FRAME ();
4957   NSEvent *theEvent = [NSApp currentEvent];
4959   if (!emacs_event)
4960     return NO;
4962   emacs_event->kind = NS_NONKEY_EVENT;
4963   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4964   ns_input_spi_name = build_string ([name UTF8String]);
4965   ns_input_spi_arg = build_string ([arg UTF8String]);
4966   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4967   EV_TRAILER (theEvent);
4969   return YES;
4973 @end  /* EmacsApp */
4977 /* ==========================================================================
4979     EmacsView implementation
4981    ========================================================================== */
4984 @implementation EmacsView
4986 /* needed to inform when window closed from LISP */
4987 - (void) setWindowClosing: (BOOL)closing
4989   windowClosing = closing;
4993 - (void)dealloc
4995   NSTRACE (EmacsView_dealloc);
4996   [toolbar release];
4997   if (fs_state == FULLSCREEN_BOTH)
4998     [nonfs_window release];
4999   [super dealloc];
5003 /* called on font panel selection */
5004 - (void)changeFont: (id)sender
5006   NSEvent *e = [[self window] currentEvent];
5007   struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5008   struct font *font = face->font;
5009   id newFont;
5010   CGFloat size;
5011   NSFont *nsfont;
5013   NSTRACE (changeFont);
5015   if (!emacs_event)
5016     return;
5018   if (EQ (font->driver->type, Qns))
5019     nsfont = ((struct nsfont_info *)font)->nsfont;
5020 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
5021   else
5022     nsfont = (NSFont *) macfont_get_nsctfont (font);
5023 #endif
5025   if ((newFont = [sender convertFont: nsfont]))
5026     {
5027       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5029       emacs_event->kind = NS_NONKEY_EVENT;
5030       emacs_event->modifiers = 0;
5031       emacs_event->code = KEY_NS_CHANGE_FONT;
5033       size = [newFont pointSize];
5034       ns_input_fontsize = make_number (lrint (size));
5035       ns_input_font = build_string ([[newFont familyName] UTF8String]);
5036       EV_TRAILER (e);
5037     }
5041 - (BOOL)acceptsFirstResponder
5043   NSTRACE (acceptsFirstResponder);
5044   return YES;
5048 - (void)resetCursorRects
5050   NSRect visible = [self visibleRect];
5051   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5052   NSTRACE (resetCursorRects);
5054   if (currentCursor == nil)
5055     currentCursor = [NSCursor arrowCursor];
5057   if (!NSIsEmptyRect (visible))
5058     [self addCursorRect: visible cursor: currentCursor];
5059   [currentCursor setOnMouseEntered: YES];
5064 /*****************************************************************************/
5065 /* Keyboard handling. */
5066 #define NS_KEYLOG 0
5068 - (void)keyDown: (NSEvent *)theEvent
5070   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5071   int code;
5072   unsigned fnKeysym = 0;
5073   static NSMutableArray *nsEvArray;
5074 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5075   static BOOL firstTime = YES;
5076 #endif
5077   int left_is_none;
5078   unsigned int flags = [theEvent modifierFlags];
5080   NSTRACE (keyDown);
5082   /* Rhapsody and OS X give up and down events for the arrow keys */
5083   if (ns_fake_keydown == YES)
5084     ns_fake_keydown = NO;
5085   else if ([theEvent type] != NSKeyDown)
5086     return;
5088   if (!emacs_event)
5089     return;
5091  if (![[self window] isKeyWindow]
5092      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5093      /* we must avoid an infinite loop here. */
5094      && (EmacsView *)[[theEvent window] delegate] != self)
5095    {
5096      /* XXX: There is an occasional condition in which, when Emacs display
5097          updates a different frame from the current one, and temporarily
5098          selects it, then processes some interrupt-driven input
5099          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5100          for some reason that window has its first responder set to the NSView
5101          most recently updated (I guess), which is not the correct one. */
5102      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5103      return;
5104    }
5106   if (nsEvArray == nil)
5107     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5109   [NSCursor setHiddenUntilMouseMoves: YES];
5111   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5112     {
5113       clear_mouse_face (hlinfo);
5114       hlinfo->mouse_face_hidden = 1;
5115     }
5117   if (!processingCompose)
5118     {
5119       /* When using screen sharing, no left or right information is sent,
5120          so use Left key in those cases.  */
5121       int is_left_key, is_right_key;
5123       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5124         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5126       /* (Carbon way: [theEvent keyCode]) */
5128       /* is it a "function key"? */
5129       /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5130          flag set (this is probably a bug in the OS).
5131       */
5132       if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5133         {
5134           fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5135         }
5136       if (fnKeysym == 0)
5137         {
5138           fnKeysym = ns_convert_key (code);
5139         }
5141       if (fnKeysym)
5142         {
5143           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5144              because Emacs treats Delete and KP-Delete same (in simple.el). */
5145           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5146 #ifdef NS_IMPL_GNUSTEP
5147               /*  GNUstep uses incompatible keycodes, even for those that are
5148                   supposed to be hardware independent.  Just check for delete.
5149                   Keypad delete does not have keysym 0xFFFF.
5150                   See http://savannah.gnu.org/bugs/?25395
5151               */
5152               || (fnKeysym == 0xFFFF && code == 127)
5153 #endif
5154             )
5155             code = 0xFF08; /* backspace */
5156           else
5157             code = fnKeysym;
5158         }
5160       /* are there modifiers? */
5161       emacs_event->modifiers = 0;
5163       if (flags & NSHelpKeyMask)
5164           emacs_event->modifiers |= hyper_modifier;
5166       if (flags & NSShiftKeyMask)
5167         emacs_event->modifiers |= shift_modifier;
5169       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5170       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5171         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5173       if (is_right_key)
5174         emacs_event->modifiers |= parse_solitary_modifier
5175           (EQ (ns_right_command_modifier, Qleft)
5176            ? ns_command_modifier
5177            : ns_right_command_modifier);
5179       if (is_left_key)
5180         {
5181           emacs_event->modifiers |= parse_solitary_modifier
5182             (ns_command_modifier);
5184           /* if super (default), take input manager's word so things like
5185              dvorak / qwerty layout work */
5186           if (EQ (ns_command_modifier, Qsuper)
5187               && !fnKeysym
5188               && [[theEvent characters] length] != 0)
5189             {
5190               /* XXX: the code we get will be unshifted, so if we have
5191                  a shift modifier, must convert ourselves */
5192               if (!(flags & NSShiftKeyMask))
5193                 code = [[theEvent characters] characterAtIndex: 0];
5194 #if 0
5195               /* this is ugly and also requires linking w/Carbon framework
5196                  (for LMGetKbdType) so for now leave this rare (?) case
5197                  undealt with.. in future look into CGEvent methods */
5198               else
5199                 {
5200                   long smv = GetScriptManagerVariable (smKeyScript);
5201                   Handle uchrHandle = GetResource
5202                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5203                   UInt32 dummy = 0;
5204                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5205                                  [[theEvent characters] characterAtIndex: 0],
5206                                  kUCKeyActionDisplay,
5207                                  (flags & ~NSCommandKeyMask) >> 8,
5208                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5209                                  &dummy, 1, &dummy, &code);
5210                   code &= 0xFF;
5211                 }
5212 #endif
5213             }
5214         }
5216       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5217       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5218         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5220       if (is_right_key)
5221           emacs_event->modifiers |= parse_solitary_modifier
5222               (EQ (ns_right_control_modifier, Qleft)
5223                ? ns_control_modifier
5224                : ns_right_control_modifier);
5226       if (is_left_key)
5227         emacs_event->modifiers |= parse_solitary_modifier
5228           (ns_control_modifier);
5230       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5231           emacs_event->modifiers |=
5232             parse_solitary_modifier (ns_function_modifier);
5234       left_is_none = NILP (ns_alternate_modifier)
5235         || EQ (ns_alternate_modifier, Qnone);
5237       is_right_key = (flags & NSRightAlternateKeyMask)
5238         == NSRightAlternateKeyMask;
5239       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5240         || (! is_right_key
5241             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5243       if (is_right_key)
5244         {
5245           if ((NILP (ns_right_alternate_modifier)
5246                || EQ (ns_right_alternate_modifier, Qnone)
5247                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5248               && !fnKeysym)
5249             {   /* accept pre-interp alt comb */
5250               if ([[theEvent characters] length] > 0)
5251                 code = [[theEvent characters] characterAtIndex: 0];
5252               /*HACK: clear lone shift modifier to stop next if from firing */
5253               if (emacs_event->modifiers == shift_modifier)
5254                 emacs_event->modifiers = 0;
5255             }
5256           else
5257             emacs_event->modifiers |= parse_solitary_modifier
5258               (EQ (ns_right_alternate_modifier, Qleft)
5259                ? ns_alternate_modifier
5260                : ns_right_alternate_modifier);
5261         }
5263       if (is_left_key) /* default = meta */
5264         {
5265           if (left_is_none && !fnKeysym)
5266             {   /* accept pre-interp alt comb */
5267               if ([[theEvent characters] length] > 0)
5268                 code = [[theEvent characters] characterAtIndex: 0];
5269               /*HACK: clear lone shift modifier to stop next if from firing */
5270               if (emacs_event->modifiers == shift_modifier)
5271                 emacs_event->modifiers = 0;
5272             }
5273           else
5274               emacs_event->modifiers |=
5275                 parse_solitary_modifier (ns_alternate_modifier);
5276         }
5278   if (NS_KEYLOG)
5279     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5280              code, fnKeysym, flags, emacs_event->modifiers);
5282       /* if it was a function key or had modifiers, pass it directly to emacs */
5283       if (fnKeysym || (emacs_event->modifiers
5284                        && (emacs_event->modifiers != shift_modifier)
5285                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5286 /*[[theEvent characters] length] */
5287         {
5288           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5289           if (code < 0x20)
5290             code |= (1<<28)|(3<<16);
5291           else if (code == 0x7f)
5292             code |= (1<<28)|(3<<16);
5293           else if (!fnKeysym)
5294             emacs_event->kind = code > 0xFF
5295               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5297           emacs_event->code = code;
5298           EV_TRAILER (theEvent);
5299           processingCompose = NO;
5300           return;
5301         }
5302     }
5305 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5306   /* if we get here we should send the key for input manager processing */
5307   /* Disable warning, there is nothing a user can do about it anyway, and
5308      it does not seem to matter.  */
5309 #if 0
5310   if (firstTime && [[NSInputManager currentInputManager]
5311                      wantsToDelayTextChangeNotifications] == NO)
5312     fprintf (stderr,
5313           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5314 #endif
5315   firstTime = NO;
5316 #endif
5317   if (NS_KEYLOG && !processingCompose)
5318     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5320   processingCompose = YES;
5321   [nsEvArray addObject: theEvent];
5322   [self interpretKeyEvents: nsEvArray];
5323   [nsEvArray removeObject: theEvent];
5327 #ifdef NS_IMPL_COCOA
5328 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5329    decided not to send key-down for.
5330    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5331    This only applies on Tiger and earlier.
5332    If it matches one of these, send it on to keyDown. */
5333 -(void)keyUp: (NSEvent *)theEvent
5335   int flags = [theEvent modifierFlags];
5336   int code = [theEvent keyCode];
5337   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5338       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5339     {
5340       if (NS_KEYLOG)
5341         fprintf (stderr, "keyUp: passed test");
5342       ns_fake_keydown = YES;
5343       [self keyDown: theEvent];
5344     }
5346 #endif
5349 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5352 /* <NSTextInput>: called when done composing;
5353    NOTE: also called when we delete over working text, followed immed.
5354          by doCommandBySelector: deleteBackward: */
5355 - (void)insertText: (id)aString
5357   int code;
5358   int len = [(NSString *)aString length];
5359   int i;
5361   if (NS_KEYLOG)
5362     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5363   processingCompose = NO;
5365   if (!emacs_event)
5366     return;
5368   /* first, clear any working text */
5369   if (workingText != nil)
5370     [self deleteWorkingText];
5372   /* now insert the string as keystrokes */
5373   for (i =0; i<len; i++)
5374     {
5375       code = [aString characterAtIndex: i];
5376       /* TODO: still need this? */
5377       if (code == 0x2DC)
5378         code = '~'; /* 0x7E */
5379       if (code != 32) /* Space */
5380         emacs_event->modifiers = 0;
5381       emacs_event->kind
5382         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5383       emacs_event->code = code;
5384       EV_TRAILER ((id)nil);
5385     }
5389 /* <NSTextInput>: inserts display of composing characters */
5390 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5392   NSString *str = [aString respondsToSelector: @selector (string)] ?
5393     [aString string] : aString;
5394   if (NS_KEYLOG)
5395     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5396            str, (unsigned long)[str length],
5397            (unsigned long)selRange.length,
5398            (unsigned long)selRange.location);
5400   if (workingText != nil)
5401     [self deleteWorkingText];
5402   if ([str length] == 0)
5403     return;
5405   if (!emacs_event)
5406     return;
5408   processingCompose = YES;
5409   workingText = [str copy];
5410   ns_working_text = build_string ([workingText UTF8String]);
5412   emacs_event->kind = NS_TEXT_EVENT;
5413   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5414   EV_TRAILER ((id)nil);
5418 /* delete display of composing characters [not in <NSTextInput>] */
5419 - (void)deleteWorkingText
5421   if (workingText == nil)
5422     return;
5423   if (NS_KEYLOG)
5424     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5425   [workingText release];
5426   workingText = nil;
5427   processingCompose = NO;
5429   if (!emacs_event)
5430     return;
5432   emacs_event->kind = NS_TEXT_EVENT;
5433   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5434   EV_TRAILER ((id)nil);
5438 - (BOOL)hasMarkedText
5440   return workingText != nil;
5444 - (NSRange)markedRange
5446   NSRange rng = workingText != nil
5447     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5448   if (NS_KEYLOG)
5449     NSLog (@"markedRange request");
5450   return rng;
5454 - (void)unmarkText
5456   if (NS_KEYLOG)
5457     NSLog (@"unmark (accept) text");
5458   [self deleteWorkingText];
5459   processingCompose = NO;
5463 /* used to position char selection windows, etc. */
5464 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5466   NSRect rect;
5467   NSPoint pt;
5468   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5469   if (NS_KEYLOG)
5470     NSLog (@"firstRectForCharRange request");
5472   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5473   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5474   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5475   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5476                                        +FRAME_LINE_HEIGHT (emacsframe));
5478   pt = [self convertPoint: pt toView: nil];
5479   pt = [[self window] convertBaseToScreen: pt];
5480   rect.origin = pt;
5481   return rect;
5485 - (NSInteger)conversationIdentifier
5487   return (NSInteger)self;
5491 - (void)doCommandBySelector: (SEL)aSelector
5493   if (NS_KEYLOG)
5494     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5496   processingCompose = NO;
5497   if (aSelector == @selector (deleteBackward:))
5498     {
5499       /* happens when user backspaces over an ongoing composition:
5500          throw a 'delete' into the event queue */
5501       if (!emacs_event)
5502         return;
5503       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5504       emacs_event->code = 0xFF08;
5505       EV_TRAILER ((id)nil);
5506     }
5509 - (NSArray *)validAttributesForMarkedText
5511   static NSArray *arr = nil;
5512   if (arr == nil) arr = [NSArray new];
5513  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5514   return arr;
5517 - (NSRange)selectedRange
5519   if (NS_KEYLOG)
5520     NSLog (@"selectedRange request");
5521   return NSMakeRange (NSNotFound, 0);
5524 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5525     GNUSTEP_GUI_MINOR_VERSION > 22
5526 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5527 #else
5528 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5529 #endif
5531   if (NS_KEYLOG)
5532     NSLog (@"characterIndexForPoint request");
5533   return 0;
5536 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5538   static NSAttributedString *str = nil;
5539   if (str == nil) str = [NSAttributedString new];
5540   if (NS_KEYLOG)
5541     NSLog (@"attributedSubstringFromRange request");
5542   return str;
5545 /* End <NSTextInput> impl. */
5546 /*****************************************************************************/
5549 /* This is what happens when the user presses a mouse button.  */
5550 - (void)mouseDown: (NSEvent *)theEvent
5552   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5553   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5555   NSTRACE (mouseDown);
5557   [self deleteWorkingText];
5559   if (!emacs_event)
5560     return;
5562   dpyinfo->last_mouse_frame = emacsframe;
5563   /* appears to be needed to prevent spurious movement events generated on
5564      button clicks */
5565   emacsframe->mouse_moved = 0;
5567   if ([theEvent type] == NSScrollWheel)
5568     {
5569       CGFloat delta = [theEvent deltaY];
5570       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5571       if (delta == 0)
5572         {
5573           delta = [theEvent deltaX];
5574           if (delta == 0)
5575             {
5576               NSTRACE (deltaIsZero);
5577               return;
5578             }
5579           emacs_event->kind = HORIZ_WHEEL_EVENT;
5580         }
5581       else
5582         emacs_event->kind = WHEEL_EVENT;
5584       emacs_event->code = 0;
5585       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5586         ((delta > 0) ? up_modifier : down_modifier);
5587     }
5588   else
5589     {
5590       emacs_event->kind = MOUSE_CLICK_EVENT;
5591       emacs_event->code = EV_BUTTON (theEvent);
5592       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5593                              | EV_UDMODIFIERS (theEvent);
5594     }
5595   XSETINT (emacs_event->x, lrint (p.x));
5596   XSETINT (emacs_event->y, lrint (p.y));
5597   EV_TRAILER (theEvent);
5601 - (void)rightMouseDown: (NSEvent *)theEvent
5603   NSTRACE (rightMouseDown);
5604   [self mouseDown: theEvent];
5608 - (void)otherMouseDown: (NSEvent *)theEvent
5610   NSTRACE (otherMouseDown);
5611   [self mouseDown: theEvent];
5615 - (void)mouseUp: (NSEvent *)theEvent
5617   NSTRACE (mouseUp);
5618   [self mouseDown: theEvent];
5622 - (void)rightMouseUp: (NSEvent *)theEvent
5624   NSTRACE (rightMouseUp);
5625   [self mouseDown: theEvent];
5629 - (void)otherMouseUp: (NSEvent *)theEvent
5631   NSTRACE (otherMouseUp);
5632   [self mouseDown: theEvent];
5636 - (void) scrollWheel: (NSEvent *)theEvent
5638   NSTRACE (scrollWheel);
5639   [self mouseDown: theEvent];
5643 /* Tell emacs the mouse has moved. */
5644 - (void)mouseMoved: (NSEvent *)e
5646   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5647   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5648   Lisp_Object frame;
5649   NSPoint pt;
5651 //  NSTRACE (mouseMoved);
5653   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
5654   pt = [self convertPoint: [e locationInWindow] fromView: nil];
5655   dpyinfo->last_mouse_motion_x = pt.x;
5656   dpyinfo->last_mouse_motion_y = pt.y;
5658   /* update any mouse face */
5659   if (hlinfo->mouse_face_hidden)
5660     {
5661       hlinfo->mouse_face_hidden = 0;
5662       clear_mouse_face (hlinfo);
5663     }
5665   /* tooltip handling */
5666   previous_help_echo_string = help_echo_string;
5667   help_echo_string = Qnil;
5669   if (!NILP (Vmouse_autoselect_window))
5670     {
5671       NSTRACE (mouse_autoselect_window);
5672       static Lisp_Object last_mouse_window;
5673       Lisp_Object window
5674         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
5676       if (WINDOWP (window)
5677           && !EQ (window, last_mouse_window)
5678           && !EQ (window, selected_window)
5679           && (focus_follows_mouse
5680               || (EQ (XWINDOW (window)->frame,
5681                       XWINDOW (selected_window)->frame))))
5682         {
5683           NSTRACE (in_window);
5684           emacs_event->kind = SELECT_WINDOW_EVENT;
5685           emacs_event->frame_or_window = window;
5686           EV_TRAILER2 (e);
5687         }
5688       /* Remember the last window where we saw the mouse.  */
5689       last_mouse_window = window;
5690     }
5692   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
5693     help_echo_string = previous_help_echo_string;
5695   XSETFRAME (frame, emacsframe);
5696   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5697     {
5698       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5699          (note_mouse_highlight), which is called through the
5700          note_mouse_movement () call above */
5701       gen_help_event (help_echo_string, frame, help_echo_window,
5702                       help_echo_object, help_echo_pos);
5703     }
5704   else
5705     {
5706       help_echo_string = Qnil;
5707       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5708     }
5710   if (emacsframe->mouse_moved && send_appdefined)
5711     ns_send_appdefined (-1);
5715 - (void)mouseDragged: (NSEvent *)e
5717   NSTRACE (mouseDragged);
5718   [self mouseMoved: e];
5722 - (void)rightMouseDragged: (NSEvent *)e
5724   NSTRACE (rightMouseDragged);
5725   [self mouseMoved: e];
5729 - (void)otherMouseDragged: (NSEvent *)e
5731   NSTRACE (otherMouseDragged);
5732   [self mouseMoved: e];
5736 - (BOOL)windowShouldClose: (id)sender
5738   NSEvent *e =[[self window] currentEvent];
5740   NSTRACE (windowShouldClose);
5741   windowClosing = YES;
5742   if (!emacs_event)
5743     return NO;
5744   emacs_event->kind = DELETE_WINDOW_EVENT;
5745   emacs_event->modifiers = 0;
5746   emacs_event->code = 0;
5747   EV_TRAILER (e);
5748   /* Don't close this window, let this be done from lisp code.  */
5749   return NO;
5752 - (void) updateFrameSize: (BOOL) delay;
5754   NSWindow *window = [self window];
5755   NSRect wr = [window frame];
5756   int extra = 0;
5757   int oldc = cols, oldr = rows;
5758   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
5759   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5760   int neww, newh;
5762   NSTRACE (updateFrameSize);
5763   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
5765   if (! [self isFullscreen])
5766     {
5767 #ifdef NS_IMPL_GNUSTEP
5768       // GNUstep does not always update the tool bar height.  Force it.
5769       if (toolbar) update_frame_tool_bar (emacsframe);
5770 #endif
5772       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5773         + FRAME_TOOLBAR_HEIGHT (emacsframe);
5774     }
5776   if (wait_for_tool_bar)
5777     {
5778       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
5779         return;
5780       wait_for_tool_bar = NO;
5781     }
5783   neww = (int)wr.size.width - emacsframe->border_width;
5784   newh = (int)wr.size.height - extra;
5786   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
5787   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
5789   if (cols < MINWIDTH)
5790     cols = MINWIDTH;
5792   if (rows < MINHEIGHT)
5793     rows = MINHEIGHT;
5795   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5796     {
5797       NSView *view = FRAME_NS_VIEW (emacsframe);
5798       NSWindow *win = [view window];
5799       NSSize sz = [win resizeIncrements];
5801       change_frame_size (emacsframe,
5802                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
5803                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
5804                          0, delay, 0, 1);
5805       SET_FRAME_GARBAGED (emacsframe);
5806       cancel_mouse_face (emacsframe);
5808       // Did resize increments change because of a font change?
5809       if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5810           sz.height != FRAME_LINE_HEIGHT (emacsframe) ||
5811           (frame_resize_pixelwise && sz.width != 1))
5812         {
5813           sz.width = frame_resize_pixelwise
5814             ? 1 : FRAME_COLUMN_WIDTH (emacsframe);
5815           sz.height = frame_resize_pixelwise
5816             ? 1 : FRAME_LINE_HEIGHT (emacsframe);
5817           [win setResizeIncrements: sz];
5819           NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
5820         }
5822       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5823       [self windowDidMove:nil];   // Update top/left.
5824     }
5827 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5828 /* normalize frame to gridded text size */
5830   int extra = 0;
5832   NSTRACE (windowWillResize);
5833   NSTRACE_SIZE ("Original size", frameSize);
5834 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5836   if (fs_state == FULLSCREEN_MAXIMIZED
5837       && (maximized_width != (int)frameSize.width
5838           || maximized_height != (int)frameSize.height))
5839     [self setFSValue: FULLSCREEN_NONE];
5840   else if (fs_state == FULLSCREEN_WIDTH
5841            && maximized_width != (int)frameSize.width)
5842     [self setFSValue: FULLSCREEN_NONE];
5843   else if (fs_state == FULLSCREEN_HEIGHT
5844            && maximized_height != (int)frameSize.height)
5845     [self setFSValue: FULLSCREEN_NONE];
5846   if (fs_state == FULLSCREEN_NONE)
5847     maximized_width = maximized_height = -1;
5849   if (! [self isFullscreen])
5850     {
5851       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5852         + FRAME_TOOLBAR_HEIGHT (emacsframe);
5853     }
5855   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
5856   if (cols < MINWIDTH)
5857     cols = MINWIDTH;
5859   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5860                                            frameSize.height - extra);
5861   if (rows < MINHEIGHT)
5862     rows = MINHEIGHT;
5863 #ifdef NS_IMPL_COCOA
5864   {
5865     /* this sets window title to have size in it; the wm does this under GS */
5866     NSRect r = [[self window] frame];
5867     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5868       {
5869         if (old_title != 0)
5870           {
5871             xfree (old_title);
5872             old_title = 0;
5873           }
5874       }
5875     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5876       {
5877         char *size_title;
5878         NSWindow *window = [self window];
5879         if (old_title == 0)
5880           {
5881             char *t = strdup ([[[self window] title] UTF8String]);
5882             char *pos = strstr (t, "  â€”  ");
5883             if (pos)
5884               *pos = '\0';
5885             old_title = t;
5886           }
5887         size_title = xmalloc (strlen (old_title) + 40);
5888         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5889         [window setTitle: [NSString stringWithUTF8String: size_title]];
5890         [window display];
5891         xfree (size_title);
5892       }
5893   }
5894 #endif /* NS_IMPL_COCOA */
5895 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5897   return frameSize;
5901 - (void)windowDidResize: (NSNotification *)notification
5903   if (! [self fsIsNative])
5904     {
5905       NSWindow *theWindow = [notification object];
5906       /* We can get notification on the non-FS window when in
5907          fullscreen mode.  */
5908       if ([self window] != theWindow) return;
5909     }
5911 #ifdef NS_IMPL_GNUSTEP
5912   NSWindow *theWindow = [notification object];
5914    /* In GNUstep, at least currently, it's possible to get a didResize
5915       without getting a willResize.. therefore we need to act as if we got
5916       the willResize now */
5917   NSSize sz = [theWindow frame].size;
5918   sz = [self windowWillResize: theWindow toSize: sz];
5919 #endif /* NS_IMPL_GNUSTEP */
5921   NSTRACE (windowDidResize);
5922 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5924 if (cols > 0 && rows > 0)
5925     {
5926       [self updateFrameSize: YES];
5927     }
5929   ns_send_appdefined (-1);
5932 #ifdef NS_IMPL_COCOA
5933 - (void)viewDidEndLiveResize
5935   [super viewDidEndLiveResize];
5936   if (old_title != 0)
5937     {
5938       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
5939       xfree (old_title);
5940       old_title = 0;
5941     }
5942   maximizing_resize = NO;
5944 #endif /* NS_IMPL_COCOA */
5947 - (void)windowDidBecomeKey: (NSNotification *)notification
5948 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5950   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5951   struct frame *old_focus = dpyinfo->x_focus_frame;
5953   NSTRACE (windowDidBecomeKey);
5955   if (emacsframe != old_focus)
5956     dpyinfo->x_focus_frame = emacsframe;
5958   ns_frame_rehighlight (emacsframe);
5960   if (emacs_event)
5961     {
5962       emacs_event->kind = FOCUS_IN_EVENT;
5963       EV_TRAILER ((id)nil);
5964     }
5968 - (void)windowDidResignKey: (NSNotification *)notification
5969 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5971   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5972   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
5973   NSTRACE (windowDidResignKey);
5975   if (is_focus_frame)
5976     dpyinfo->x_focus_frame = 0;
5978   emacsframe->mouse_moved = 0;
5979   ns_frame_rehighlight (emacsframe);
5981   /* FIXME: for some reason needed on second and subsequent clicks away
5982             from sole-frame Emacs to get hollow box to show */
5983   if (!windowClosing && [[self window] isVisible] == YES)
5984     {
5985       x_update_cursor (emacsframe, 1);
5986       x_set_frame_alpha (emacsframe);
5987     }
5989   if (emacs_event && is_focus_frame)
5990     {
5991       [self deleteWorkingText];
5992       emacs_event->kind = FOCUS_OUT_EVENT;
5993       EV_TRAILER ((id)nil);
5994     }
5998 - (void)windowWillMiniaturize: sender
6000   NSTRACE (windowWillMiniaturize);
6004 - (BOOL)isFlipped
6006   return YES;
6010 - (BOOL)isOpaque
6012   return NO;
6016 - initFrameFromEmacs: (struct frame *)f
6018   NSRect r, wr;
6019   Lisp_Object tem;
6020   NSWindow *win;
6021   NSSize sz;
6022   NSColor *col;
6023   NSString *name;
6025   NSTRACE (initFrameFromEmacs);
6027   windowClosing = NO;
6028   processingCompose = NO;
6029   scrollbarsNeedingUpdate = 0;
6030   fs_state = FULLSCREEN_NONE;
6031   fs_before_fs = next_maximized = -1;
6032 #ifdef HAVE_NATIVE_FS
6033   fs_is_native = ns_use_native_fullscreen;
6034 #else
6035   fs_is_native = NO;
6036 #endif
6037   maximized_width = maximized_height = -1;
6038   nonfs_window = nil;
6040 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
6042   ns_userRect = NSMakeRect (0, 0, 0, 0);
6043   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6044                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6045   [self initWithFrame: r];
6046   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6048   FRAME_NS_VIEW (f) = self;
6049   emacsframe = f;
6050 #ifdef NS_IMPL_COCOA
6051   old_title = 0;
6052   maximizing_resize = NO;
6053 #endif
6055   win = [[EmacsWindow alloc]
6056             initWithContentRect: r
6057                       styleMask: (NSResizableWindowMask |
6058 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6059                                   NSTitledWindowMask |
6060 #endif
6061                                   NSMiniaturizableWindowMask |
6062                                   NSClosableWindowMask)
6063                         backing: NSBackingStoreBuffered
6064                           defer: YES];
6066 #ifdef HAVE_NATIVE_FS
6067     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6068 #endif
6070   wr = [win frame];
6071   bwidth = f->border_width = wr.size.width - r.size.width;
6072   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6074   [win setAcceptsMouseMovedEvents: YES];
6075   [win setDelegate: self];
6076   [win useOptimizedDrawing: YES];
6078   sz.width = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
6079   sz.height = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
6080   [win setResizeIncrements: sz];
6082   [[win contentView] addSubview: self];
6084   if (ns_drag_types)
6085     [self registerForDraggedTypes: ns_drag_types];
6087   tem = f->name;
6088   name = [NSString stringWithUTF8String:
6089                    NILP (tem) ? "Emacs" : SSDATA (tem)];
6090   [win setTitle: name];
6092   /* toolbar support */
6093   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6094                          [NSString stringWithFormat: @"Emacs Frame %d",
6095                                    ns_window_num]];
6096   [win setToolbar: toolbar];
6097   [toolbar setVisible: NO];
6099   /* Don't set frame garbaged until tool bar is up to date?
6100      This avoids an extra clear and redraw (flicker) at frame creation.  */
6101   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6102   else wait_for_tool_bar = NO;
6105 #ifdef NS_IMPL_COCOA
6106   {
6107     NSButton *toggleButton;
6108   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6109   [toggleButton setTarget: self];
6110   [toggleButton setAction: @selector (toggleToolbar: )];
6111   }
6112 #endif
6113   FRAME_TOOLBAR_HEIGHT (f) = 0;
6115   tem = f->icon_name;
6116   if (!NILP (tem))
6117     [win setMiniwindowTitle:
6118            [NSString stringWithUTF8String: SSDATA (tem)]];
6120   {
6121     NSScreen *screen = [win screen];
6123     if (screen != 0)
6124       [win setFrameTopLeftPoint: NSMakePoint
6125            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6126             IN_BOUND (-SCREENMAX,
6127                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
6128   }
6130   [win makeFirstResponder: self];
6132   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6133                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6134   [win setBackgroundColor: col];
6135   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6136     [win setOpaque: NO];
6138   [self allocateGState];
6140   [NSApp registerServicesMenuSendTypes: ns_send_types
6141                            returnTypes: nil];
6143   ns_window_num++;
6144   return self;
6148 - (void)windowDidMove: sender
6150   NSWindow *win = [self window];
6151   NSRect r = [win frame];
6152   NSArray *screens = [NSScreen screens];
6153   NSScreen *screen = [screens objectAtIndex: 0];
6155   NSTRACE (windowDidMove);
6157   if (!emacsframe->output_data.ns)
6158     return;
6159   if (screen != nil)
6160     {
6161       emacsframe->left_pos = r.origin.x;
6162       emacsframe->top_pos =
6163         [screen frame].size.height - (r.origin.y + r.size.height);
6164     }
6168 /* Called AFTER method below, but before our windowWillResize call there leads
6169    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
6170    location so set_window_size moves the frame. */
6171 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6173   emacsframe->output_data.ns->zooming = 1;
6174   return YES;
6178 /* Override to do something slightly nonstandard, but nice.  First click on
6179    zoom button will zoom vertically.  Second will zoom completely.  Third
6180    returns to original. */
6181 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6182                         defaultFrame:(NSRect)defaultFrame
6184   NSRect result = [sender frame];
6186   NSTRACE (windowWillUseStandardFrame);
6188   if (fs_before_fs != -1) /* Entering fullscreen */
6189       {
6190         result = defaultFrame;
6191       }
6192   else if (next_maximized == FULLSCREEN_HEIGHT
6193       || (next_maximized == -1
6194           && abs (defaultFrame.size.height - result.size.height)
6195           > FRAME_LINE_HEIGHT (emacsframe)))
6196     {
6197       /* first click */
6198       ns_userRect = result;
6199       maximized_height = result.size.height = defaultFrame.size.height;
6200       maximized_width = -1;
6201       result.origin.y = defaultFrame.origin.y;
6202       [self setFSValue: FULLSCREEN_HEIGHT];
6203 #ifdef NS_IMPL_COCOA
6204       maximizing_resize = YES;
6205 #endif
6206     }
6207   else if (next_maximized == FULLSCREEN_WIDTH)
6208     {
6209       ns_userRect = result;
6210       maximized_width = result.size.width = defaultFrame.size.width;
6211       maximized_height = -1;
6212       result.origin.x = defaultFrame.origin.x;
6213       [self setFSValue: FULLSCREEN_WIDTH];
6214     }
6215   else if (next_maximized == FULLSCREEN_MAXIMIZED
6216            || (next_maximized == -1
6217                && abs (defaultFrame.size.width - result.size.width)
6218                > FRAME_COLUMN_WIDTH (emacsframe)))
6219     {
6220       result = defaultFrame;  /* second click */
6221       maximized_width = result.size.width;
6222       maximized_height = result.size.height;
6223       [self setFSValue: FULLSCREEN_MAXIMIZED];
6224 #ifdef NS_IMPL_COCOA
6225       maximizing_resize = YES;
6226 #endif
6227     }
6228   else
6229     {
6230       /* restore */
6231       result = ns_userRect.size.height ? ns_userRect : result;
6232       ns_userRect = NSMakeRect (0, 0, 0, 0);
6233 #ifdef NS_IMPL_COCOA
6234       maximizing_resize = fs_state != FULLSCREEN_NONE;
6235 #endif
6236       [self setFSValue: FULLSCREEN_NONE];
6237       maximized_width = maximized_height = -1;
6238     }
6240   if (fs_before_fs == -1) next_maximized = -1;
6241   [self windowWillResize: sender toSize: result.size];
6242   return result;
6246 - (void)windowDidDeminiaturize: sender
6248   NSTRACE (windowDidDeminiaturize);
6249   if (!emacsframe->output_data.ns)
6250     return;
6252   SET_FRAME_ICONIFIED (emacsframe, 0);
6253   SET_FRAME_VISIBLE (emacsframe, 1);
6254   windows_or_buffers_changed = 63;
6256   if (emacs_event)
6257     {
6258       emacs_event->kind = DEICONIFY_EVENT;
6259       EV_TRAILER ((id)nil);
6260     }
6264 - (void)windowDidExpose: sender
6266   NSTRACE (windowDidExpose);
6267   if (!emacsframe->output_data.ns)
6268     return;
6270   SET_FRAME_VISIBLE (emacsframe, 1);
6271   SET_FRAME_GARBAGED (emacsframe);
6273   if (send_appdefined)
6274     ns_send_appdefined (-1);
6278 - (void)windowDidMiniaturize: sender
6280   NSTRACE (windowDidMiniaturize);
6281   if (!emacsframe->output_data.ns)
6282     return;
6284   SET_FRAME_ICONIFIED (emacsframe, 1);
6285   SET_FRAME_VISIBLE (emacsframe, 0);
6287   if (emacs_event)
6288     {
6289       emacs_event->kind = ICONIFY_EVENT;
6290       EV_TRAILER ((id)nil);
6291     }
6294 #ifdef HAVE_NATIVE_FS
6295 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6296       willUseFullScreenPresentationOptions:
6297   (NSApplicationPresentationOptions)proposedOptions
6299   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6301 #endif
6303 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6305   fs_before_fs = fs_state;
6308 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6310   [self setFSValue: FULLSCREEN_BOTH];
6311   if (! [self fsIsNative])
6312     {
6313       [self windowDidBecomeKey:notification];
6314       [nonfs_window orderOut:self];
6315     }
6316   else
6317     {
6318       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
6319 #ifdef NS_IMPL_COCOA
6320 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6321       unsigned val = (unsigned)[NSApp presentationOptions];
6323       // OSX 10.7 bug fix, the menu won't appear without this.
6324       // val is non-zero on other OSX versions.
6325       if (val == 0)
6326         {
6327           NSApplicationPresentationOptions options
6328             = NSApplicationPresentationAutoHideDock
6329             | NSApplicationPresentationAutoHideMenuBar
6330             | NSApplicationPresentationFullScreen
6331             | NSApplicationPresentationAutoHideToolbar;
6333           [NSApp setPresentationOptions: options];
6334         }
6335 #endif
6336 #endif
6337       [toolbar setVisible:tbar_visible];
6338     }
6341 - (void)windowWillExitFullScreen:(NSNotification *)notification
6343   if (next_maximized != -1)
6344     fs_before_fs = next_maximized;
6347 - (void)windowDidExitFullScreen:(NSNotification *)notification
6349   [self setFSValue: fs_before_fs];
6350   fs_before_fs = -1;
6351 #ifdef HAVE_NATIVE_FS
6352   [self updateCollectionBehavior];
6353 #endif
6354   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6355     {
6356       [toolbar setVisible:YES];
6357       update_frame_tool_bar (emacsframe);
6358       [self updateFrameSize:YES];
6359       [[self window] display];
6360     }
6361   else
6362     [toolbar setVisible:NO];
6364   if (next_maximized != -1)
6365     [[self window] performZoom:self];
6368 - (BOOL)fsIsNative
6370   return fs_is_native;
6373 - (BOOL)isFullscreen
6375   if (! fs_is_native) return nonfs_window != nil;
6376 #ifdef HAVE_NATIVE_FS
6377   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6378 #else
6379   return NO;
6380 #endif
6383 #ifdef HAVE_NATIVE_FS
6384 - (void)updateCollectionBehavior
6386   if (! [self isFullscreen])
6387     {
6388       NSWindow *win = [self window];
6389       NSWindowCollectionBehavior b = [win collectionBehavior];
6390       if (ns_use_native_fullscreen)
6391         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6392       else
6393         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6395       [win setCollectionBehavior: b];
6396       fs_is_native = ns_use_native_fullscreen;
6397     }
6399 #endif
6401 - (void)toggleFullScreen: (id)sender
6403   NSWindow *w, *fw;
6404   BOOL onFirstScreen;
6405   struct frame *f;
6406   NSSize sz;
6407   NSRect r, wr;
6408   NSColor *col;
6410   if (fs_is_native)
6411     {
6412 #ifdef HAVE_NATIVE_FS
6413       [[self window] toggleFullScreen:sender];
6414 #endif
6415       return;
6416     }
6418   w = [self window];
6419   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6420   f = emacsframe;
6421   wr = [w frame];
6422   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6423                                  (FRAME_DEFAULT_FACE (f)),
6424                                  f);
6426   sz.width = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
6427   sz.height = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
6429   if (fs_state != FULLSCREEN_BOTH)
6430     {
6431       NSScreen *screen = [w screen];
6433 #if defined (NS_IMPL_COCOA) && \
6434   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
6435       /* Hide ghost menu bar on secondary monitor? */
6436       if (! onFirstScreen)
6437         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
6438 #endif
6439       /* Hide dock and menubar if we are on the primary screen.  */
6440       if (onFirstScreen)
6441         {
6442 #if defined (NS_IMPL_COCOA) && \
6443   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6444           NSApplicationPresentationOptions options
6445             = NSApplicationPresentationAutoHideDock
6446             | NSApplicationPresentationAutoHideMenuBar;
6448           [NSApp setPresentationOptions: options];
6449 #else
6450           [NSMenu setMenuBarVisible:NO];
6451 #endif
6452         }
6454       fw = [[EmacsFSWindow alloc]
6455                        initWithContentRect:[w contentRectForFrameRect:wr]
6456                                  styleMask:NSBorderlessWindowMask
6457                                    backing:NSBackingStoreBuffered
6458                                      defer:YES
6459                                     screen:screen];
6461       [fw setContentView:[w contentView]];
6462       [fw setTitle:[w title]];
6463       [fw setDelegate:self];
6464       [fw setAcceptsMouseMovedEvents: YES];
6465       [fw useOptimizedDrawing: YES];
6466       [fw setResizeIncrements: sz];
6467       [fw setBackgroundColor: col];
6468       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6469         [fw setOpaque: NO];
6471       f->border_width = 0;
6472       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6473       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6474       FRAME_TOOLBAR_HEIGHT (f) = 0;
6476       nonfs_window = w;
6478       [self windowWillEnterFullScreen:nil];
6479       [fw makeKeyAndOrderFront:NSApp];
6480       [fw makeFirstResponder:self];
6481       [w orderOut:self];
6482       r = [fw frameRectForContentRect:[screen frame]];
6483       [fw setFrame: r display:YES animate:YES];
6484       [self windowDidEnterFullScreen:nil];
6485       [fw display];
6486     }
6487   else
6488     {
6489       fw = w;
6490       w = nonfs_window;
6491       nonfs_window = nil;
6493       if (onFirstScreen)
6494         {
6495 #if defined (NS_IMPL_COCOA) && \
6496   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6497           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6498 #else
6499           [NSMenu setMenuBarVisible:YES];
6500 #endif
6501         }
6503       [w setContentView:[fw contentView]];
6504       [w setResizeIncrements: sz];
6505       [w setBackgroundColor: col];
6506       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6507         [w setOpaque: NO];
6509       f->border_width = bwidth;
6510       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6511       if (FRAME_EXTERNAL_TOOL_BAR (f))
6512         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6514       [self windowWillExitFullScreen:nil];
6515       [fw setFrame: [w frame] display:YES animate:YES];
6516       [fw close];
6517       [w makeKeyAndOrderFront:NSApp];
6518       [self windowDidExitFullScreen:nil];
6519       [self updateFrameSize:YES];
6520     }
6523 - (void)handleFS
6525   if (fs_state != emacsframe->want_fullscreen)
6526     {
6527       if (fs_state == FULLSCREEN_BOTH)
6528         {
6529           [self toggleFullScreen:self];
6530         }
6532       switch (emacsframe->want_fullscreen)
6533         {
6534         case FULLSCREEN_BOTH:
6535           [self toggleFullScreen:self];
6536           break;
6537         case FULLSCREEN_WIDTH:
6538           next_maximized = FULLSCREEN_WIDTH;
6539           if (fs_state != FULLSCREEN_BOTH)
6540             [[self window] performZoom:self];
6541           break;
6542         case FULLSCREEN_HEIGHT:
6543           next_maximized = FULLSCREEN_HEIGHT;
6544           if (fs_state != FULLSCREEN_BOTH)
6545             [[self window] performZoom:self];
6546           break;
6547         case FULLSCREEN_MAXIMIZED:
6548           next_maximized = FULLSCREEN_MAXIMIZED;
6549           if (fs_state != FULLSCREEN_BOTH)
6550             [[self window] performZoom:self];
6551           break;
6552         case FULLSCREEN_NONE:
6553           if (fs_state != FULLSCREEN_BOTH)
6554             {
6555               next_maximized = FULLSCREEN_NONE;
6556               [[self window] performZoom:self];
6557             }
6558           break;
6559         }
6561       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6562     }
6566 - (void) setFSValue: (int)value
6568   Lisp_Object lval = Qnil;
6569   switch (value)
6570     {
6571     case FULLSCREEN_BOTH:
6572       lval = Qfullboth;
6573       break;
6574     case FULLSCREEN_WIDTH:
6575       lval = Qfullwidth;
6576       break;
6577     case FULLSCREEN_HEIGHT:
6578       lval = Qfullheight;
6579       break;
6580     case FULLSCREEN_MAXIMIZED:
6581       lval = Qmaximized;
6582       break;
6583     }
6584   store_frame_param (emacsframe, Qfullscreen, lval);
6585   fs_state = value;
6588 - (void)mouseEntered: (NSEvent *)theEvent
6590   NSTRACE (mouseEntered);
6591   if (emacsframe)
6592     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6593       = EV_TIMESTAMP (theEvent);
6597 - (void)mouseExited: (NSEvent *)theEvent
6599   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6601   NSTRACE (mouseExited);
6603   if (!hlinfo)
6604     return;
6606   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6607     = EV_TIMESTAMP (theEvent);
6609   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6610     {
6611       clear_mouse_face (hlinfo);
6612       hlinfo->mouse_face_mouse_frame = 0;
6613     }
6617 - menuDown: sender
6619   NSTRACE (menuDown);
6620   if (context_menu_value == -1)
6621     context_menu_value = [sender tag];
6622   else
6623     {
6624       NSInteger tag = [sender tag];
6625       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6626                                     emacsframe->menu_bar_vector,
6627                                     (void *)tag);
6628     }
6630   ns_send_appdefined (-1);
6631   return self;
6635 - (EmacsToolbar *)toolbar
6637   return toolbar;
6641 /* this gets called on toolbar button click */
6642 - toolbarClicked: (id)item
6644   NSEvent *theEvent;
6645   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6647   NSTRACE (toolbarClicked);
6649   if (!emacs_event)
6650     return self;
6652   /* send first event (for some reason two needed) */
6653   theEvent = [[self window] currentEvent];
6654   emacs_event->kind = TOOL_BAR_EVENT;
6655   XSETFRAME (emacs_event->arg, emacsframe);
6656   EV_TRAILER (theEvent);
6658   emacs_event->kind = TOOL_BAR_EVENT;
6659 /*   XSETINT (emacs_event->code, 0); */
6660   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6661                            idx + TOOL_BAR_ITEM_KEY);
6662   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6663   EV_TRAILER (theEvent);
6664   return self;
6668 - toggleToolbar: (id)sender
6670   if (!emacs_event)
6671     return self;
6673   emacs_event->kind = NS_NONKEY_EVENT;
6674   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6675   EV_TRAILER ((id)nil);
6676   return self;
6680 - (void)drawRect: (NSRect)rect
6682   int x = NSMinX (rect), y = NSMinY (rect);
6683   int width = NSWidth (rect), height = NSHeight (rect);
6685   NSTRACE (drawRect);
6687   if (!emacsframe || !emacsframe->output_data.ns)
6688     return;
6690   ns_clear_frame_area (emacsframe, x, y, width, height);
6691   expose_frame (emacsframe, x, y, width, height);
6693   /*
6694     drawRect: may be called (at least in OS X 10.5) for invisible
6695     views as well for some reason.  Thus, do not infer visibility
6696     here.
6698     emacsframe->async_visible = 1;
6699     emacsframe->async_iconified = 0;
6700   */
6704 /* NSDraggingDestination protocol methods.  Actually this is not really a
6705    protocol, but a category of Object.  O well...  */
6707 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6709   NSTRACE (draggingEntered);
6710   return NSDragOperationGeneric;
6714 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6716   return YES;
6720 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6722   id pb;
6723   int x, y;
6724   NSString *type;
6725   NSEvent *theEvent = [[self window] currentEvent];
6726   NSPoint position;
6727   NSDragOperation op = [sender draggingSourceOperationMask];
6728   int modifiers = 0;
6730   NSTRACE (performDragOperation);
6732   if (!emacs_event)
6733     return NO;
6735   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6736   x = lrint (position.x);  y = lrint (position.y);
6738   pb = [sender draggingPasteboard];
6739   type = [pb availableTypeFromArray: ns_drag_types];
6741   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
6742       // URL drags contain all operations (0xf), don't allow all to be set.
6743       (op & 0xf) != 0xf)
6744     {
6745       if (op & NSDragOperationLink)
6746         modifiers |= NSControlKeyMask;
6747       if (op & NSDragOperationCopy)
6748         modifiers |= NSAlternateKeyMask;
6749       if (op & NSDragOperationGeneric)
6750         modifiers |= NSCommandKeyMask;
6751     }
6753   modifiers = EV_MODIFIERS2 (modifiers);
6754   if (type == 0)
6755     {
6756       return NO;
6757     }
6758   else if ([type isEqualToString: NSFilenamesPboardType])
6759     {
6760       NSArray *files;
6761       NSEnumerator *fenum;
6762       NSString *file;
6764       if (!(files = [pb propertyListForType: type]))
6765         return NO;
6767       fenum = [files objectEnumerator];
6768       while ( (file = [fenum nextObject]) )
6769         {
6770           emacs_event->kind = DRAG_N_DROP_EVENT;
6771           XSETINT (emacs_event->x, x);
6772           XSETINT (emacs_event->y, y);
6773           ns_input_file = append2 (ns_input_file,
6774                                    build_string ([file UTF8String]));
6775           emacs_event->modifiers = modifiers;
6776           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
6777           EV_TRAILER (theEvent);
6778         }
6779       return YES;
6780     }
6781   else if ([type isEqualToString: NSURLPboardType])
6782     {
6783       NSURL *url = [NSURL URLFromPasteboard: pb];
6784       if (url == nil) return NO;
6786       emacs_event->kind = DRAG_N_DROP_EVENT;
6787       XSETINT (emacs_event->x, x);
6788       XSETINT (emacs_event->y, y);
6789       emacs_event->modifiers = modifiers;
6790       emacs_event->arg =  list2 (Qurl,
6791                                  build_string ([[url absoluteString]
6792                                                  UTF8String]));
6793       EV_TRAILER (theEvent);
6795       if ([url isFileURL] != NO)
6796         {
6797           NSString *file = [url path];
6798           ns_input_file = append2 (ns_input_file,
6799                                    build_string ([file UTF8String]));
6800         }
6801       return YES;
6802     }
6803   else if ([type isEqualToString: NSStringPboardType]
6804            || [type isEqualToString: NSTabularTextPboardType])
6805     {
6806       NSString *data;
6808       if (! (data = [pb stringForType: type]))
6809         return NO;
6811       emacs_event->kind = DRAG_N_DROP_EVENT;
6812       XSETINT (emacs_event->x, x);
6813       XSETINT (emacs_event->y, y);
6814       emacs_event->modifiers = modifiers;
6815       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
6816       EV_TRAILER (theEvent);
6817       return YES;
6818     }
6819   else
6820     {
6821       error ("Invalid data type in dragging pasteboard");
6822       return NO;
6823     }
6827 - (id) validRequestorForSendType: (NSString *)typeSent
6828                       returnType: (NSString *)typeReturned
6830   NSTRACE (validRequestorForSendType);
6831   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6832       && typeReturned == nil)
6833     {
6834       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6835         return self;
6836     }
6838   return [super validRequestorForSendType: typeSent
6839                                returnType: typeReturned];
6843 /* The next two methods are part of NSServicesRequests informal protocol,
6844    supposedly called when a services menu item is chosen from this app.
6845    But this should not happen because we override the services menu with our
6846    own entries which call ns-perform-service.
6847    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6848    So let's at least stub them out until further investigation can be done. */
6850 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6852   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6853      be written into the buffer in place of the existing selection..
6854      ordinary service calls go through functions defined in ns-win.el */
6855   return NO;
6858 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6860   NSArray *typesDeclared;
6861   Lisp_Object val;
6863   /* We only support NSStringPboardType */
6864   if ([types containsObject:NSStringPboardType] == NO) {
6865     return NO;
6866   }
6868   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6869   if (CONSP (val) && SYMBOLP (XCAR (val)))
6870     {
6871       val = XCDR (val);
6872       if (CONSP (val) && NILP (XCDR (val)))
6873         val = XCAR (val);
6874     }
6875   if (! STRINGP (val))
6876     return NO;
6878   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6879   [pb declareTypes:typesDeclared owner:nil];
6880   ns_string_to_pasteboard (pb, val);
6881   return YES;
6885 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6886    (gives a miniaturized version of the window); currently we use the latter for
6887    frames whose active buffer doesn't correspond to any file
6888    (e.g., '*scratch*') */
6889 - setMiniwindowImage: (BOOL) setMini
6891   id image = [[self window] miniwindowImage];
6892   NSTRACE (setMiniwindowImage);
6894   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6895      about "AppleDockIconEnabled" notwithstanding, however the set message
6896      below has its effect nonetheless. */
6897   if (image != emacsframe->output_data.ns->miniimage)
6898     {
6899       if (image && [image isKindOfClass: [EmacsImage class]])
6900         [image release];
6901       [[self window] setMiniwindowImage:
6902                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6903     }
6905   return self;
6909 - (void) setRows: (int) r andColumns: (int) c
6911   rows = r;
6912   cols = c;
6915 @end  /* EmacsView */
6919 /* ==========================================================================
6921     EmacsWindow implementation
6923    ========================================================================== */
6925 @implementation EmacsWindow
6927 #ifdef NS_IMPL_COCOA
6928 - (id)accessibilityAttributeValue:(NSString *)attribute
6930   Lisp_Object str = Qnil;
6931   struct frame *f = SELECTED_FRAME ();
6932   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
6934   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6935     return NSAccessibilityTextFieldRole;
6937   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6938       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6939     {
6940       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6941     }
6942   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6943     {
6944       if (! NILP (BVAR (curbuf, mark_active)))
6945           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6947       if (NILP (str))
6948         {
6949           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6950           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6951           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6953           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6954             str = make_uninit_multibyte_string (range, byte_range);
6955           else
6956             str = make_uninit_string (range);
6957           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6958              Is this a problem?  */
6959           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6960         }
6961     }
6964   if (! NILP (str))
6965     {
6966       if (CONSP (str) && SYMBOLP (XCAR (str)))
6967         {
6968           str = XCDR (str);
6969           if (CONSP (str) && NILP (XCDR (str)))
6970             str = XCAR (str);
6971         }
6972       if (STRINGP (str))
6973         {
6974           const char *utfStr = SSDATA (str);
6975           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6976           return nsStr;
6977         }
6978     }
6980   return [super accessibilityAttributeValue:attribute];
6982 #endif /* NS_IMPL_COCOA */
6984 /* If we have multiple monitors, one above the other, we don't want to
6985    restrict the height to just one monitor.  So we override this.  */
6986 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6988   /* When making the frame visible for the first time or if there is just
6989      one screen, we want to constrain.  Other times not.  */
6990   NSArray *screens = [NSScreen screens];
6991   NSUInteger nr_screens = [screens count], nr_eff_screens = 0, i;
6992   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6993   NSTRACE (constrainFrameRect);
6994   NSTRACE_RECT ("input", frameRect);
6996   if (ns_menu_bar_should_be_hidden ())
6997     return frameRect;
6999   if (nr_screens == 1)
7000     return [super constrainFrameRect:frameRect toScreen:screen];
7002 #ifdef NS_IMPL_COCOA
7003 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7004   // If separate spaces is on, it is like each screen is independent.  There is
7005   // no spanning of frames across screens.
7006   if ([NSScreen screensHaveSeparateSpaces])
7007     return [super constrainFrameRect:frameRect toScreen:screen];
7008 #endif
7009 #endif
7011   for (i = 0; i < nr_screens; ++i) 
7012     {
7013       NSScreen *s = [screens objectAtIndex: i];
7014       NSRect scrrect = [s frame];
7015       NSRect intersect = NSIntersectionRect (frameRect, scrrect);
7017       if (intersect.size.width > 0 || intersect.size.height > 0)
7018         ++nr_eff_screens;
7019     }
7021   if (nr_eff_screens == 1)
7022     return [super constrainFrameRect:frameRect toScreen:screen];
7023   
7024   /* The default implementation does two things 1) ensure that the top
7025      of the rectangle is below the menu bar (or below the top of the
7026      screen) and 2) resizes windows larger than the screen. As we
7027      don't want the latter, a smaller rectangle is used. */
7028 #define FAKE_HEIGHT 64
7029   float old_top = frameRect.origin.y + frameRect.size.height;
7030   NSRect r;
7031   r.size.height = FAKE_HEIGHT;
7032   r.size.width = frameRect.size.width;
7033   r.origin.x = frameRect.origin.x;
7034   r.origin.y = old_top - FAKE_HEIGHT;
7036   NSTRACE_RECT ("input to super", r);
7038   r = [super constrainFrameRect:r toScreen:screen];
7040   NSTRACE_RECT ("output from super", r);
7042   float new_top = r.origin.y + FAKE_HEIGHT;
7043   if (new_top < old_top)
7044   {
7045     frameRect.origin.y = new_top - frameRect.size.height;
7046   }
7048   NSTRACE_RECT ("output", frameRect);
7050   return frameRect;
7051 #undef FAKE_HEIGHT
7054 @end /* EmacsWindow */
7057 @implementation EmacsFSWindow
7059 - (BOOL)canBecomeKeyWindow
7061   return YES;
7064 - (BOOL)canBecomeMainWindow
7066   return YES;
7069 @end
7071 /* ==========================================================================
7073     EmacsScroller implementation
7075    ========================================================================== */
7078 @implementation EmacsScroller
7080 /* for repeat button push */
7081 #define SCROLL_BAR_FIRST_DELAY 0.5
7082 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
7084 + (CGFloat) scrollerWidth
7086   /* TODO: if we want to allow variable widths, this is the place to do it,
7087            however neither GNUstep nor Cocoa support it very well */
7088   return [NSScroller scrollerWidth];
7092 - initFrame: (NSRect )r window: (Lisp_Object)nwin
7094   NSTRACE (EmacsScroller_initFrame);
7096   r.size.width = [EmacsScroller scrollerWidth];
7097   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
7098   [self setContinuous: YES];
7099   [self setEnabled: YES];
7101   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
7102      locked against the top and bottom edges, and right edge on OS X, where
7103      scrollers are on right. */
7104 #ifdef NS_IMPL_GNUSTEP
7105   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
7106 #else
7107   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
7108 #endif
7110   window = XWINDOW (nwin);
7111   condemned = NO;
7112   pixel_height = NSHeight (r);
7113   if (pixel_height == 0) pixel_height = 1;
7114   min_portion = 20 / pixel_height;
7116   frame = XFRAME (window->frame);
7117   if (FRAME_LIVE_P (frame))
7118     {
7119       int i;
7120       EmacsView *view = FRAME_NS_VIEW (frame);
7121       NSView *sview = [[view window] contentView];
7122       NSArray *subs = [sview subviews];
7124       /* disable optimization stopping redraw of other scrollbars */
7125       view->scrollbarsNeedingUpdate = 0;
7126       for (i =[subs count]-1; i >= 0; i--)
7127         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
7128           view->scrollbarsNeedingUpdate++;
7129       [sview addSubview: self];
7130     }
7132 /*  [self setFrame: r]; */
7134   return self;
7138 - (void)setFrame: (NSRect)newRect
7140   NSTRACE (EmacsScroller_setFrame);
7141 /*  block_input (); */
7142   pixel_height = NSHeight (newRect);
7143   if (pixel_height == 0) pixel_height = 1;
7144   min_portion = 20 / pixel_height;
7145   [super setFrame: newRect];
7146   [self display];
7147 /*  unblock_input (); */
7151 - (void)dealloc
7153   NSTRACE (EmacsScroller_dealloc);
7154   if (window)
7155     wset_vertical_scroll_bar (window, Qnil);
7156   window = 0;
7157   [super dealloc];
7161 - condemn
7163   NSTRACE (condemn);
7164   condemned =YES;
7165   return self;
7169 - reprieve
7171   NSTRACE (reprieve);
7172   condemned =NO;
7173   return self;
7177 - judge
7179   NSTRACE (judge);
7180   if (condemned)
7181     {
7182       EmacsView *view;
7183       block_input ();
7184       /* ensure other scrollbar updates after deletion */
7185       view = (EmacsView *)FRAME_NS_VIEW (frame);
7186       if (view != nil)
7187         view->scrollbarsNeedingUpdate++;
7188       [self removeFromSuperview];
7189       [self release];
7190       unblock_input ();
7191     }
7192   return self;
7196 - (void)resetCursorRects
7198   NSRect visible = [self visibleRect];
7199   NSTRACE (resetCursorRects);
7201   if (!NSIsEmptyRect (visible))
7202     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
7203   [[NSCursor arrowCursor] setOnMouseEntered: YES];
7207 - (int) checkSamePosition: (int) position portion: (int) portion
7208                     whole: (int) whole
7210   return em_position ==position && em_portion ==portion && em_whole ==whole
7211     && portion != whole; /* needed for resize empty buf */
7215 - setPosition: (int)position portion: (int)portion whole: (int)whole
7217   NSTRACE (setPosition);
7219   em_position = position;
7220   em_portion = portion;
7221   em_whole = whole;
7223   if (portion >= whole)
7224     {
7225 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
7226       [self setKnobProportion: 1.0];
7227       [self setDoubleValue: 1.0];
7228 #else
7229       [self setFloatValue: 0.0 knobProportion: 1.0];
7230 #endif
7231     }
7232   else
7233     {
7234       float pos;
7235       CGFloat por;
7236       portion = max ((float)whole*min_portion/pixel_height, portion);
7237       pos = (float)position / (whole - portion);
7238       por = (CGFloat)portion/whole;
7239 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
7240       [self setKnobProportion: por];
7241       [self setDoubleValue: pos];
7242 #else
7243       [self setFloatValue: pos knobProportion: por];
7244 #endif
7245     }
7247   /* Events may come here even if the event loop is not running.
7248      If we don't enter the event loop, the scroll bar will not update.
7249      So send SIGIO to ourselves.  */
7250   if (apploopnr == 0) raise (SIGIO);
7252   return self;
7255 /* set up emacs_event */
7256 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
7258   Lisp_Object win;
7259   if (!emacs_event)
7260     return;
7262   emacs_event->part = last_hit_part;
7263   emacs_event->code = 0;
7264   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
7265   XSETWINDOW (win, window);
7266   emacs_event->frame_or_window = win;
7267   emacs_event->timestamp = EV_TIMESTAMP (e);
7268   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
7269   emacs_event->arg = Qnil;
7270   XSETINT (emacs_event->x, loc * pixel_height);
7271   XSETINT (emacs_event->y, pixel_height-20);
7273   if (q_event_ptr)
7274     {
7275       n_emacs_events_pending++;
7276       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7277     }
7278   else
7279     hold_event (emacs_event);
7280   EVENT_INIT (*emacs_event);
7281   ns_send_appdefined (-1);
7285 /* called manually thru timer to implement repeated button action w/hold-down */
7286 - repeatScroll: (NSTimer *)scrollEntry
7288   NSEvent *e = [[self window] currentEvent];
7289   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
7290   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7292   /* clear timer if need be */
7293   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7294     {
7295         [scroll_repeat_entry invalidate];
7296         [scroll_repeat_entry release];
7297         scroll_repeat_entry = nil;
7299         if (inKnob)
7300           return self;
7302         scroll_repeat_entry
7303           = [[NSTimer scheduledTimerWithTimeInterval:
7304                         SCROLL_BAR_CONTINUOUS_DELAY
7305                                             target: self
7306                                           selector: @selector (repeatScroll:)
7307                                           userInfo: 0
7308                                            repeats: YES]
7309               retain];
7310     }
7312   [self sendScrollEventAtLoc: 0 fromEvent: e];
7313   return self;
7317 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
7318    mouseDragged events without going into a modal loop. */
7319 - (void)mouseDown: (NSEvent *)e
7321   NSRect sr, kr;
7322   /* hitPart is only updated AFTER event is passed on */
7323   NSScrollerPart part = [self testPart: [e locationInWindow]];
7324   CGFloat inc = 0.0, loc, kloc, pos;
7325   int edge = 0;
7327   NSTRACE (EmacsScroller_mouseDown);
7329   switch (part)
7330     {
7331     case NSScrollerDecrementPage:
7332         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7333     case NSScrollerIncrementPage:
7334         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7335     case NSScrollerDecrementLine:
7336       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7337     case NSScrollerIncrementLine:
7338       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7339     case NSScrollerKnob:
7340       last_hit_part = scroll_bar_handle; break;
7341     case NSScrollerKnobSlot:  /* GNUstep-only */
7342       last_hit_part = scroll_bar_move_ratio; break;
7343     default:  /* NSScrollerNoPart? */
7344       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7345                (long) part);
7346       return;
7347     }
7349   if (inc != 0.0)
7350     {
7351       pos = 0;      /* ignored */
7353       /* set a timer to repeat, as we can't let superclass do this modally */
7354       scroll_repeat_entry
7355         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7356                                             target: self
7357                                           selector: @selector (repeatScroll:)
7358                                           userInfo: 0
7359                                            repeats: YES]
7360             retain];
7361     }
7362   else
7363     {
7364       /* handle, or on GNUstep possibly slot */
7365       NSEvent *fake_event;
7367       /* compute float loc in slot and mouse offset on knob */
7368       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7369                       toView: nil];
7370       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7371       if (loc <= 0.0)
7372         {
7373           loc = 0.0;
7374           edge = -1;
7375         }
7376       else if (loc >= NSHeight (sr))
7377         {
7378           loc = NSHeight (sr);
7379           edge = 1;
7380         }
7382       if (edge)
7383         kloc = 0.5 * edge;
7384       else
7385         {
7386           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7387                           toView: nil];
7388           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7389         }
7390       last_mouse_offset = kloc;
7392       /* if knob, tell emacs a location offset by knob pos
7393          (to indicate top of handle) */
7394       if (part == NSScrollerKnob)
7395           pos = (loc - last_mouse_offset) / NSHeight (sr);
7396       else
7397         /* else this is a slot click on GNUstep: go straight there */
7398         pos = loc / NSHeight (sr);
7400       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7401       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7402                                       location: [e locationInWindow]
7403                                  modifierFlags: [e modifierFlags]
7404                                      timestamp: [e timestamp]
7405                                   windowNumber: [e windowNumber]
7406                                        context: [e context]
7407                                    eventNumber: [e eventNumber]
7408                                     clickCount: [e clickCount]
7409                                       pressure: [e pressure]];
7410       [super mouseUp: fake_event];
7411     }
7413   if (part != NSScrollerKnob)
7414     [self sendScrollEventAtLoc: pos fromEvent: e];
7418 /* Called as we manually track scroller drags, rather than superclass. */
7419 - (void)mouseDragged: (NSEvent *)e
7421     NSRect sr;
7422     double loc, pos;
7424     NSTRACE (EmacsScroller_mouseDragged);
7426       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7427                       toView: nil];
7428       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7430       if (loc <= 0.0)
7431         {
7432           loc = 0.0;
7433         }
7434       else if (loc >= NSHeight (sr) + last_mouse_offset)
7435         {
7436           loc = NSHeight (sr) + last_mouse_offset;
7437         }
7439       pos = (loc - last_mouse_offset) / NSHeight (sr);
7440       [self sendScrollEventAtLoc: pos fromEvent: e];
7444 - (void)mouseUp: (NSEvent *)e
7446   if (scroll_repeat_entry)
7447     {
7448       [scroll_repeat_entry invalidate];
7449       [scroll_repeat_entry release];
7450       scroll_repeat_entry = nil;
7451     }
7452   last_hit_part = 0;
7456 /* treat scrollwheel events in the bar as though they were in the main window */
7457 - (void) scrollWheel: (NSEvent *)theEvent
7459   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7460   [view mouseDown: theEvent];
7463 @end  /* EmacsScroller */
7466 #ifdef NS_IMPL_GNUSTEP
7467 /* Dummy class to get rid of startup warnings.  */
7468 @implementation EmacsDocument
7470 @end
7471 #endif
7474 /* ==========================================================================
7476    Font-related functions; these used to be in nsfaces.m
7478    ========================================================================== */
7481 Lisp_Object
7482 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7484   struct font *font = XFONT_OBJECT (font_object);
7485   EmacsView *view = FRAME_NS_VIEW (f);
7487   if (fontset < 0)
7488     fontset = fontset_from_font (font_object);
7489   FRAME_FONTSET (f) = fontset;
7491   if (FRAME_FONT (f) == font)
7492     /* This font is already set in frame F.  There's nothing more to
7493        do.  */
7494     return font_object;
7496   FRAME_FONT (f) = font;
7498   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7499   FRAME_COLUMN_WIDTH (f) = font->average_width;
7500   FRAME_LINE_HEIGHT (f) = font->height;
7502   compute_fringe_widths (f, 1);
7504   /* Compute the scroll bar width in character columns.  */
7505   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7506     {
7507       int wid = FRAME_COLUMN_WIDTH (f);
7508       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7509         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7510     }
7511   else
7512     {
7513       int wid = FRAME_COLUMN_WIDTH (f);
7514       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7515     }
7517   /* Now make the frame display the given font.  */
7518   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
7519     x_set_window_size (f, 0, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
7520                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 1);
7522   return font_object;
7526 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7527 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7528          in 1.43. */
7530 const char *
7531 ns_xlfd_to_fontname (const char *xlfd)
7532 /* --------------------------------------------------------------------------
7533     Convert an X font name (XLFD) to an NS font name.
7534     Only family is used.
7535     The string returned is temporarily allocated.
7536    -------------------------------------------------------------------------- */
7538   char *name = xmalloc (180);
7539   int i, len;
7540   const char *ret;
7542   if (!strncmp (xlfd, "--", 2))
7543     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7544   else
7545     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7547   /* stopgap for malformed XLFD input */
7548   if (strlen (name) == 0)
7549     strcpy (name, "Monaco");
7551   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7552      also uppercase after '-' or ' ' */
7553   name[0] = c_toupper (name[0]);
7554   for (len =strlen (name), i =0; i<len; i++)
7555     {
7556       if (name[i] == '$')
7557         {
7558           name[i] = '-';
7559           if (i+1<len)
7560             name[i+1] = c_toupper (name[i+1]);
7561         }
7562       else if (name[i] == '_')
7563         {
7564           name[i] = ' ';
7565           if (i+1<len)
7566             name[i+1] = c_toupper (name[i+1]);
7567         }
7568     }
7569 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7570   ret = [[NSString stringWithUTF8String: name] UTF8String];
7571   xfree (name);
7572   return ret;
7576 void
7577 syms_of_nsterm (void)
7579   NSTRACE (syms_of_nsterm);
7581   ns_antialias_threshold = 10.0;
7583   /* from 23+ we need to tell emacs what modifiers there are.. */
7584   DEFSYM (Qmodifier_value, "modifier-value");
7585   DEFSYM (Qalt, "alt");
7586   DEFSYM (Qhyper, "hyper");
7587   DEFSYM (Qmeta, "meta");
7588   DEFSYM (Qsuper, "super");
7589   DEFSYM (Qcontrol, "control");
7590   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7592   DEFSYM (Qfile, "file");
7593   DEFSYM (Qurl, "url");
7595   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7596   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7597   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7598   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7599   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7601   DEFVAR_LISP ("ns-input-file", ns_input_file,
7602               "The file specified in the last NS event.");
7603   ns_input_file =Qnil;
7605   DEFVAR_LISP ("ns-working-text", ns_working_text,
7606               "String for visualizing working composition sequence.");
7607   ns_working_text =Qnil;
7609   DEFVAR_LISP ("ns-input-font", ns_input_font,
7610               "The font specified in the last NS event.");
7611   ns_input_font =Qnil;
7613   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7614               "The fontsize specified in the last NS event.");
7615   ns_input_fontsize =Qnil;
7617   DEFVAR_LISP ("ns-input-line", ns_input_line,
7618                "The line specified in the last NS event.");
7619   ns_input_line =Qnil;
7621   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7622                "The service name specified in the last NS event.");
7623   ns_input_spi_name =Qnil;
7625   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7626                "The service argument specified in the last NS event.");
7627   ns_input_spi_arg =Qnil;
7629   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7630                "This variable describes the behavior of the alternate or option key.\n\
7631 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7632 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7633 at all, allowing it to be used at a lower level for accented character entry.");
7634   ns_alternate_modifier = Qmeta;
7636   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7637                "This variable describes the behavior of the right alternate or option key.\n\
7638 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7639 Set to left means be the same key as `ns-alternate-modifier'.\n\
7640 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7641 at all, allowing it to be used at a lower level for accented character entry.");
7642   ns_right_alternate_modifier = Qleft;
7644   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7645                "This variable describes the behavior of the command key.\n\
7646 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7647   ns_command_modifier = Qsuper;
7649   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7650                "This variable describes the behavior of the right command key.\n\
7651 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7652 Set to left means be the same key as `ns-command-modifier'.\n\
7653 Set to none means that the command / option key is not interpreted by Emacs\n\
7654 at all, allowing it to be used at a lower level for accented character entry.");
7655   ns_right_command_modifier = Qleft;
7657   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7658                "This variable describes the behavior of the control key.\n\
7659 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7660   ns_control_modifier = Qcontrol;
7662   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7663                "This variable describes the behavior of the right control key.\n\
7664 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7665 Set to left means be the same key as `ns-control-modifier'.\n\
7666 Set to none means that the control / option key is not interpreted by Emacs\n\
7667 at all, allowing it to be used at a lower level for accented character entry.");
7668   ns_right_control_modifier = Qleft;
7670   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7671                "This variable describes the behavior of the function key (on laptops).\n\
7672 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7673 Set to none means that the function key is not interpreted by Emacs at all,\n\
7674 allowing it to be used at a lower level for accented character entry.");
7675   ns_function_modifier = Qnone;
7677   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7678                "Non-nil (the default) means to render text antialiased.");
7679   ns_antialias_text = Qt;
7681   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7682                "Whether to confirm application quit using dialog.");
7683   ns_confirm_quit = Qnil;
7685   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7686                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7687 Only works on OSX 10.6 or later.  */);
7688   ns_auto_hide_menu_bar = Qnil;
7690   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7691      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7692 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7693 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7694 Default is t for OSX >= 10.7, nil otherwise.  */);
7695 #ifdef HAVE_NATIVE_FS
7696   ns_use_native_fullscreen = YES;
7697 #else
7698   ns_use_native_fullscreen = NO;
7699 #endif
7700   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7702   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
7703      doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
7704 Note that this does not apply to images.
7705 This variable is ignored on OSX < 10.7 and GNUstep.  */);
7706   ns_use_srgb_colorspace = YES;
7708   /* TODO: move to common code */
7709   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7710                doc: /* Which toolkit scroll bars Emacs uses, if any.
7711 A value of nil means Emacs doesn't use toolkit scroll bars.
7712 With the X Window system, the value is a symbol describing the
7713 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7714 With MS Windows or Nextstep, the value is t.  */);
7715   Vx_toolkit_scroll_bars = Qt;
7717   DEFVAR_BOOL ("x-use-underline-position-properties",
7718                x_use_underline_position_properties,
7719      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7720 A value of nil means ignore them.  If you encounter fonts with bogus
7721 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7722 to 4.1, set this to nil. */);
7723   x_use_underline_position_properties = 0;
7725   DEFVAR_BOOL ("x-underline-at-descent-line",
7726                x_underline_at_descent_line,
7727      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7728 A value of nil means to draw the underline according to the value of the
7729 variable `x-use-underline-position-properties', which is usually at the
7730 baseline level.  The default value is nil.  */);
7731   x_underline_at_descent_line = 0;
7733   /* Tell Emacs about this window system.  */
7734   Fprovide (Qns, Qnil);
7736   DEFSYM (Qcocoa, "cocoa");
7737   DEFSYM (Qgnustep, "gnustep");
7739   syms_of_nsfont ();
7740 #ifdef NS_IMPL_COCOA
7741   Fprovide (Qcocoa, Qnil);
7742 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
7743   syms_of_macfont ();
7744 #endif
7745 #else
7746   Fprovide (Qgnustep, Qnil);
7747 #endif