Some more fixes for pixelwise resizing.
[emacs.git] / src / nsterm.m
blob10780b054d93351252869e950d80bc14834bf6ca
1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2013
4   Free Software 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     Local declarations
110    ========================================================================== */
112 /* Convert a symbol indexed with an NSxxx value to a value as defined
113    in keyboard.c (lispy_function_key). I hope this is a correct way
114    of doing things... */
115 static unsigned convert_ns_to_X_keysym[] =
117   NSHomeFunctionKey,            0x50,
118   NSLeftArrowFunctionKey,       0x51,
119   NSUpArrowFunctionKey,         0x52,
120   NSRightArrowFunctionKey,      0x53,
121   NSDownArrowFunctionKey,       0x54,
122   NSPageUpFunctionKey,          0x55,
123   NSPageDownFunctionKey,        0x56,
124   NSEndFunctionKey,             0x57,
125   NSBeginFunctionKey,           0x58,
126   NSSelectFunctionKey,          0x60,
127   NSPrintFunctionKey,           0x61,
128   NSClearLineFunctionKey,       0x0B,
129   NSExecuteFunctionKey,         0x62,
130   NSInsertFunctionKey,          0x63,
131   NSUndoFunctionKey,            0x65,
132   NSRedoFunctionKey,            0x66,
133   NSMenuFunctionKey,            0x67,
134   NSFindFunctionKey,            0x68,
135   NSHelpFunctionKey,            0x6A,
136   NSBreakFunctionKey,           0x6B,
138   NSF1FunctionKey,              0xBE,
139   NSF2FunctionKey,              0xBF,
140   NSF3FunctionKey,              0xC0,
141   NSF4FunctionKey,              0xC1,
142   NSF5FunctionKey,              0xC2,
143   NSF6FunctionKey,              0xC3,
144   NSF7FunctionKey,              0xC4,
145   NSF8FunctionKey,              0xC5,
146   NSF9FunctionKey,              0xC6,
147   NSF10FunctionKey,             0xC7,
148   NSF11FunctionKey,             0xC8,
149   NSF12FunctionKey,             0xC9,
150   NSF13FunctionKey,             0xCA,
151   NSF14FunctionKey,             0xCB,
152   NSF15FunctionKey,             0xCC,
153   NSF16FunctionKey,             0xCD,
154   NSF17FunctionKey,             0xCE,
155   NSF18FunctionKey,             0xCF,
156   NSF19FunctionKey,             0xD0,
157   NSF20FunctionKey,             0xD1,
158   NSF21FunctionKey,             0xD2,
159   NSF22FunctionKey,             0xD3,
160   NSF23FunctionKey,             0xD4,
161   NSF24FunctionKey,             0xD5,
163   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
164   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
165   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
167   NSTabCharacter,               0x09,
168   0x19,                         0x09,  /* left tab->regular since pass shift */
169   NSCarriageReturnCharacter,    0x0D,
170   NSNewlineCharacter,           0x0D,
171   NSEnterCharacter,             0x8D,
173   0x41|NSNumericPadKeyMask,     0xAE,  /* KP_Decimal */
174   0x43|NSNumericPadKeyMask,     0xAA,  /* KP_Multiply */
175   0x45|NSNumericPadKeyMask,     0xAB,  /* KP_Add */
176   0x4B|NSNumericPadKeyMask,     0xAF,  /* KP_Divide */
177   0x4E|NSNumericPadKeyMask,     0xAD,  /* KP_Subtract */
178   0x51|NSNumericPadKeyMask,     0xBD,  /* KP_Equal */
179   0x52|NSNumericPadKeyMask,     0xB0,  /* KP_0 */
180   0x53|NSNumericPadKeyMask,     0xB1,  /* KP_1 */
181   0x54|NSNumericPadKeyMask,     0xB2,  /* KP_2 */
182   0x55|NSNumericPadKeyMask,     0xB3,  /* KP_3 */
183   0x56|NSNumericPadKeyMask,     0xB4,  /* KP_4 */
184   0x57|NSNumericPadKeyMask,     0xB5,  /* KP_5 */
185   0x58|NSNumericPadKeyMask,     0xB6,  /* KP_6 */
186   0x59|NSNumericPadKeyMask,     0xB7,  /* KP_7 */
187   0x5B|NSNumericPadKeyMask,     0xB8,  /* KP_8 */
188   0x5C|NSNumericPadKeyMask,     0xB9,  /* KP_9 */
190   0x1B,                         0x1B   /* escape */
193 static Lisp_Object Qmodifier_value;
194 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
195 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
197 static Lisp_Object QUTF8_STRING;
198 static Lisp_Object Qcocoa, Qgnustep;
199 static Lisp_Object Qfile, Qurl;
201 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
202    the maximum font size to NOT antialias.  On GNUstep there is currently
203    no way to control this behavior. */
204 float ns_antialias_threshold;
206 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
207 NSString *ns_app_name = @"Emacs";  /* default changed later */
209 /* Display variables */
210 struct ns_display_info *x_display_list; /* Chain of existing displays */
211 long context_menu_value = 0;
213 /* display update */
214 static struct frame *ns_updating_frame;
215 static NSView *focus_view = NULL;
216 static int ns_window_num = 0;
217 #ifdef NS_IMPL_GNUSTEP
218 static NSRect uRect;
219 #endif
220 static BOOL gsaved = NO;
221 static BOOL ns_fake_keydown = NO;
222 #ifdef NS_IMPL_COCOA
223 static BOOL ns_menu_bar_is_hidden = NO;
224 #endif
225 /*static int debug_lock = 0; */
227 /* event loop */
228 static BOOL send_appdefined = YES;
229 #define NO_APPDEFINED_DATA (-8)
230 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
231 static NSTimer *timed_entry = 0;
232 static NSTimer *scroll_repeat_entry = nil;
233 static fd_set select_readfds, select_writefds;
234 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
235 static int select_nfds = 0, select_valid = 0;
236 static struct timespec select_timeout = { 0, 0 };
237 static int selfds[2] = { -1, -1 };
238 static pthread_mutex_t select_mutex;
239 static int apploopnr = 0;
240 static NSAutoreleasePool *outerpool;
241 static struct input_event *emacs_event = NULL;
242 static struct input_event *q_event_ptr = NULL;
243 static int n_emacs_events_pending = 0;
244 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
245   *ns_pending_service_args;
246 static BOOL ns_do_open_file = NO;
247 static BOOL ns_last_use_native_fullscreen;
249 static struct {
250   struct input_event *q;
251   int nr, cap;
252 } hold_event_q = {
253   NULL, 0, 0
256 #ifdef NS_IMPL_COCOA
258  * State for pending menu activation:
259  * MENU_NONE     Normal state
260  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
261  *               run lisp to update the menu.
262  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
263  *               will open.
264  */
265 #define MENU_NONE 0
266 #define MENU_PENDING 1
267 #define MENU_OPENING 2
268 static int menu_will_open_state = MENU_NONE;
270 /* Saved position for menu click.  */
271 static CGPoint menu_mouse_point;
272 #endif
274 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
275 #define NS_FUNCTION_KEY_MASK 0x800000
276 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
277 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
278 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
279 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
280 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
281 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
282 #define EV_MODIFIERS2(flags)                          \
283     (((flags & NSHelpKeyMask) ?           \
284            hyper_modifier : 0)                        \
285      | (!EQ (ns_right_alternate_modifier, Qleft) && \
286         ((flags & NSRightAlternateKeyMask) \
287          == NSRightAlternateKeyMask) ? \
288            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
289      | ((flags & NSAlternateKeyMask) ?                 \
290            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
291      | ((flags & NSShiftKeyMask) ?     \
292            shift_modifier : 0)                        \
293      | (!EQ (ns_right_control_modifier, Qleft) && \
294         ((flags & NSRightControlKeyMask) \
295          == NSRightControlKeyMask) ? \
296            parse_solitary_modifier (ns_right_control_modifier) : 0) \
297      | ((flags & NSControlKeyMask) ?      \
298            parse_solitary_modifier (ns_control_modifier) : 0)     \
299      | ((flags & NS_FUNCTION_KEY_MASK) ?  \
300            parse_solitary_modifier (ns_function_modifier) : 0)    \
301      | (!EQ (ns_right_command_modifier, Qleft) && \
302         ((flags & NSRightCommandKeyMask) \
303          == NSRightCommandKeyMask) ? \
304            parse_solitary_modifier (ns_right_command_modifier) : 0) \
305      | ((flags & NSCommandKeyMask) ?      \
306            parse_solitary_modifier (ns_command_modifier):0))
307 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
309 #define EV_UDMODIFIERS(e)                                      \
310     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
311      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
312      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
313      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
314      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
315      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
316      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
317      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
318      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
320 #define EV_BUTTON(e)                                                         \
321     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
322       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
323      [e buttonNumber] - 1)
325 /* Convert the time field to a timestamp in milliseconds. */
326 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
328 /* This is a piece of code which is common to all the event handling
329    methods.  Maybe it should even be a function.  */
330 #define EV_TRAILER(e)                                                   \
331   {                                                                     \
332     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
333     EV_TRAILER2 (e);                                                    \
334   }
336 #define EV_TRAILER2(e)                                                  \
337   {                                                                     \
338       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
339       if (q_event_ptr)                                                  \
340         {                                                               \
341           n_emacs_events_pending++;                                     \
342           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
343         }                                                               \
344       else                                                              \
345         hold_event (emacs_event);                                       \
346       EVENT_INIT (*emacs_event);                                        \
347       ns_send_appdefined (-1);                                          \
348     }
350 /* TODO: get rid of need for these forward declarations */
351 static void ns_condemn_scroll_bars (struct frame *f);
352 static void ns_judge_scroll_bars (struct frame *f);
353 void x_set_frame_alpha (struct frame *f);
356 /* ==========================================================================
358     Utilities
360    ========================================================================== */
362 static void
363 hold_event (struct input_event *event)
365   if (hold_event_q.nr == hold_event_q.cap)
366     {
367       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
368       else hold_event_q.cap *= 2;
369       hold_event_q.q =
370         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
371     }
373   hold_event_q.q[hold_event_q.nr++] = *event;
374   /* Make sure ns_read_socket is called, i.e. we have input.  */
375   raise (SIGIO);
376   send_appdefined = YES;
379 static Lisp_Object
380 append2 (Lisp_Object list, Lisp_Object item)
381 /* --------------------------------------------------------------------------
382    Utility to append to a list
383    -------------------------------------------------------------------------- */
385   Lisp_Object array[2];
386   array[0] = list;
387   array[1] = list1 (item);
388   return Fnconc (2, &array[0]);
392 const char *
393 ns_etc_directory (void)
394 /* If running as a self-contained app bundle, return as a string the
395    filename of the etc directory, if present; else nil.  */
397   NSBundle *bundle = [NSBundle mainBundle];
398   NSString *resourceDir = [bundle resourcePath];
399   NSString *resourcePath;
400   NSFileManager *fileManager = [NSFileManager defaultManager];
401   BOOL isDir;
403   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
404   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
405     {
406       if (isDir) return [resourcePath UTF8String];
407     }
408   return NULL;
412 const char *
413 ns_exec_path (void)
414 /* If running as a self-contained app bundle, return as a path string
415    the filenames of the libexec and bin directories, ie libexec:bin.
416    Otherwise, return nil.
417    Normally, Emacs does not add its own bin/ directory to the PATH.
418    However, a self-contained NS build has a different layout, with
419    bin/ and libexec/ subdirectories in the directory that contains
420    Emacs.app itself.
421    We put libexec first, because init_callproc_1 uses the first
422    element to initialize exec-directory.  An alternative would be
423    for init_callproc to check for invocation-directory/libexec.
426   NSBundle *bundle = [NSBundle mainBundle];
427   NSString *resourceDir = [bundle resourcePath];
428   NSString *binDir = [bundle bundlePath];
429   NSString *resourcePath, *resourcePaths;
430   NSRange range;
431   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
432   NSFileManager *fileManager = [NSFileManager defaultManager];
433   NSArray *paths;
434   NSEnumerator *pathEnum;
435   BOOL isDir;
437   range = [resourceDir rangeOfString: @"Contents"];
438   if (range.location != NSNotFound)
439     {
440       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
441 #ifdef NS_IMPL_COCOA
442       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
443 #endif
444     }
446   paths = [binDir stringsByAppendingPaths:
447                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
448   pathEnum = [paths objectEnumerator];
449   resourcePaths = @"";
451   while ((resourcePath = [pathEnum nextObject]))
452     {
453       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
454         if (isDir)
455           {
456             if ([resourcePaths length] > 0)
457               resourcePaths
458                 = [resourcePaths stringByAppendingString: pathSeparator];
459             resourcePaths
460               = [resourcePaths stringByAppendingString: resourcePath];
461           }
462     }
463   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
465   return NULL;
469 const char *
470 ns_load_path (void)
471 /* If running as a self-contained app bundle, return as a path string
472    the filenames of the site-lisp and lisp directories.
473    Ie, site-lisp:lisp.  Otherwise, return nil.  */
475   NSBundle *bundle = [NSBundle mainBundle];
476   NSString *resourceDir = [bundle resourcePath];
477   NSString *resourcePath, *resourcePaths;
478   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
479   NSFileManager *fileManager = [NSFileManager defaultManager];
480   BOOL isDir;
481   NSArray *paths = [resourceDir stringsByAppendingPaths:
482                               [NSArray arrayWithObjects:
483                                          @"site-lisp", @"lisp", nil]];
484   NSEnumerator *pathEnum = [paths objectEnumerator];
485   resourcePaths = @"";
487   /* Hack to skip site-lisp.  */
488   if (no_site_lisp) resourcePath = [pathEnum nextObject];
490   while ((resourcePath = [pathEnum nextObject]))
491     {
492       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
493         if (isDir)
494           {
495             if ([resourcePaths length] > 0)
496               resourcePaths
497                 = [resourcePaths stringByAppendingString: pathSeparator];
498             resourcePaths
499               = [resourcePaths stringByAppendingString: resourcePath];
500           }
501     }
502   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
504   return NULL;
507 static void
508 ns_timeout (int usecs)
509 /* --------------------------------------------------------------------------
510      Blocking timer utility used by ns_ring_bell
511    -------------------------------------------------------------------------- */
513   struct timespec wakeup = timespec_add (current_timespec (),
514                                          make_timespec (0, usecs * 1000));
516   /* Keep waiting until past the time wakeup.  */
517   while (1)
518     {
519       struct timespec timeout, now = current_timespec ();
520       if (timespec_cmp (wakeup, now) <= 0)
521         break;
522       timeout = timespec_sub (wakeup, now);
524       /* Try to wait that long--but we might wake up sooner.  */
525       pselect (0, NULL, NULL, NULL, &timeout, NULL);
526     }
530 void
531 ns_release_object (void *obj)
532 /* --------------------------------------------------------------------------
533     Release an object (callable from C)
534    -------------------------------------------------------------------------- */
536     [(id)obj release];
540 void
541 ns_retain_object (void *obj)
542 /* --------------------------------------------------------------------------
543     Retain an object (callable from C)
544    -------------------------------------------------------------------------- */
546     [(id)obj retain];
550 void *
551 ns_alloc_autorelease_pool (void)
552 /* --------------------------------------------------------------------------
553      Allocate a pool for temporary objects (callable from C)
554    -------------------------------------------------------------------------- */
556   return [[NSAutoreleasePool alloc] init];
560 void
561 ns_release_autorelease_pool (void *pool)
562 /* --------------------------------------------------------------------------
563      Free a pool and temporary objects it refers to (callable from C)
564    -------------------------------------------------------------------------- */
566   ns_release_object (pool);
571 /* ==========================================================================
573     Focus (clipping) and screen update
575    ========================================================================== */
578 // Window constraining
579 // -------------------
581 // To ensure that the windows are not placed under the menu bar, they
582 // are typically moved by the call-back constrainFrameRect. However,
583 // by overriding it, it's possible to inhibit this, leaving the window
584 // in it's original position.
586 // It's possible to hide the menu bar. However, technically, it's only
587 // possible to hide it when the application is active. To ensure that
588 // this work properly, the menu bar and window constraining are
589 // deferred until the application becomes active.
591 // Even though it's not possible to manually move a window above the
592 // top of the screen, it is allowed if it's done programmatically,
593 // when the menu is hidden. This allows the editable area to cover the
594 // full screen height.
596 // Test cases
597 // ----------
599 // Use the following extra files:
601 //    init.el:
602 //       ;; Hide menu and place frame slightly above the top of the screen.
603 //       (setq ns-auto-hide-menu-bar t)
604 //       (set-frame-position (selected-frame) 0 -20)
606 // Test 1:
608 //    emacs -Q -l init.el
610 //    Result: No menu bar, and the title bar should be above the screen.
612 // Test 2:
614 //    emacs -Q
616 //    Result: Menu bar visible, frame placed immediately below the menu.
619 static void
620 ns_constrain_all_frames (void)
622   Lisp_Object tail, frame;
624   FOR_EACH_FRAME (tail, frame)
625     {
626       struct frame *f = XFRAME (frame);
627       if (FRAME_NS_P (f))
628         {
629           NSView *view = FRAME_NS_VIEW (f);
630           /* This no-op will trigger the default window placing
631            * constraint system. */
632           [[view window] setFrameOrigin:[[view window] frame].origin];
633         }
634     }
638 /* True, if the menu bar should be hidden.  */
640 static BOOL
641 ns_menu_bar_should_be_hidden (void)
643   return !NILP (ns_auto_hide_menu_bar)
644     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
648 /* Show or hide the menu bar, based on user setting.  */
650 static void
651 ns_update_auto_hide_menu_bar (void)
653 #ifdef NS_IMPL_COCOA
654 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
655   block_input ();
657   NSTRACE (ns_update_auto_hide_menu_bar);
659   if (NSApp != nil && [NSApp isActive])
660     {
661       // Note, "setPresentationOptions" triggers an error unless the
662       // application is active.
663       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
665       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
666         {
667           NSApplicationPresentationOptions options
668             = NSApplicationPresentationDefault;
670           if (menu_bar_should_be_hidden)
671             options |= NSApplicationPresentationAutoHideMenuBar
672               | NSApplicationPresentationAutoHideDock;
674           [NSApp setPresentationOptions: options];
676           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
678           if (!ns_menu_bar_is_hidden)
679             {
680               ns_constrain_all_frames ();
681             }
682         }
683     }
685   unblock_input ();
686 #endif
687 #endif
691 static void
692 ns_update_begin (struct frame *f)
693 /* --------------------------------------------------------------------------
694    Prepare for a grouped sequence of drawing calls
695    external (RIF) call; whole frame, called before update_window_begin
696    -------------------------------------------------------------------------- */
698   EmacsView *view = FRAME_NS_VIEW (f);
699   NSTRACE (ns_update_begin);
701   ns_update_auto_hide_menu_bar ();
703 #ifdef NS_IMPL_COCOA
704   if ([view isFullscreen] && [view fsIsNative])
705   {
706     // Fix reappearing tool bar in fullscreen for OSX 10.7
707     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
708     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
709     if (! tbar_visible != ! [toolbar isVisible])
710       [toolbar setVisible: tbar_visible];
711   }
712 #endif
714   ns_updating_frame = f;
715   [view lockFocus];
717   /* drawRect may have been called for say the minibuffer, and then clip path
718      is for the minibuffer.  But the display engine may draw more because
719      we have set the frame as garbaged.  So reset clip path to the whole
720      view.  */
721 #ifdef NS_IMPL_COCOA
722   {
723     NSBezierPath *bp;
724     NSRect r = [view frame];
725     NSRect cr = [[view window] frame];
726     /* If a large frame size is set, r may be larger than the window frame
727        before constrained.  In that case don't change the clip path, as we
728        will clear in to the tool bar and title bar.  */
729     if (r.size.height
730         + FRAME_NS_TITLEBAR_HEIGHT (f)
731         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
732       {
733         bp = [[NSBezierPath bezierPathWithRect: r] retain];
734         [bp setClip];
735         [bp release];
736       }
737   }
738 #endif
740 #ifdef NS_IMPL_GNUSTEP
741   uRect = NSMakeRect (0, 0, 0, 0);
742 #endif
746 static void
747 ns_update_window_begin (struct window *w)
748 /* --------------------------------------------------------------------------
749    Prepare for a grouped sequence of drawing calls
750    external (RIF) call; for one window, called after update_begin
751    -------------------------------------------------------------------------- */
753   struct frame *f = XFRAME (WINDOW_FRAME (w));
754   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
756   NSTRACE (ns_update_window_begin);
757   w->output_cursor = w->cursor;
759   block_input ();
761   if (f == hlinfo->mouse_face_mouse_frame)
762     {
763       /* Don't do highlighting for mouse motion during the update.  */
764       hlinfo->mouse_face_defer = 1;
766         /* If the frame needs to be redrawn,
767            simply forget about any prior mouse highlighting.  */
768       if (FRAME_GARBAGED_P (f))
769         hlinfo->mouse_face_window = Qnil;
771       /* (further code for mouse faces ifdef'd out in other terms elided) */
772     }
774   unblock_input ();
778 static void
779 ns_update_window_end (struct window *w, bool cursor_on_p,
780                       bool mouse_face_overwritten_p)
781 /* --------------------------------------------------------------------------
782    Finished a grouped sequence of drawing calls
783    external (RIF) call; for one window called before update_end
784    -------------------------------------------------------------------------- */
786   /* note: this fn is nearly identical in all terms */
787   if (!w->pseudo_window_p)
788     {
789       block_input ();
791       if (cursor_on_p)
792         display_and_set_cursor (w, 1,
793                                 w->output_cursor.hpos, w->output_cursor.vpos,
794                                 w->output_cursor.x, w->output_cursor.y);
796       if (draw_window_fringes (w, 1))
797         {
798           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
799             x_draw_right_divider (w);
800           else
801             x_draw_vertical_border (w);
802         }
804       unblock_input ();
805     }
807   /* If a row with mouse-face was overwritten, arrange for
808      frame_up_to_date to redisplay the mouse highlight.  */
809   if (mouse_face_overwritten_p)
810     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
812   NSTRACE (update_window_end);
816 static void
817 ns_update_end (struct frame *f)
818 /* --------------------------------------------------------------------------
819    Finished a grouped sequence of drawing calls
820    external (RIF) call; for whole frame, called after update_window_end
821    -------------------------------------------------------------------------- */
823   EmacsView *view = FRAME_NS_VIEW (f);
825 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
826   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
828   block_input ();
830   [view unlockFocus];
831   [[view window] flushWindow];
833   unblock_input ();
834   ns_updating_frame = NULL;
835   NSTRACE (ns_update_end);
838 static void
839 ns_focus (struct frame *f, NSRect *r, int n)
840 /* --------------------------------------------------------------------------
841    Internal: Focus on given frame.  During small local updates this is used to
842      draw, however during large updates, ns_update_begin and ns_update_end are
843      called to wrap the whole thing, in which case these calls are stubbed out.
844      Except, on GNUstep, we accumulate the rectangle being drawn into, because
845      the back end won't do this automatically, and will just end up flushing
846      the entire window.
847    -------------------------------------------------------------------------- */
849 //  NSTRACE (ns_focus);
850 /* static int c =0;
851    fprintf (stderr, "focus: %d", c++);
852    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
853    fprintf (stderr, "\n"); */
855   if (f != ns_updating_frame)
856     {
857       NSView *view = FRAME_NS_VIEW (f);
858       if (view != focus_view)
859         {
860           if (focus_view != NULL)
861             {
862               [focus_view unlockFocus];
863               [[focus_view window] flushWindow];
864 /*debug_lock--; */
865             }
867           if (view)
868             [view lockFocus];
869           focus_view = view;
870 /*if (view) debug_lock++; */
871         }
872     }
874   /* clipping */
875   if (r)
876     {
877       [[NSGraphicsContext currentContext] saveGraphicsState];
878       if (n == 2)
879         NSRectClipList (r, 2);
880       else
881         NSRectClip (*r);
882       gsaved = YES;
883     }
887 static void
888 ns_unfocus (struct frame *f)
889 /* --------------------------------------------------------------------------
890      Internal: Remove focus on given frame
891    -------------------------------------------------------------------------- */
893 //  NSTRACE (ns_unfocus);
895   if (gsaved)
896     {
897       [[NSGraphicsContext currentContext] restoreGraphicsState];
898       gsaved = NO;
899     }
901   if (f != ns_updating_frame)
902     {
903       if (focus_view != NULL)
904         {
905           [focus_view unlockFocus];
906           [[focus_view window] flushWindow];
907           focus_view = NULL;
908 /*debug_lock--; */
909         }
910     }
914 static void
915 ns_clip_to_row (struct window *w, struct glyph_row *row,
916                 enum glyph_row_area area, BOOL gc)
917 /* --------------------------------------------------------------------------
918      Internal (but parallels other terms): Focus drawing on given row
919    -------------------------------------------------------------------------- */
921   struct frame *f = XFRAME (WINDOW_FRAME (w));
922   NSRect clip_rect;
923   int window_x, window_y, window_width;
925   window_box (w, area, &window_x, &window_y, &window_width, 0);
927   clip_rect.origin.x = window_x;
928   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
929   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
930   clip_rect.size.width = window_width;
931   clip_rect.size.height = row->visible_height;
933   ns_focus (f, &clip_rect, 1);
937 static void
938 ns_ring_bell (struct frame *f)
939 /* --------------------------------------------------------------------------
940      "Beep" routine
941    -------------------------------------------------------------------------- */
943   NSTRACE (ns_ring_bell);
944   if (visible_bell)
945     {
946       NSAutoreleasePool *pool;
947       struct frame *frame = SELECTED_FRAME ();
948       NSView *view;
950       block_input ();
951       pool = [[NSAutoreleasePool alloc] init];
953       view = FRAME_NS_VIEW (frame);
954       if (view != nil)
955         {
956           NSRect r, surr;
957           NSPoint dim = NSMakePoint (128, 128);
959           r = [view bounds];
960           r.origin.x += (r.size.width - dim.x) / 2;
961           r.origin.y += (r.size.height - dim.y) / 2;
962           r.size.width = dim.x;
963           r.size.height = dim.y;
964           surr = NSInsetRect (r, -2, -2);
965           ns_focus (frame, &surr, 1);
966           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
967           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
968                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
969           NSRectFill (r);
970           [[view window] flushWindow];
971           ns_timeout (150000);
972           [[view window] restoreCachedImage];
973           [[view window] flushWindow];
974           ns_unfocus (frame);
975         }
976       [pool release];
977       unblock_input ();
978     }
979   else
980     {
981       NSBeep ();
982     }
985 /* ==========================================================================
987     Frame / window manager related functions
989    ========================================================================== */
992 static void
993 ns_raise_frame (struct frame *f)
994 /* --------------------------------------------------------------------------
995      Bring window to foreground and make it active
996    -------------------------------------------------------------------------- */
998   NSView *view;
999   check_window_system (f);
1000   view = FRAME_NS_VIEW (f);
1001   block_input ();
1002   if (FRAME_VISIBLE_P (f))
1003     [[view window] makeKeyAndOrderFront: NSApp];
1004   unblock_input ();
1008 static void
1009 ns_lower_frame (struct frame *f)
1010 /* --------------------------------------------------------------------------
1011      Send window to back
1012    -------------------------------------------------------------------------- */
1014   NSView *view;
1015   check_window_system (f);
1016   view = FRAME_NS_VIEW (f);
1017   block_input ();
1018   [[view window] orderBack: NSApp];
1019   unblock_input ();
1023 static void
1024 ns_frame_raise_lower (struct frame *f, int raise)
1025 /* --------------------------------------------------------------------------
1026      External (hook)
1027    -------------------------------------------------------------------------- */
1029   NSTRACE (ns_frame_raise_lower);
1031   if (raise)
1032     ns_raise_frame (f);
1033   else
1034     ns_lower_frame (f);
1038 static void
1039 ns_frame_rehighlight (struct frame *frame)
1040 /* --------------------------------------------------------------------------
1041      External (hook): called on things like window switching within frame
1042    -------------------------------------------------------------------------- */
1044   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1045   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1047   NSTRACE (ns_frame_rehighlight);
1048   if (dpyinfo->x_focus_frame)
1049     {
1050       dpyinfo->x_highlight_frame
1051         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1052            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1053            : dpyinfo->x_focus_frame);
1054       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1055         {
1056           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1057           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1058         }
1059     }
1060   else
1061       dpyinfo->x_highlight_frame = 0;
1063   if (dpyinfo->x_highlight_frame &&
1064          dpyinfo->x_highlight_frame != old_highlight)
1065     {
1066       if (old_highlight)
1067         {
1068           x_update_cursor (old_highlight, 1);
1069           x_set_frame_alpha (old_highlight);
1070         }
1071       if (dpyinfo->x_highlight_frame)
1072         {
1073           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1074           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1075         }
1076     }
1080 void
1081 x_make_frame_visible (struct frame *f)
1082 /* --------------------------------------------------------------------------
1083      External: Show the window (X11 semantics)
1084    -------------------------------------------------------------------------- */
1086   NSTRACE (x_make_frame_visible);
1087   /* XXX: at some points in past this was not needed, as the only place that
1088      called this (frame.c:Fraise_frame ()) also called raise_lower;
1089      if this ends up the case again, comment this out again. */
1090   if (!FRAME_VISIBLE_P (f))
1091     {
1092       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1094       SET_FRAME_VISIBLE (f, 1);
1095       ns_raise_frame (f);
1097       /* Making a new frame from a fullscreen frame will make the new frame
1098          fullscreen also.  So skip handleFS as this will print an error.  */
1099       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1100           && [view isFullscreen])
1101         return;
1103       if (f->want_fullscreen != FULLSCREEN_NONE)
1104         {
1105           block_input ();
1106           [view handleFS];
1107           unblock_input ();
1108         }
1109     }
1113 void
1114 x_make_frame_invisible (struct frame *f)
1115 /* --------------------------------------------------------------------------
1116      External: Hide the window (X11 semantics)
1117    -------------------------------------------------------------------------- */
1119   NSView *view;
1120   NSTRACE (x_make_frame_invisible);
1121   check_window_system (f);
1122   view = FRAME_NS_VIEW (f);
1123   [[view window] orderOut: NSApp];
1124   SET_FRAME_VISIBLE (f, 0);
1125   SET_FRAME_ICONIFIED (f, 0);
1129 void
1130 x_iconify_frame (struct frame *f)
1131 /* --------------------------------------------------------------------------
1132      External: Iconify window
1133    -------------------------------------------------------------------------- */
1135   NSView *view;
1136   struct ns_display_info *dpyinfo;
1138   NSTRACE (x_iconify_frame);
1139   check_window_system (f);
1140   view = FRAME_NS_VIEW (f);
1141   dpyinfo = FRAME_DISPLAY_INFO (f);
1143   if (dpyinfo->x_highlight_frame == f)
1144     dpyinfo->x_highlight_frame = 0;
1146   if ([[view window] windowNumber] <= 0)
1147     {
1148       /* the window is still deferred.  Make it very small, bring it
1149          on screen and order it out. */
1150       NSRect s = { { 100, 100}, {0, 0} };
1151       NSRect t;
1152       t = [[view window] frame];
1153       [[view window] setFrame: s display: NO];
1154       [[view window] orderBack: NSApp];
1155       [[view window] orderOut: NSApp];
1156       [[view window] setFrame: t display: NO];
1157     }
1158   [[view window] miniaturize: NSApp];
1161 /* Free X resources of frame F.  */
1163 void
1164 x_free_frame_resources (struct frame *f)
1166   NSView *view;
1167   struct ns_display_info *dpyinfo;
1168   Mouse_HLInfo *hlinfo;
1170   NSTRACE (x_free_frame_resources);
1171   check_window_system (f);
1172   view = FRAME_NS_VIEW (f);
1173   dpyinfo = FRAME_DISPLAY_INFO (f);
1174   hlinfo = MOUSE_HL_INFO (f);
1176   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1178   block_input ();
1180   free_frame_menubar (f);
1181   free_frame_faces (f);
1183   if (f == dpyinfo->x_focus_frame)
1184     dpyinfo->x_focus_frame = 0;
1185   if (f == dpyinfo->x_highlight_frame)
1186     dpyinfo->x_highlight_frame = 0;
1187   if (f == hlinfo->mouse_face_mouse_frame)
1188     reset_mouse_highlight (hlinfo);
1190   if (f->output_data.ns->miniimage != nil)
1191     [f->output_data.ns->miniimage release];
1193   [[view window] close];
1194   [view release];
1196   xfree (f->output_data.ns);
1198   unblock_input ();
1201 void
1202 x_destroy_window (struct frame *f)
1203 /* --------------------------------------------------------------------------
1204      External: Delete the window
1205    -------------------------------------------------------------------------- */
1207   NSTRACE (x_destroy_window);
1208   check_window_system (f);
1209   x_free_frame_resources (f);
1210   ns_window_num--;
1214 void
1215 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1216 /* --------------------------------------------------------------------------
1217      External: Position the window
1218    -------------------------------------------------------------------------- */
1220   NSView *view = FRAME_NS_VIEW (f);
1221   NSArray *screens = [NSScreen screens];
1222   NSScreen *fscreen = [screens objectAtIndex: 0];
1223   NSScreen *screen = [[view window] screen];
1225   NSTRACE (x_set_offset);
1227   block_input ();
1229   f->left_pos = xoff;
1230   f->top_pos = yoff;
1232   if (view != nil && screen && fscreen)
1233     {
1234       f->left_pos = f->size_hint_flags & XNegative
1235         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1236         : f->left_pos;
1237       /* We use visibleFrame here to take menu bar into account.
1238          Ideally we should also adjust left/top with visibleFrame.origin.  */
1240       f->top_pos = f->size_hint_flags & YNegative
1241         ? ([screen visibleFrame].size.height + f->top_pos
1242            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1243            - FRAME_TOOLBAR_HEIGHT (f))
1244         : f->top_pos;
1245 #ifdef NS_IMPL_GNUSTEP
1246       if (f->left_pos < 100)
1247         f->left_pos = 100;  /* don't overlap menu */
1248 #endif
1249       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1250          menu bar.  */
1251       [[view window] setFrameTopLeftPoint:
1252                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1253                                     SCREENMAXBOUND ([fscreen frame].size.height
1254                                                     - NS_TOP_POS (f)))];
1255       f->size_hint_flags &= ~(XNegative|YNegative);
1256     }
1258   unblock_input ();
1262 void
1263 x_set_window_size (struct frame *f,
1264                    int change_grav,
1265                    int width,
1266                    int height,
1267                    bool pixelwise)
1268 /* --------------------------------------------------------------------------
1269      Adjust window pixel size based on given character grid size
1270      Impl is a bit more complex than other terms, need to do some
1271      internal clipping.
1272    -------------------------------------------------------------------------- */
1274   EmacsView *view = FRAME_NS_VIEW (f);
1275   NSWindow *window = [view window];
1276   NSRect wr = [window frame];
1277   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1278   int pixelwidth, pixelheight;
1279   int rows, cols;
1281   NSTRACE (x_set_window_size);
1283   if (view == nil)
1284     return;
1286 /*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));*/
1288   block_input ();
1290   check_frame_size (f, &width, &height, pixelwise);
1292   compute_fringe_widths (f, 0);
1294   if (pixelwise)
1295     {
1296       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1297       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1298       cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
1299       rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
1300     }
1301   else
1302     {
1303       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1304       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1305       cols = width;
1306       rows = height;
1307     }
1309   /* If we have a toolbar, take its height into account. */
1310   if (tb && ! [view isFullscreen])
1311     {
1312     /* NOTE: previously this would generate wrong result if toolbar not
1313              yet displayed and fixing toolbar_height=32 helped, but
1314              now (200903) seems no longer needed */
1315     FRAME_TOOLBAR_HEIGHT (f) =
1316       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1317         - FRAME_NS_TITLEBAR_HEIGHT (f);
1318 #ifdef NS_IMPL_GNUSTEP
1319       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1320 #endif
1321     }
1322   else
1323     FRAME_TOOLBAR_HEIGHT (f) = 0;
1325   wr.size.width = pixelwidth + f->border_width;
1326   wr.size.height = pixelheight;
1327   if (! [view isFullscreen])
1328     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1329       + FRAME_TOOLBAR_HEIGHT (f);
1331   /* Do not try to constrain to this screen.  We may have multiple
1332      screens, and want Emacs to span those.  Constraining to screen
1333      prevents that, and that is not nice to the user.  */
1334  if (f->output_data.ns->zooming)
1335    f->output_data.ns->zooming = 0;
1336  else
1337    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1339   [view setRows: rows andColumns: cols];
1340   [window setFrame: wr display: YES];
1342   /* This is a trick to compensate for Emacs' managing the scrollbar area
1343      as a fixed number of standard character columns.  Instead of leaving
1344      blank space for the extra, we chopped it off above.  Now for
1345      left-hand scrollbars, we shift all rendering to the left by the
1346      difference between the real width and Emacs' imagined one.  For
1347      right-hand bars, don't worry about it since the extra is never used.
1348      (Obviously doesn't work for vertically split windows tho..) */
1349   {
1350     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1351       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1352                      - NS_SCROLL_BAR_WIDTH (f), 0)
1353       : NSMakePoint (0, 0);
1354     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1355     [view setBoundsOrigin: origin];
1356   }
1358   change_frame_size (f, width, height, 0, 1, 0, pixelwise);
1359 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1361   mark_window_cursors_off (XWINDOW (f->root_window));
1362   cancel_mouse_face (f);
1364   unblock_input ();
1368 static void
1369 ns_fullscreen_hook (struct frame *f)
1371   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1373   if (!FRAME_VISIBLE_P (f))
1374     return;
1376    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1377     {
1378       /* Old style fs don't initiate correctly if created from
1379          init/default-frame alist, so use a timer (not nice...).
1380       */
1381       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1382                                      selector: @selector (handleFS)
1383                                      userInfo: nil repeats: NO];
1384       return;
1385     }
1387   block_input ();
1388   [view handleFS];
1389   unblock_input ();
1392 /* ==========================================================================
1394     Color management
1396    ========================================================================== */
1399 NSColor *
1400 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1402   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1403   if (idx < 1 || idx >= color_table->avail)
1404     return nil;
1405   return color_table->colors[idx];
1409 unsigned long
1410 ns_index_color (NSColor *color, struct frame *f)
1412   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1413   ptrdiff_t idx;
1414   ptrdiff_t i;
1416   if (!color_table->colors)
1417     {
1418       color_table->size = NS_COLOR_CAPACITY;
1419       color_table->avail = 1; /* skip idx=0 as marker */
1420       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1421       color_table->colors[0] = nil;
1422       color_table->empty_indices = [[NSMutableSet alloc] init];
1423     }
1425   /* Do we already have this color?  */
1426   for (i = 1; i < color_table->avail; i++)
1427     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1428       return i;
1430   if ([color_table->empty_indices count] > 0)
1431     {
1432       NSNumber *index = [color_table->empty_indices anyObject];
1433       [color_table->empty_indices removeObject: index];
1434       idx = [index unsignedLongValue];
1435     }
1436   else
1437     {
1438       if (color_table->avail == color_table->size)
1439         color_table->colors =
1440           xpalloc (color_table->colors, &color_table->size, 1,
1441                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1442       idx = color_table->avail++;
1443     }
1445   color_table->colors[idx] = color;
1446   [color retain];
1447 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1448   return idx;
1452 void
1453 ns_free_indexed_color (unsigned long idx, struct frame *f)
1455   struct ns_color_table *color_table;
1456   NSColor *color;
1457   NSNumber *index;
1459   if (!f)
1460     return;
1462   color_table = FRAME_DISPLAY_INFO (f)->color_table;
1464   if (idx <= 0 || idx >= color_table->size) {
1465     message1 ("ns_free_indexed_color: Color index out of range.\n");
1466     return;
1467   }
1469   index = [NSNumber numberWithUnsignedInt: idx];
1470   if ([color_table->empty_indices containsObject: index]) {
1471     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1472     return;
1473   }
1475   color = color_table->colors[idx];
1476   [color release];
1477   color_table->colors[idx] = nil;
1478   [color_table->empty_indices addObject: index];
1479 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1483 static int
1484 ns_get_color (const char *name, NSColor **col)
1485 /* --------------------------------------------------------------------------
1486      Parse a color name
1487    -------------------------------------------------------------------------- */
1488 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1489    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1490    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1492   NSColor *new = nil;
1493   static char hex[20];
1494   int scaling;
1495   float r = -1.0, g, b;
1496   NSString *nsname = [NSString stringWithUTF8String: name];
1498 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1499   block_input ();
1501   if ([nsname isEqualToString: @"ns_selection_bg_color"])
1502     {
1503 #ifdef NS_IMPL_COCOA
1504       NSString *defname = [[NSUserDefaults standardUserDefaults]
1505                             stringForKey: @"AppleHighlightColor"];
1506       if (defname != nil)
1507         nsname = defname;
1508       else
1509 #endif
1510       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1511         {
1512           *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1513           unblock_input ();
1514           return 0;
1515         }
1516       else
1517         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1519       name = [nsname UTF8String];
1520     }
1521   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1522     {
1523       /* NOTE: OSX applications normally don't set foreground selection, but
1524          text may be unreadable if we don't.
1525       */
1526       if ((new = [NSColor selectedTextColor]) != nil)
1527         {
1528           *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1529           unblock_input ();
1530           return 0;
1531         }
1533       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1534       name = [nsname UTF8String];
1535     }
1537   /* First, check for some sort of numeric specification. */
1538   hex[0] = '\0';
1540   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1541     {
1542       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1543       [scanner scanFloat: &r];
1544       [scanner scanFloat: &g];
1545       [scanner scanFloat: &b];
1546     }
1547   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1548     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1549   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1550     {
1551       int len = (strlen(name) - 1);
1552       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1553       int i;
1554       scaling = strlen(name+start) / 3;
1555       for (i = 0; i < 3; i++)
1556         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1557                  name + start + i * scaling);
1558       hex[3 * (scaling + 1) - 1] = '\0';
1559     }
1561   if (hex[0])
1562     {
1563       int rr, gg, bb;
1564       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1565       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1566         {
1567           r = rr / fscale;
1568           g = gg / fscale;
1569           b = bb / fscale;
1570         }
1571     }
1573   if (r >= 0.0F)
1574     {
1575       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1576       unblock_input ();
1577       return 0;
1578     }
1580   /* Otherwise, color is expected to be from a list */
1581   {
1582     NSEnumerator *lenum, *cenum;
1583     NSString *name;
1584     NSColorList *clist;
1586 #ifdef NS_IMPL_GNUSTEP
1587     /* XXX: who is wrong, the requestor or the implementation? */
1588     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1589         == NSOrderedSame)
1590       nsname = @"highlightColor";
1591 #endif
1593     lenum = [[NSColorList availableColorLists] objectEnumerator];
1594     while ( (clist = [lenum nextObject]) && new == nil)
1595       {
1596         cenum = [[clist allKeys] objectEnumerator];
1597         while ( (name = [cenum nextObject]) && new == nil )
1598           {
1599             if ([name compare: nsname
1600                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1601               new = [clist colorWithKey: name];
1602           }
1603       }
1604   }
1606   if (new)
1607     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1608   unblock_input ();
1609   return new ? 0 : 1;
1614 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1615 /* --------------------------------------------------------------------------
1616      Convert a Lisp string object to a NS color
1617    -------------------------------------------------------------------------- */
1619   NSTRACE (ns_lisp_to_color);
1620   if (STRINGP (color))
1621     return ns_get_color (SSDATA (color), col);
1622   else if (SYMBOLP (color))
1623     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1624   return 1;
1628 Lisp_Object
1629 ns_color_to_lisp (NSColor *col)
1630 /* --------------------------------------------------------------------------
1631      Convert a color to a lisp string with the RGB equivalent
1632    -------------------------------------------------------------------------- */
1634   EmacsCGFloat red, green, blue, alpha, gray;
1635   char buf[1024];
1636   const char *str;
1637   NSTRACE (ns_color_to_lisp);
1639   block_input ();
1640   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1642       if ((str =[[col colorNameComponent] UTF8String]))
1643         {
1644           unblock_input ();
1645           return build_string ((char *)str);
1646         }
1648     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1649         getRed: &red green: &green blue: &blue alpha: &alpha];
1650   if (red ==green && red ==blue)
1651     {
1652       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1653             getWhite: &gray alpha: &alpha];
1654       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1655                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1656       unblock_input ();
1657       return build_string (buf);
1658     }
1660   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1661             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1663   unblock_input ();
1664   return build_string (buf);
1668 void
1669 ns_query_color(void *col, XColor *color_def, int setPixel)
1670 /* --------------------------------------------------------------------------
1671          Get ARGB values out of NSColor col and put them into color_def.
1672          If setPixel, set the pixel to a concatenated version.
1673          and set color_def pixel to the resulting index.
1674    -------------------------------------------------------------------------- */
1676   EmacsCGFloat r, g, b, a;
1678   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1679   color_def->red   = r * 65535;
1680   color_def->green = g * 65535;
1681   color_def->blue  = b * 65535;
1683   if (setPixel == YES)
1684     color_def->pixel
1685       = ARGB_TO_ULONG((int)(a*255),
1686                       (int)(r*255), (int)(g*255), (int)(b*255));
1690 bool
1691 ns_defined_color (struct frame *f,
1692                   const char *name,
1693                   XColor *color_def,
1694                   bool alloc,
1695                   bool makeIndex)
1696 /* --------------------------------------------------------------------------
1697          Return true if named color found, and set color_def rgb accordingly.
1698          If makeIndex and alloc are nonzero put the color in the color_table,
1699          and set color_def pixel to the resulting index.
1700          If makeIndex is zero, set color_def pixel to ARGB.
1701          Return false if not found
1702    -------------------------------------------------------------------------- */
1704   NSColor *col;
1705   NSTRACE (ns_defined_color);
1707   block_input ();
1708   if (ns_get_color (name, &col) != 0) /* Color not found  */
1709     {
1710       unblock_input ();
1711       return 0;
1712     }
1713   if (makeIndex && alloc)
1714     color_def->pixel = ns_index_color (col, f);
1715   ns_query_color (col, color_def, !makeIndex);
1716   unblock_input ();
1717   return 1;
1721 void
1722 x_set_frame_alpha (struct frame *f)
1723 /* --------------------------------------------------------------------------
1724      change the entire-frame transparency
1725    -------------------------------------------------------------------------- */
1727   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1728   double alpha = 1.0;
1729   double alpha_min = 1.0;
1731   if (dpyinfo->x_highlight_frame == f)
1732     alpha = f->alpha[0];
1733   else
1734     alpha = f->alpha[1];
1736   if (FLOATP (Vframe_alpha_lower_limit))
1737     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1738   else if (INTEGERP (Vframe_alpha_lower_limit))
1739     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1741   if (alpha < 0.0)
1742     return;
1743   else if (1.0 < alpha)
1744     alpha = 1.0;
1745   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1746     alpha = alpha_min;
1748 #ifdef NS_IMPL_COCOA
1749   {
1750     EmacsView *view = FRAME_NS_VIEW (f);
1751   [[view window] setAlphaValue: alpha];
1752   }
1753 #endif
1757 /* ==========================================================================
1759     Mouse handling
1761    ========================================================================== */
1764 void
1765 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1766 /* --------------------------------------------------------------------------
1767      Programmatically reposition mouse pointer in pixel coordinates
1768    -------------------------------------------------------------------------- */
1770   NSTRACE (x_set_mouse_pixel_position);
1771   ns_raise_frame (f);
1772 #if 0
1773   /* FIXME: this does not work, and what about GNUstep? */
1774 #ifdef NS_IMPL_COCOA
1775   [FRAME_NS_VIEW (f) lockFocus];
1776   PSsetmouse ((float)pix_x, (float)pix_y);
1777   [FRAME_NS_VIEW (f) unlockFocus];
1778 #endif
1779 #endif
1783 void
1784 x_set_mouse_position (struct frame *f, int h, int v)
1785 /* --------------------------------------------------------------------------
1786      Programmatically reposition mouse pointer in character coordinates
1787    -------------------------------------------------------------------------- */
1789   int pix_x, pix_y;
1791   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1792   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1794   if (pix_x < 0) pix_x = 0;
1795   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1797   if (pix_y < 0) pix_y = 0;
1798   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1800   x_set_mouse_pixel_position (f, pix_x, pix_y);
1804 static int
1805 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1806 /*   ------------------------------------------------------------------------
1807      Called by EmacsView on mouseMovement events.  Passes on
1808      to emacs mainstream code if we moved off of a rect of interest
1809      known as last_mouse_glyph.
1810      ------------------------------------------------------------------------ */
1812   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1813   NSRect *r;
1815 //  NSTRACE (note_mouse_movement);
1817   dpyinfo->last_mouse_motion_frame = frame;
1818   r = &dpyinfo->last_mouse_glyph;
1820   /* Note, this doesn't get called for enter/leave, since we don't have a
1821      position.  Those are taken care of in the corresponding NSView methods. */
1823   /* has movement gone beyond last rect we were tracking? */
1824   if (x < r->origin.x || x >= r->origin.x + r->size.width
1825       || y < r->origin.y || y >= r->origin.y + r->size.height)
1826     {
1827       ns_update_begin (frame);
1828       frame->mouse_moved = 1;
1829       note_mouse_highlight (frame, x, y);
1830       remember_mouse_glyph (frame, x, y, r);
1831       ns_update_end (frame);
1832       return 1;
1833     }
1835   return 0;
1839 static void
1840 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1841                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1842                    Time *time)
1843 /* --------------------------------------------------------------------------
1844     External (hook): inform emacs about mouse position and hit parts.
1845     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1846     x & y should be position in the scrollbar (the whole bar, not the handle)
1847     and length of scrollbar respectively
1848    -------------------------------------------------------------------------- */
1850   id view;
1851   NSPoint position;
1852   Lisp_Object frame, tail;
1853   struct frame *f;
1854   struct ns_display_info *dpyinfo;
1856   NSTRACE (ns_mouse_position);
1858   if (*fp == NULL)
1859     {
1860       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1861       return;
1862     }
1864   dpyinfo = FRAME_DISPLAY_INFO (*fp);
1866   block_input ();
1868   if (dpyinfo->last_mouse_scroll_bar != nil && insist == 0)
1869     {
1870       /* TODO: we do not use this path at the moment because drag events will
1871            go directly to the EmacsScroller.  Leaving code in for now. */
1872       [dpyinfo->last_mouse_scroll_bar
1873           getMouseMotionPart: (int *)part window: bar_window x: x y: y];
1874       if (time)
1875         *time = dpyinfo->last_mouse_movement_time;
1876       dpyinfo->last_mouse_scroll_bar = nil;
1877     }
1878   else
1879     {
1880       /* Clear the mouse-moved flag for every frame on this display.  */
1881       FOR_EACH_FRAME (tail, frame)
1882         if (FRAME_NS_P (XFRAME (frame))
1883             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1884           XFRAME (frame)->mouse_moved = 0;
1886       dpyinfo->last_mouse_scroll_bar = nil;
1887       if (dpyinfo->last_mouse_frame
1888           && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
1889         f = dpyinfo->last_mouse_frame;
1890       else
1891         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1892                                     : SELECTED_FRAME ();
1894       if (f && FRAME_NS_P (f))
1895         {
1896           view = FRAME_NS_VIEW (*fp);
1898           position = [[view window] mouseLocationOutsideOfEventStream];
1899           position = [view convertPoint: position fromView: nil];
1900           remember_mouse_glyph (f, position.x, position.y,
1901                                 &dpyinfo->last_mouse_glyph);
1902 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1904           if (bar_window) *bar_window = Qnil;
1905           if (part) *part = 0; /*scroll_bar_handle; */
1907           if (x) XSETINT (*x, lrint (position.x));
1908           if (y) XSETINT (*y, lrint (position.y));
1909           if (time)
1910             *time = dpyinfo->last_mouse_movement_time;
1911           *fp = f;
1912         }
1913     }
1915   unblock_input ();
1919 static void
1920 ns_frame_up_to_date (struct frame *f)
1921 /* --------------------------------------------------------------------------
1922     External (hook): Fix up mouse highlighting right after a full update.
1923     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1924    -------------------------------------------------------------------------- */
1926   NSTRACE (ns_frame_up_to_date);
1928   if (FRAME_NS_P (f))
1929     {
1930       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1931       if (f == hlinfo->mouse_face_mouse_frame)
1932         {
1933           block_input ();
1934           ns_update_begin(f);
1935           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1936                                 hlinfo->mouse_face_mouse_x,
1937                                 hlinfo->mouse_face_mouse_y);
1938           ns_update_end(f);
1939           unblock_input ();
1940         }
1941     }
1945 static void
1946 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1947 /* --------------------------------------------------------------------------
1948     External (RIF): set frame mouse pointer type.
1949    -------------------------------------------------------------------------- */
1951   NSTRACE (ns_define_frame_cursor);
1952   if (FRAME_POINTER_TYPE (f) != cursor)
1953     {
1954       EmacsView *view = FRAME_NS_VIEW (f);
1955       FRAME_POINTER_TYPE (f) = cursor;
1956       [[view window] invalidateCursorRectsForView: view];
1957       /* Redisplay assumes this function also draws the changed frame
1958          cursor, but this function doesn't, so do it explicitly.  */
1959       x_update_cursor (f, 1);
1960     }
1965 /* ==========================================================================
1967     Keyboard handling
1969    ========================================================================== */
1972 static unsigned
1973 ns_convert_key (unsigned code)
1974 /* --------------------------------------------------------------------------
1975     Internal call used by NSView-keyDown.
1976    -------------------------------------------------------------------------- */
1978   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1979                                 / sizeof (convert_ns_to_X_keysym[0]));
1980   unsigned keysym;
1981   /* An array would be faster, but less easy to read. */
1982   for (keysym = 0; keysym < last_keysym; keysym += 2)
1983     if (code == convert_ns_to_X_keysym[keysym])
1984       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1985   return 0;
1986 /* if decide to use keyCode and Carbon table, use this line:
1987      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1991 char *
1992 x_get_keysym_name (int keysym)
1993 /* --------------------------------------------------------------------------
1994     Called by keyboard.c.  Not sure if the return val is important, except
1995     that it be unique.
1996    -------------------------------------------------------------------------- */
1998   static char value[16];
1999   NSTRACE (x_get_keysym_name);
2000   sprintf (value, "%d", keysym);
2001   return value;
2006 /* ==========================================================================
2008     Block drawing operations
2010    ========================================================================== */
2013 static void
2014 ns_redraw_scroll_bars (struct frame *f)
2016   int i;
2017   id view;
2018   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2019   NSTRACE (ns_redraw_scroll_bars);
2020   for (i =[subviews count]-1; i >= 0; i--)
2021     {
2022       view = [subviews objectAtIndex: i];
2023       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2024       [view display];
2025     }
2029 void
2030 ns_clear_frame (struct frame *f)
2031 /* --------------------------------------------------------------------------
2032       External (hook): Erase the entire frame
2033    -------------------------------------------------------------------------- */
2035   NSView *view = FRAME_NS_VIEW (f);
2036   NSRect r;
2038   NSTRACE (ns_clear_frame);
2040  /* comes on initial frame because we have
2041     after-make-frame-functions = select-frame */
2042  if (!FRAME_DEFAULT_FACE (f))
2043    return;
2045   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2047   r = [view bounds];
2049   block_input ();
2050   ns_focus (f, &r, 1);
2051   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2052   NSRectFill (r);
2053   ns_unfocus (f);
2055   /* as of 2006/11 or so this is now needed */
2056   ns_redraw_scroll_bars (f);
2057   unblock_input ();
2061 static void
2062 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2063 /* --------------------------------------------------------------------------
2064     External (RIF):  Clear section of frame
2065    -------------------------------------------------------------------------- */
2067   NSRect r = NSMakeRect (x, y, width, height);
2068   NSView *view = FRAME_NS_VIEW (f);
2069   struct face *face = FRAME_DEFAULT_FACE (f);
2071   if (!view || !face)
2072     return;
2074   NSTRACE (ns_clear_frame_area);
2076   r = NSIntersectionRect (r, [view frame]);
2077   ns_focus (f, &r, 1);
2078   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2080   NSRectFill (r);
2082   ns_unfocus (f);
2083   return;
2087 static void
2088 ns_scroll_run (struct window *w, struct run *run)
2089 /* --------------------------------------------------------------------------
2090     External (RIF):  Insert or delete n lines at line vpos
2091    -------------------------------------------------------------------------- */
2093   struct frame *f = XFRAME (w->frame);
2094   int x, y, width, height, from_y, to_y, bottom_y;
2096   NSTRACE (ns_scroll_run);
2098   /* begin copy from other terms */
2099   /* Get frame-relative bounding box of the text display area of W,
2100      without mode lines.  Include in this box the left and right
2101      fringe of W.  */
2102   window_box (w, ANY_AREA, &x, &y, &width, &height);
2104   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2105   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2106   bottom_y = y + height;
2108   if (to_y < from_y)
2109     {
2110       /* Scrolling up.  Make sure we don't copy part of the mode
2111          line at the bottom.  */
2112       if (from_y + run->height > bottom_y)
2113         height = bottom_y - from_y;
2114       else
2115         height = run->height;
2116     }
2117   else
2118     {
2119       /* Scrolling down.  Make sure we don't copy over the mode line.
2120          at the bottom.  */
2121       if (to_y + run->height > bottom_y)
2122         height = bottom_y - to_y;
2123       else
2124         height = run->height;
2125     }
2126   /* end copy from other terms */
2128   if (height == 0)
2129       return;
2131   block_input ();
2133   x_clear_cursor (w);
2135   {
2136     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2137     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2138     NSPoint dstOrigin = NSMakePoint (x, to_y);
2140     ns_focus (f, &dstRect, 1);
2141     NSCopyBits (0, srcRect , dstOrigin);
2142     ns_unfocus (f);
2143   }
2145   unblock_input ();
2149 static void
2150 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2151 /* --------------------------------------------------------------------------
2152     External (RIF): preparatory to fringe update after text was updated
2153    -------------------------------------------------------------------------- */
2155   struct frame *f;
2156   int width, height;
2158   NSTRACE (ns_after_update_window_line);
2160   /* begin copy from other terms */
2161   eassert (w);
2163   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2164     desired_row->redraw_fringe_bitmaps_p = 1;
2166   /* When a window has disappeared, make sure that no rest of
2167      full-width rows stays visible in the internal border.  */
2168   if (windows_or_buffers_changed
2169       && desired_row->full_width_p
2170       && (f = XFRAME (w->frame),
2171           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2172           width != 0)
2173       && (height = desired_row->visible_height,
2174           height > 0))
2175     {
2176       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2178       block_input ();
2179       ns_clear_frame_area (f, 0, y, width, height);
2180       ns_clear_frame_area (f,
2181                            FRAME_PIXEL_WIDTH (f) - width,
2182                            y, width, height);
2183       unblock_input ();
2184     }
2188 static void
2189 ns_shift_glyphs_for_insert (struct frame *f,
2190                            int x, int y, int width, int height,
2191                            int shift_by)
2192 /* --------------------------------------------------------------------------
2193     External (RIF): copy an area horizontally, don't worry about clearing src
2194    -------------------------------------------------------------------------- */
2196   NSRect srcRect = NSMakeRect (x, y, width, height);
2197   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2198   NSPoint dstOrigin = dstRect.origin;
2200   NSTRACE (ns_shift_glyphs_for_insert);
2202   ns_focus (f, &dstRect, 1);
2203   NSCopyBits (0, srcRect, dstOrigin);
2204   ns_unfocus (f);
2209 /* ==========================================================================
2211     Character encoding and metrics
2213    ========================================================================== */
2216 static void
2217 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2218 /* --------------------------------------------------------------------------
2219      External (RIF); compute left/right overhang of whole string and set in s
2220    -------------------------------------------------------------------------- */
2222   struct font *font = s->font;
2224   if (s->char2b)
2225     {
2226       struct font_metrics metrics;
2227       unsigned int codes[2];
2228       codes[0] = *(s->char2b);
2229       codes[1] = *(s->char2b + s->nchars - 1);
2231       font->driver->text_extents (font, codes, 2, &metrics);
2232       s->left_overhang = -metrics.lbearing;
2233       s->right_overhang
2234         = metrics.rbearing > metrics.width
2235         ? metrics.rbearing - metrics.width : 0;
2236     }
2237   else
2238     {
2239       s->left_overhang = 0;
2240       if (EQ (font->driver->type, Qns))
2241         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2242           FONT_HEIGHT (font) * 0.2 : 0;
2243       else
2244         s->right_overhang = 0;
2245     }
2250 /* ==========================================================================
2252     Fringe and cursor drawing
2254    ========================================================================== */
2257 extern int max_used_fringe_bitmap;
2258 static void
2259 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2260                       struct draw_fringe_bitmap_params *p)
2261 /* --------------------------------------------------------------------------
2262     External (RIF); fringe-related
2263    -------------------------------------------------------------------------- */
2265   struct frame *f = XFRAME (WINDOW_FRAME (w));
2266   struct face *face = p->face;
2267   static EmacsImage **bimgs = NULL;
2268   static int nBimgs = 0;
2270   /* grow bimgs if needed */
2271   if (nBimgs < max_used_fringe_bitmap)
2272     {
2273       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2274       memset (bimgs + nBimgs, 0,
2275               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2276       nBimgs = max_used_fringe_bitmap;
2277     }
2279   /* Must clip because of partially visible lines.  */
2280   ns_clip_to_row (w, row, ANY_AREA, YES);
2282   if (!p->overlay_p)
2283     {
2284       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2286       /* If the fringe is adjacent to the left (right) scroll bar of a
2287          leftmost (rightmost, respectively) window, then extend its
2288          background to the gap between the fringe and the bar.  */
2289       if ((WINDOW_LEFTMOST_P (w)
2290            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2291           || (WINDOW_RIGHTMOST_P (w)
2292               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2293         {
2294           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2296           if (sb_width > 0)
2297             {
2298               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2299               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2300                                     * FRAME_COLUMN_WIDTH (f));
2302               if (bx < 0)
2303                 {
2304                   /* Bitmap fills the fringe.  */
2305                   if (bar_area_x + bar_area_width == p->x)
2306                     bx = bar_area_x + sb_width;
2307                   else if (p->x + p->wd == bar_area_x)
2308                     bx = bar_area_x;
2309                   if (bx >= 0)
2310                     {
2311                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2313                       nx = bar_area_width - sb_width;
2314                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2315                                                             row->y));
2316                       ny = row->visible_height;
2317                     }
2318                 }
2319               else
2320                 {
2321                   if (bar_area_x + bar_area_width == bx)
2322                     {
2323                       bx = bar_area_x + sb_width;
2324                       nx += bar_area_width - sb_width;
2325                     }
2326                   else if (bx + nx == bar_area_x)
2327                     nx += bar_area_width - sb_width;
2328                 }
2329             }
2330         }
2332       if (bx >= 0 && nx > 0)
2333         {
2334           NSRect r = NSMakeRect (bx, by, nx, ny);
2335           NSRectClip (r);
2336           [ns_lookup_indexed_color (face->background, f) set];
2337           NSRectFill (r);
2338         }
2339     }
2341   if (p->which)
2342     {
2343       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2344       EmacsImage *img = bimgs[p->which - 1];
2346       if (!img)
2347         {
2348           unsigned short *bits = p->bits + p->dh;
2349           int len = p->h;
2350           int i;
2351           unsigned char *cbits = xmalloc (len);
2353           for (i = 0; i < len; i++)
2354             cbits[i] = ~(bits[i] & 0xff);
2355           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2356                                            flip: NO];
2357           bimgs[p->which - 1] = img;
2358           xfree (cbits);
2359         }
2361       NSRectClip (r);
2362       /* Since we composite the bitmap instead of just blitting it, we need
2363          to erase the whole background. */
2364       [ns_lookup_indexed_color(face->background, f) set];
2365       NSRectFill (r);
2366       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2367 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2368       [img drawInRect: r
2369               fromRect: NSZeroRect
2370              operation: NSCompositeSourceOver
2371               fraction: 1.0
2372            respectFlipped: YES
2373                 hints: nil];
2374 #else
2375       {
2376         NSPoint pt = r.origin;
2377         pt.y += p->h;
2378         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2379       }
2380 #endif
2381     }
2382   ns_unfocus (f);
2386 static void
2387 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2388                        int x, int y, enum text_cursor_kinds cursor_type,
2389                        int cursor_width, bool on_p, bool active_p)
2390 /* --------------------------------------------------------------------------
2391      External call (RIF): draw cursor.
2392      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2393    -------------------------------------------------------------------------- */
2395   NSRect r, s;
2396   int fx, fy, h, cursor_height;
2397   struct frame *f = WINDOW_XFRAME (w);
2398   struct glyph *phys_cursor_glyph;
2399   struct glyph *cursor_glyph;
2400   struct face *face;
2401   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2403   /* If cursor is out of bounds, don't draw garbage.  This can happen
2404      in mini-buffer windows when switching between echo area glyphs
2405      and mini-buffer.  */
2407   NSTRACE (dumpcursor);
2409   if (!on_p)
2410     return;
2412   w->phys_cursor_type = cursor_type;
2413   w->phys_cursor_on_p = on_p;
2415   if (cursor_type == NO_CURSOR)
2416     {
2417       w->phys_cursor_width = 0;
2418       return;
2419     }
2421   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2422     {
2423       if (glyph_row->exact_window_width_line_p
2424           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2425         {
2426           glyph_row->cursor_in_fringe_p = 1;
2427           draw_fringe_bitmap (w, glyph_row, 0);
2428         }
2429       return;
2430     }
2432   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2433      (other terminals do it the other way round).  We must set
2434      w->phys_cursor_width to the cursor width.  For bar cursors, that
2435      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2436   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2438   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2439      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2440   if (cursor_type == BAR_CURSOR)
2441     {
2442       if (cursor_width < 1)
2443         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2444       w->phys_cursor_width = cursor_width;
2445     }
2446   /* If we have an HBAR, "cursor_width" MAY specify height. */
2447   else if (cursor_type == HBAR_CURSOR)
2448     {
2449       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2450       fy += h - cursor_height;
2451       h = cursor_height;
2452     }
2454   r.origin.x = fx, r.origin.y = fy;
2455   r.size.height = h;
2456   r.size.width = w->phys_cursor_width;
2458   /* TODO: only needed in rare cases with last-resort font in HELLO..
2459      should we do this more efficiently? */
2460   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2463   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2464   if (face && NS_FACE_BACKGROUND (face)
2465       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2466     {
2467       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2468       hollow_color = FRAME_CURSOR_COLOR (f);
2469     }
2470   else
2471     [FRAME_CURSOR_COLOR (f) set];
2473 #ifdef NS_IMPL_COCOA
2474   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2475            atomic.  Cleaner ways of doing this should be investigated.
2476            One way would be to set a global variable DRAWING_CURSOR
2477            when making the call to draw_phys..(), don't focus in that
2478            case, then move the ns_unfocus() here after that call. */
2479   NSDisableScreenUpdates ();
2480 #endif
2482   switch (cursor_type)
2483     {
2484     case NO_CURSOR:
2485       break;
2486     case FILLED_BOX_CURSOR:
2487       NSRectFill (r);
2488       break;
2489     case HOLLOW_BOX_CURSOR:
2490       NSRectFill (r);
2491       [hollow_color set];
2492       NSRectFill (NSInsetRect (r, 1, 1));
2493       [FRAME_CURSOR_COLOR (f) set];
2494       break;
2495     case HBAR_CURSOR:
2496       NSRectFill (r);
2497       break;
2498     case BAR_CURSOR:
2499       s = r;
2500       /* If the character under cursor is R2L, draw the bar cursor
2501          on the right of its glyph, rather than on the left.  */
2502       cursor_glyph = get_phys_cursor_glyph (w);
2503       if ((cursor_glyph->resolved_level & 1) != 0)
2504         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2506       NSRectFill (s);
2507       break;
2508     }
2509   ns_unfocus (f);
2511   /* draw the character under the cursor */
2512   if (cursor_type != NO_CURSOR)
2513     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2515 #ifdef NS_IMPL_COCOA
2516   NSEnableScreenUpdates ();
2517 #endif
2522 static void
2523 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2524 /* --------------------------------------------------------------------------
2525      External (RIF): Draw a vertical line.
2526    -------------------------------------------------------------------------- */
2528   struct frame *f = XFRAME (WINDOW_FRAME (w));
2529   struct face *face;
2530   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2532   NSTRACE (ns_draw_vertical_window_border);
2534   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2535   if (face)
2536       [ns_lookup_indexed_color(face->foreground, f) set];
2538   ns_focus (f, &r, 1);
2539   NSRectFill(r);
2540   ns_unfocus (f);
2544 static void
2545 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2546 /* --------------------------------------------------------------------------
2547      External (RIF): Draw a window divider.
2548    -------------------------------------------------------------------------- */
2550   struct frame *f = XFRAME (WINDOW_FRAME (w));
2551   struct face *face;
2552   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2554   NSTRACE (ns_draw_window_divider);
2556   face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2557   if (face)
2558       [ns_lookup_indexed_color(face->foreground, f) set];
2560   ns_focus (f, &r, 1);
2561   NSRectFill(r);
2562   ns_unfocus (f);
2566 void
2567 show_hourglass (struct atimer *timer)
2569   if (hourglass_shown_p)
2570     return;
2572   block_input ();
2574   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2576   hourglass_shown_p = 1;
2577   unblock_input ();
2581 void
2582 hide_hourglass (void)
2584   if (!hourglass_shown_p)
2585     return;
2587   block_input ();
2589   /* TODO: remove NSProgressIndicator from all frames */
2591   hourglass_shown_p = 0;
2592   unblock_input ();
2597 /* ==========================================================================
2599     Glyph drawing operations
2601    ========================================================================== */
2603 static int
2604 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2605 /* --------------------------------------------------------------------------
2606     Wrapper utility to account for internal border width on full-width lines,
2607     and allow top full-width rows to hit the frame top.  nr should be pointer
2608     to two successive NSRects.  Number of rects actually used is returned.
2609    -------------------------------------------------------------------------- */
2611   int n = get_glyph_string_clip_rects (s, nr, 2);
2612   return n;
2615 /* --------------------------------------------------------------------
2616    Draw a wavy line under glyph string s. The wave fills wave_height
2617    pixels from y.
2619                     x          wave_length = 2
2620                                  --
2621                 y    *   *   *   *   *
2622                      |* * * * * * * * *
2623     wave_height = 3  | *   *   *   *
2624   --------------------------------------------------------------------- */
2626 static void
2627 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2629   int wave_height = 3, wave_length = 2;
2630   int y, dx, dy, odd, xmax;
2631   NSPoint a, b;
2632   NSRect waveClip;
2634   dx = wave_length;
2635   dy = wave_height - 1;
2636   y =  s->ybase - wave_height + 3;
2637   xmax = x + width;
2639   /* Find and set clipping rectangle */
2640   waveClip = NSMakeRect (x, y, width, wave_height);
2641   [[NSGraphicsContext currentContext] saveGraphicsState];
2642   NSRectClip (waveClip);
2644   /* Draw the waves */
2645   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2646   b.x = a.x + dx;
2647   odd = (int)(a.x/dx) % 2;
2648   a.y = b.y = y + 0.5;
2650   if (odd)
2651     a.y += dy;
2652   else
2653     b.y += dy;
2655   while (a.x <= xmax)
2656     {
2657       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2658       a.x = b.x, a.y = b.y;
2659       b.x += dx, b.y = y + 0.5 + odd*dy;
2660       odd = !odd;
2661     }
2663   /* Restore previous clipping rectangle(s) */
2664   [[NSGraphicsContext currentContext] restoreGraphicsState];
2669 void
2670 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2671                          NSColor *defaultCol, CGFloat width, CGFloat x)
2672 /* --------------------------------------------------------------------------
2673    Draw underline, overline, and strike-through on glyph string s.
2674    -------------------------------------------------------------------------- */
2676   if (s->for_overlaps)
2677     return;
2679   /* Do underline. */
2680   if (face->underline_p)
2681     {
2682       if (s->face->underline_type == FACE_UNDER_WAVE)
2683         {
2684           if (face->underline_defaulted_p)
2685             [defaultCol set];
2686           else
2687             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2689           ns_draw_underwave (s, width, x);
2690         }
2691       else if (s->face->underline_type == FACE_UNDER_LINE)
2692         {
2694           NSRect r;
2695           unsigned long thickness, position;
2697           /* If the prev was underlined, match its appearance. */
2698           if (s->prev && s->prev->face->underline_p
2699               && s->prev->face->underline_type == FACE_UNDER_LINE
2700               && s->prev->underline_thickness > 0)
2701             {
2702               thickness = s->prev->underline_thickness;
2703               position = s->prev->underline_position;
2704             }
2705           else
2706             {
2707               struct font *font;
2708               unsigned long descent;
2710               font=s->font;
2711               descent = s->y + s->height - s->ybase;
2713               /* Use underline thickness of font, defaulting to 1. */
2714               thickness = (font && font->underline_thickness > 0)
2715                 ? font->underline_thickness : 1;
2717               /* Determine the offset of underlining from the baseline. */
2718               if (x_underline_at_descent_line)
2719                 position = descent - thickness;
2720               else if (x_use_underline_position_properties
2721                        && font && font->underline_position >= 0)
2722                 position = font->underline_position;
2723               else if (font)
2724                 position = lround (font->descent / 2);
2725               else
2726                 position = underline_minimum_offset;
2728               position = max (position, underline_minimum_offset);
2730               /* Ensure underlining is not cropped. */
2731               if (descent <= position)
2732                 {
2733                   position = descent - 1;
2734                   thickness = 1;
2735                 }
2736               else if (descent < position + thickness)
2737                 thickness = 1;
2738             }
2740           s->underline_thickness = thickness;
2741           s->underline_position = position;
2743           r = NSMakeRect (x, s->ybase + position, width, thickness);
2745           if (face->underline_defaulted_p)
2746             [defaultCol set];
2747           else
2748             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2749           NSRectFill (r);
2750         }
2751     }
2752   /* Do overline. We follow other terms in using a thickness of 1
2753      and ignoring overline_margin. */
2754   if (face->overline_p)
2755     {
2756       NSRect r;
2757       r = NSMakeRect (x, s->y, width, 1);
2759       if (face->overline_color_defaulted_p)
2760         [defaultCol set];
2761       else
2762         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2763       NSRectFill (r);
2764     }
2766   /* Do strike-through.  We follow other terms for thickness and
2767      vertical position.*/
2768   if (face->strike_through_p)
2769     {
2770       NSRect r;
2771       unsigned long dy;
2773       dy = lrint ((s->height - 1) / 2);
2774       r = NSMakeRect (x, s->y + dy, width, 1);
2776       if (face->strike_through_color_defaulted_p)
2777         [defaultCol set];
2778       else
2779         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2780       NSRectFill (r);
2781     }
2784 static void
2785 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2786              char left_p, char right_p)
2787 /* --------------------------------------------------------------------------
2788     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2789     Note we can't just use an NSDrawRect command, because of the possibility
2790     of some sides not being drawn, and because the rect will be filled.
2791    -------------------------------------------------------------------------- */
2793   NSRect s = r;
2794   [col set];
2796   /* top, bottom */
2797   s.size.height = thickness;
2798   NSRectFill (s);
2799   s.origin.y += r.size.height - thickness;
2800   NSRectFill (s);
2802   s.size.height = r.size.height;
2803   s.origin.y = r.origin.y;
2805   /* left, right (optional) */
2806   s.size.width = thickness;
2807   if (left_p)
2808     NSRectFill (s);
2809   if (right_p)
2810     {
2811       s.origin.x += r.size.width - thickness;
2812       NSRectFill (s);
2813     }
2817 static void
2818 ns_draw_relief (NSRect r, int thickness, char raised_p,
2819                char top_p, char bottom_p, char left_p, char right_p,
2820                struct glyph_string *s)
2821 /* --------------------------------------------------------------------------
2822     Draw a relief rect inside r, optionally leaving some sides open.
2823     Note we can't just use an NSDrawBezel command, because of the possibility
2824     of some sides not being drawn, and because the rect will be filled.
2825    -------------------------------------------------------------------------- */
2827   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2828   NSColor *newBaseCol = nil;
2829   NSRect sr = r;
2831   NSTRACE (ns_draw_relief);
2833   /* set up colors */
2835   if (s->face->use_box_color_for_shadows_p)
2836     {
2837       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2838     }
2839 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2840            && s->img->pixmap
2841            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2842        {
2843          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2844        } */
2845   else
2846     {
2847       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2848     }
2850   if (newBaseCol == nil)
2851     newBaseCol = [NSColor grayColor];
2853   if (newBaseCol != baseCol)  /* TODO: better check */
2854     {
2855       [baseCol release];
2856       baseCol = [newBaseCol retain];
2857       [lightCol release];
2858       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2859       [darkCol release];
2860       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2861     }
2863   [(raised_p ? lightCol : darkCol) set];
2865   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2867   /* top */
2868   sr.size.height = thickness;
2869   if (top_p) NSRectFill (sr);
2871   /* left */
2872   sr.size.height = r.size.height;
2873   sr.size.width = thickness;
2874   if (left_p) NSRectFill (sr);
2876   [(raised_p ? darkCol : lightCol) set];
2878   /* bottom */
2879   sr.size.width = r.size.width;
2880   sr.size.height = thickness;
2881   sr.origin.y += r.size.height - thickness;
2882   if (bottom_p) NSRectFill (sr);
2884   /* right */
2885   sr.size.height = r.size.height;
2886   sr.origin.y = r.origin.y;
2887   sr.size.width = thickness;
2888   sr.origin.x += r.size.width - thickness;
2889   if (right_p) NSRectFill (sr);
2893 static void
2894 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2895 /* --------------------------------------------------------------------------
2896       Function modeled after x_draw_glyph_string_box ().
2897       Sets up parameters for drawing.
2898    -------------------------------------------------------------------------- */
2900   int right_x, last_x;
2901   char left_p, right_p;
2902   struct glyph *last_glyph;
2903   NSRect r;
2904   int thickness;
2905   struct face *face;
2907   if (s->hl == DRAW_MOUSE_FACE)
2908     {
2909       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2910       if (!face)
2911         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2912     }
2913   else
2914     face = s->face;
2916   thickness = face->box_line_width;
2918   NSTRACE (ns_dumpglyphs_box_or_relief);
2920   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2921             ? WINDOW_RIGHT_EDGE_X (s->w)
2922             : window_box_right (s->w, s->area));
2923   last_glyph = (s->cmp || s->img
2924                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2926   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2927               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2929   left_p = (s->first_glyph->left_box_line_p
2930             || (s->hl == DRAW_MOUSE_FACE
2931                 && (s->prev == NULL || s->prev->hl != s->hl)));
2932   right_p = (last_glyph->right_box_line_p
2933              || (s->hl == DRAW_MOUSE_FACE
2934                  && (s->next == NULL || s->next->hl != s->hl)));
2936   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2938   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2939   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2940     {
2941       ns_draw_box (r, abs (thickness),
2942                    ns_lookup_indexed_color (face->box_color, s->f),
2943                   left_p, right_p);
2944     }
2945   else
2946     {
2947       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2948                      1, 1, left_p, right_p, s);
2949     }
2953 static void
2954 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2955 /* --------------------------------------------------------------------------
2956       Modeled after x_draw_glyph_string_background, which draws BG in
2957       certain cases.  Others are left to the text rendering routine.
2958    -------------------------------------------------------------------------- */
2960   NSTRACE (ns_maybe_dumpglyphs_background);
2962   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2963     {
2964       int box_line_width = max (s->face->box_line_width, 0);
2965       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2966           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2967         {
2968           struct face *face;
2969           if (s->hl == DRAW_MOUSE_FACE)
2970             {
2971               face = FACE_FROM_ID (s->f,
2972                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2973               if (!face)
2974                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2975             }
2976           else
2977             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2978           if (!face->stipple)
2979             [(NS_FACE_BACKGROUND (face) != 0
2980               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2981               : FRAME_BACKGROUND_COLOR (s->f)) set];
2982           else
2983             {
2984               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
2985               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2986             }
2988           if (s->hl != DRAW_CURSOR)
2989             {
2990               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2991                                     s->background_width,
2992                                     s->height-2*box_line_width);
2993               NSRectFill (r);
2994             }
2996           s->background_filled_p = 1;
2997         }
2998     }
3002 static void
3003 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3004 /* --------------------------------------------------------------------------
3005       Renders an image and associated borders.
3006    -------------------------------------------------------------------------- */
3008   EmacsImage *img = s->img->pixmap;
3009   int box_line_vwidth = max (s->face->box_line_width, 0);
3010   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3011   int bg_x, bg_y, bg_height;
3012   int th;
3013   char raised_p;
3014   NSRect br;
3015   struct face *face;
3016   NSColor *tdCol;
3018   NSTRACE (ns_dumpglyphs_image);
3020   if (s->face->box != FACE_NO_BOX
3021       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3022     x += abs (s->face->box_line_width);
3024   bg_x = x;
3025   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3026   bg_height = s->height;
3027   /* other terms have this, but was causing problems w/tabbar mode */
3028   /* - 2 * box_line_vwidth; */
3030   if (s->slice.x == 0) x += s->img->hmargin;
3031   if (s->slice.y == 0) y += s->img->vmargin;
3033   /* Draw BG: if we need larger area than image itself cleared, do that,
3034      otherwise, since we composite the image under NS (instead of mucking
3035      with its background color), we must clear just the image area. */
3036   if (s->hl == DRAW_MOUSE_FACE)
3037     {
3038       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3039       if (!face)
3040        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3041     }
3042   else
3043     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3045   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3047   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3048       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3049     {
3050       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3051       s->background_filled_p = 1;
3052     }
3053   else
3054     {
3055       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3056     }
3058   NSRectFill (br);
3060   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3061   if (img != nil)
3062     {
3063 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
3064       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3065       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3066                               s->slice.width, s->slice.height);
3067       [img drawInRect: dr
3068              fromRect: ir
3069              operation: NSCompositeSourceOver
3070               fraction: 1.0
3071            respectFlipped: YES
3072                 hints: nil];
3073 #else
3074       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3075                   operation: NSCompositeSourceOver];
3076 #endif
3077     }
3079   if (s->hl == DRAW_CURSOR)
3080     {
3081     [FRAME_CURSOR_COLOR (s->f) set];
3082     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3083       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3084     else
3085       /* Currently on NS img->mask is always 0. Since
3086          get_window_cursor_type specifies a hollow box cursor when on
3087          a non-masked image we never reach this clause. But we put it
3088          in in anticipation of better support for image masks on
3089          NS. */
3090       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3091     }
3092   else
3093     {
3094       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3095     }
3097   /* Draw underline, overline, strike-through. */
3098   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3100   /* Draw relief, if requested */
3101   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3102     {
3103       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3104         {
3105           th = tool_bar_button_relief >= 0 ?
3106             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3107           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3108         }
3109       else
3110         {
3111           th = abs (s->img->relief);
3112           raised_p = (s->img->relief > 0);
3113         }
3115       r.origin.x = x - th;
3116       r.origin.y = y - th;
3117       r.size.width = s->slice.width + 2*th-1;
3118       r.size.height = s->slice.height + 2*th-1;
3119       ns_draw_relief (r, th, raised_p,
3120                       s->slice.y == 0,
3121                       s->slice.y + s->slice.height == s->img->height,
3122                       s->slice.x == 0,
3123                       s->slice.x + s->slice.width == s->img->width, s);
3124     }
3126   /* If there is no mask, the background won't be seen,
3127      so draw a rectangle on the image for the cursor.
3128      Do this for all images, getting transparency right is not reliable.  */
3129   if (s->hl == DRAW_CURSOR)
3130     {
3131       int thickness = abs (s->img->relief);
3132       if (thickness == 0) thickness = 1;
3133       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3134     }
3138 static void
3139 ns_dumpglyphs_stretch (struct glyph_string *s)
3141   NSRect r[2];
3142   int n, i;
3143   struct face *face;
3144   NSColor *fgCol, *bgCol;
3146   if (!s->background_filled_p)
3147     {
3148       n = ns_get_glyph_string_clip_rect (s, r);
3149       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3151       ns_focus (s->f, r, n);
3153       if (s->hl == DRAW_MOUSE_FACE)
3154        {
3155          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3156          if (!face)
3157            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3158        }
3159       else
3160        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3162       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3163       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3165       for (i = 0; i < n; ++i)
3166         {
3167           if (!s->row->full_width_p)
3168             {
3169               int overrun, leftoverrun;
3171               /* truncate to avoid overwriting fringe and/or scrollbar */
3172               overrun = max (0, (s->x + s->background_width)
3173                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3174                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3175               r[i].size.width -= overrun;
3177               /* truncate to avoid overwriting to left of the window box */
3178               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3179                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3181               if (leftoverrun > 0)
3182                 {
3183                   r[i].origin.x += leftoverrun;
3184                   r[i].size.width -= leftoverrun;
3185                 }
3187               /* XXX: Try to work between problem where a stretch glyph on
3188                  a partially-visible bottom row will clear part of the
3189                  modeline, and another where list-buffers headers and similar
3190                  rows erroneously have visible_height set to 0.  Not sure
3191                  where this is coming from as other terms seem not to show. */
3192               r[i].size.height = min (s->height, s->row->visible_height);
3193             }
3195           [bgCol set];
3197           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3198              overwriting cursor (usually when cursor on a tab) */
3199           if (s->hl == DRAW_CURSOR)
3200             {
3201               CGFloat x, width;
3203               x = r[i].origin.x;
3204               width = s->w->phys_cursor_width;
3205               r[i].size.width -= width;
3206               r[i].origin.x += width;
3208               NSRectFill (r[i]);
3210               /* Draw overlining, etc. on the cursor. */
3211               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3212                 ns_draw_text_decoration (s, face, bgCol, width, x);
3213               else
3214                 ns_draw_text_decoration (s, face, fgCol, width, x);
3215             }
3216           else
3217             {
3218               NSRectFill (r[i]);
3219             }
3221           /* Draw overlining, etc. on the stretch glyph (or the part
3222              of the stretch glyph after the cursor). */
3223           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3224                                    r[i].origin.x);
3225         }
3226       ns_unfocus (s->f);
3227       s->background_filled_p = 1;
3228     }
3232 static void
3233 ns_draw_glyph_string (struct glyph_string *s)
3234 /* --------------------------------------------------------------------------
3235       External (RIF): Main draw-text call.
3236    -------------------------------------------------------------------------- */
3238   /* TODO (optimize): focus for box and contents draw */
3239   NSRect r[2];
3240   int n, flags;
3241   char box_drawn_p = 0;
3242   struct font *font = s->face->font;
3243   if (! font) font = FRAME_FONT (s->f);
3245   NSTRACE (ns_draw_glyph_string);
3247   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3248     {
3249       int width;
3250       struct glyph_string *next;
3252       for (width = 0, next = s->next;
3253            next && width < s->right_overhang;
3254            width += next->width, next = next->next)
3255         if (next->first_glyph->type != IMAGE_GLYPH)
3256           {
3257             if (next->first_glyph->type != STRETCH_GLYPH)
3258               {
3259                 n = ns_get_glyph_string_clip_rect (s->next, r);
3260                 ns_focus (s->f, r, n);
3261                 ns_maybe_dumpglyphs_background (s->next, 1);
3262                 ns_unfocus (s->f);
3263               }
3264             else
3265               {
3266                 ns_dumpglyphs_stretch (s->next);
3267               }
3268             next->num_clips = 0;
3269           }
3270     }
3272   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3273         && (s->first_glyph->type == CHAR_GLYPH
3274             || s->first_glyph->type == COMPOSITE_GLYPH))
3275     {
3276       n = ns_get_glyph_string_clip_rect (s, r);
3277       ns_focus (s->f, r, n);
3278       ns_maybe_dumpglyphs_background (s, 1);
3279       ns_dumpglyphs_box_or_relief (s);
3280       ns_unfocus (s->f);
3281       box_drawn_p = 1;
3282     }
3284   switch (s->first_glyph->type)
3285     {
3287     case IMAGE_GLYPH:
3288       n = ns_get_glyph_string_clip_rect (s, r);
3289       ns_focus (s->f, r, n);
3290       ns_dumpglyphs_image (s, r[0]);
3291       ns_unfocus (s->f);
3292       break;
3294     case STRETCH_GLYPH:
3295       ns_dumpglyphs_stretch (s);
3296       break;
3298     case CHAR_GLYPH:
3299     case COMPOSITE_GLYPH:
3300       n = ns_get_glyph_string_clip_rect (s, r);
3301       ns_focus (s->f, r, n);
3303       if (s->for_overlaps || (s->cmp_from > 0
3304                               && ! s->first_glyph->u.cmp.automatic))
3305         s->background_filled_p = 1;
3306       else
3307         ns_maybe_dumpglyphs_background
3308           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3310       flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3311         (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3312          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3313           NS_DUMPGLYPH_NORMAL));
3315       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3316         {
3317           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3318           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3319           NS_FACE_FOREGROUND (s->face) = tmp;
3320         }
3322       font->driver->draw
3323         (s, 0, s->nchars, s->x, s->y,
3324          (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3325          || flags == NS_DUMPGLYPH_MOUSEFACE);
3327       {
3328         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3329                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3330                                                    s->f)
3331                         : FRAME_FOREGROUND_COLOR (s->f));
3332         [col set];
3334         /* Draw underline, overline, strike-through. */
3335         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3336       }
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       ns_unfocus (s->f);
3346       break;
3348     case GLYPHLESS_GLYPH:
3349       n = ns_get_glyph_string_clip_rect (s, r);
3350       ns_focus (s->f, r, n);
3352       if (s->for_overlaps || (s->cmp_from > 0
3353                               && ! s->first_glyph->u.cmp.automatic))
3354         s->background_filled_p = 1;
3355       else
3356         ns_maybe_dumpglyphs_background
3357           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3358       /* ... */
3359       /* Not yet implemented.  */
3360       /* ... */
3361       ns_unfocus (s->f);
3362       break;
3364     default:
3365       emacs_abort ();
3366     }
3368   /* Draw box if not done already. */
3369   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3370     {
3371       n = ns_get_glyph_string_clip_rect (s, r);
3372       ns_focus (s->f, r, n);
3373       ns_dumpglyphs_box_or_relief (s);
3374       ns_unfocus (s->f);
3375     }
3377   s->num_clips = 0;
3382 /* ==========================================================================
3384     Event loop
3386    ========================================================================== */
3389 static void
3390 ns_send_appdefined (int value)
3391 /* --------------------------------------------------------------------------
3392     Internal: post an appdefined event which EmacsApp-sendEvent will
3393               recognize and take as a command to halt the event loop.
3394    -------------------------------------------------------------------------- */
3396   /*NSTRACE (ns_send_appdefined); */
3398 #ifdef NS_IMPL_GNUSTEP
3399   // GNUStep needs postEvent to happen on the main thread.
3400   if (! [[NSThread currentThread] isMainThread])
3401     {
3402       EmacsApp *app = (EmacsApp *)NSApp;
3403       app->nextappdefined = value;
3404       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3405                             withObject:nil
3406                          waitUntilDone:YES];
3407       return;
3408     }
3409 #endif
3411   /* Only post this event if we haven't already posted one.  This will end
3412        the [NXApp run] main loop after having processed all events queued at
3413        this moment.  */
3414   if (send_appdefined)
3415     {
3416       NSEvent *nxev;
3418       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3419       send_appdefined = NO;
3421       /* Don't need wakeup timer any more */
3422       if (timed_entry)
3423         {
3424           [timed_entry invalidate];
3425           [timed_entry release];
3426           timed_entry = nil;
3427         }
3429       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3430                                 location: NSMakePoint (0, 0)
3431                            modifierFlags: 0
3432                                timestamp: 0
3433                             windowNumber: [[NSApp mainWindow] windowNumber]
3434                                  context: [NSApp context]
3435                                  subtype: 0
3436                                    data1: value
3437                                    data2: 0];
3439       /* Post an application defined event on the event queue.  When this is
3440          received the [NXApp run] will return, thus having processed all
3441          events which are currently queued.  */
3442       [NSApp postEvent: nxev atStart: NO];
3443     }
3446 #ifdef HAVE_NATIVE_FS
3447 static void
3448 check_native_fs ()
3450   Lisp_Object frame, tail;
3452   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3453     return;
3455   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3457   FOR_EACH_FRAME (tail, frame)
3458     {
3459       struct frame *f = XFRAME (frame);
3460       if (FRAME_NS_P (f))
3461         {
3462           EmacsView *view = FRAME_NS_VIEW (f);
3463           [view updateCollectionBehaviour];
3464         }
3465     }
3467 #endif
3469 /* GNUStep and OSX <= 10.4 does not have cancelTracking.  */
3470 #if defined (NS_IMPL_COCOA) && \
3471   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
3472 /* Check if menu open should be cancelled or continued as normal.  */
3473 void
3474 ns_check_menu_open (NSMenu *menu)
3476   /* Click in menu bar? */
3477   NSArray *a = [[NSApp mainMenu] itemArray];
3478   int i;
3479   BOOL found = NO;
3481   if (menu == nil) // Menu tracking ended.
3482     {
3483       if (menu_will_open_state == MENU_OPENING)
3484         menu_will_open_state = MENU_NONE;
3485       return;
3486     }
3488   for (i = 0; ! found && i < [a count]; i++)
3489     found = menu == [[a objectAtIndex:i] submenu];
3490   if (found)
3491     {
3492       if (menu_will_open_state == MENU_NONE && emacs_event)
3493         {
3494           NSEvent *theEvent = [NSApp currentEvent];
3495           struct frame *emacsframe = SELECTED_FRAME ();
3497           [menu cancelTracking];
3498           menu_will_open_state = MENU_PENDING;
3499           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3500           EV_TRAILER (theEvent);
3502           CGEventRef ourEvent = CGEventCreate (NULL);
3503           menu_mouse_point = CGEventGetLocation (ourEvent);
3504           CFRelease (ourEvent);
3505         }
3506       else if (menu_will_open_state == MENU_OPENING)
3507         {
3508           menu_will_open_state = MENU_NONE;
3509         }
3510     }
3513 /* Redo saved menu click if state is MENU_PENDING.  */
3514 void
3515 ns_check_pending_open_menu ()
3517   if (menu_will_open_state == MENU_PENDING)
3518     {
3519       CGEventSourceRef source
3520         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3522       CGEventRef event = CGEventCreateMouseEvent (source,
3523                                                   kCGEventLeftMouseDown,
3524                                                   menu_mouse_point,
3525                                                   kCGMouseButtonLeft);
3526       CGEventSetType (event, kCGEventLeftMouseDown);
3527       CGEventPost (kCGHIDEventTap, event);
3528       CFRelease (event);
3529       CFRelease (source);
3531       menu_will_open_state = MENU_OPENING;
3532     }
3534 #endif /* NS_IMPL_COCOA) && >= MAC_OS_X_VERSION_10_5 */
3536 static int
3537 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3538 /* --------------------------------------------------------------------------
3539      External (hook): Post an event to ourself and keep reading events until
3540      we read it back again.  In effect process all events which were waiting.
3541      From 21+ we have to manage the event buffer ourselves.
3542    -------------------------------------------------------------------------- */
3544   struct input_event ev;
3545   int nevents;
3547 /* NSTRACE (ns_read_socket); */
3549 #ifdef HAVE_NATIVE_FS
3550   check_native_fs ();
3551 #endif
3553   if ([NSApp modalWindow] != nil)
3554     return -1;
3556   if (hold_event_q.nr > 0)
3557     {
3558       int i;
3559       for (i = 0; i < hold_event_q.nr; ++i)
3560         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3561       hold_event_q.nr = 0;
3562       return i;
3563     }
3565   block_input ();
3566   n_emacs_events_pending = 0;
3567   EVENT_INIT (ev);
3568   emacs_event = &ev;
3569   q_event_ptr = hold_quit;
3571   /* we manage autorelease pools by allocate/reallocate each time around
3572      the loop; strict nesting is occasionally violated but seems not to
3573      matter.. earlier methods using full nesting caused major memory leaks */
3574   [outerpool release];
3575   outerpool = [[NSAutoreleasePool alloc] init];
3577   /* If have pending open-file requests, attend to the next one of those. */
3578   if (ns_pending_files && [ns_pending_files count] != 0
3579       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3580     {
3581       [ns_pending_files removeObjectAtIndex: 0];
3582     }
3583   /* Deal with pending service requests. */
3584   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3585     && [(EmacsApp *)
3586          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3587                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3588     {
3589       [ns_pending_service_names removeObjectAtIndex: 0];
3590       [ns_pending_service_args removeObjectAtIndex: 0];
3591     }
3592   else
3593     {
3594       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3595          to ourself, otherwise [NXApp run] will never exit.  */
3596       send_appdefined = YES;
3597       ns_send_appdefined (-1);
3599       if (++apploopnr != 1)
3600         {
3601           emacs_abort ();
3602         }
3603       [NSApp run];
3604       --apploopnr;
3605     }
3607   nevents = n_emacs_events_pending;
3608   n_emacs_events_pending = 0;
3609   emacs_event = q_event_ptr = NULL;
3610   unblock_input ();
3612   return nevents;
3617 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3618            fd_set *exceptfds, struct timespec const *timeout,
3619            sigset_t const *sigmask)
3620 /* --------------------------------------------------------------------------
3621      Replacement for select, checking for events
3622    -------------------------------------------------------------------------- */
3624   int result;
3625   int t, k, nr = 0;
3626   struct input_event event;
3627   char c;
3629 /*  NSTRACE (ns_select); */
3631 #ifdef HAVE_NATIVE_FS
3632   check_native_fs ();
3633 #endif
3635   if (hold_event_q.nr > 0)
3636     {
3637       /* We already have events pending. */
3638       raise (SIGIO);
3639       errno = EINTR;
3640       return -1;
3641     }
3643   for (k = 0; k < nfds+1; k++)
3644     {
3645       if (readfds && FD_ISSET(k, readfds)) ++nr;
3646       if (writefds && FD_ISSET(k, writefds)) ++nr;
3647     }
3649   if (NSApp == nil
3650       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3651     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3653   [outerpool release];
3654   outerpool = [[NSAutoreleasePool alloc] init];
3657   send_appdefined = YES;
3658   if (nr > 0)
3659     {
3660       pthread_mutex_lock (&select_mutex);
3661       select_nfds = nfds;
3662       select_valid = 0;
3663       if (readfds)
3664         {
3665           select_readfds = *readfds;
3666           select_valid += SELECT_HAVE_READ;
3667         }
3668       if (writefds)
3669         {
3670           select_writefds = *writefds;
3671           select_valid += SELECT_HAVE_WRITE;
3672         }
3674       if (timeout)
3675         {
3676           select_timeout = *timeout;
3677           select_valid += SELECT_HAVE_TMO;
3678         }
3680       pthread_mutex_unlock (&select_mutex);
3682       /* Inform fd_handler that select should be called */
3683       c = 'g';
3684       emacs_write_sig (selfds[1], &c, 1);
3685     }
3686   else if (nr == 0 && timeout)
3687     {
3688       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3689       double time = timespectod (*timeout);
3690       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3691                                                       target: NSApp
3692                                                     selector:
3693                                   @selector (timeout_handler:)
3694                                                     userInfo: 0
3695                                                      repeats: NO]
3696                       retain];
3697     }
3698   else /* No timeout and no file descriptors, can this happen?  */
3699     {
3700       /* Send appdefined so we exit from the loop */
3701       ns_send_appdefined (-1);
3702     }
3704   EVENT_INIT (event);
3705   block_input ();
3706   emacs_event = &event;
3707   if (++apploopnr != 1)
3708     {
3709       emacs_abort ();
3710     }
3711   [NSApp run];
3712   --apploopnr;
3713   emacs_event = NULL;
3714   if (nr > 0 && readfds)
3715     {
3716       c = 's';
3717       emacs_write_sig (selfds[1], &c, 1);
3718     }
3719   unblock_input ();
3721   t = last_appdefined_event_data;
3723   if (t != NO_APPDEFINED_DATA)
3724     {
3725       last_appdefined_event_data = NO_APPDEFINED_DATA;
3727       if (t == -2)
3728         {
3729           /* The NX_APPDEFINED event we received was a timeout. */
3730           result = 0;
3731         }
3732       else if (t == -1)
3733         {
3734           /* The NX_APPDEFINED event we received was the result of
3735              at least one real input event arriving.  */
3736           errno = EINTR;
3737           result = -1;
3738         }
3739       else
3740         {
3741           /* Received back from select () in fd_handler; copy the results */
3742           pthread_mutex_lock (&select_mutex);
3743           if (readfds) *readfds = select_readfds;
3744           if (writefds) *writefds = select_writefds;
3745           pthread_mutex_unlock (&select_mutex);
3746           result = t;
3747         }
3748     }
3749   else
3750     {
3751       errno = EINTR;
3752       result = -1;
3753     }
3755   return result;
3760 /* ==========================================================================
3762     Scrollbar handling
3764    ========================================================================== */
3767 static void
3768 ns_set_vertical_scroll_bar (struct window *window,
3769                            int portion, int whole, int position)
3770 /* --------------------------------------------------------------------------
3771       External (hook): Update or add scrollbar
3772    -------------------------------------------------------------------------- */
3774   Lisp_Object win;
3775   NSRect r, v;
3776   struct frame *f = XFRAME (WINDOW_FRAME (window));
3777   EmacsView *view = FRAME_NS_VIEW (f);
3778   int window_y, window_height;
3779   int top, left, height, width, sb_width, sb_left;
3780   EmacsScroller *bar;
3781   BOOL fringe_extended_p;
3783   /* optimization; display engine sends WAY too many of these.. */
3784   if (!NILP (window->vertical_scroll_bar))
3785     {
3786       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3787       if ([bar checkSamePosition: position portion: portion whole: whole])
3788         {
3789           if (view->scrollbarsNeedingUpdate == 0)
3790             {
3791               if (!windows_or_buffers_changed)
3792                   return;
3793             }
3794           else
3795             view->scrollbarsNeedingUpdate--;
3796         }
3797     }
3799   NSTRACE (ns_set_vertical_scroll_bar);
3801   /* Get dimensions.  */
3802   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3803   top = window_y;
3804   height = window_height;
3805   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3806   left = WINDOW_SCROLL_BAR_AREA_X (window);
3808   /* allow for displaying a skinnier scrollbar than char area allotted */
3809   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3810     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3811   sb_left = left;
3813   r = NSMakeRect (sb_left, top, sb_width, height);
3814   /* the parent view is flipped, so we need to flip y value */
3815   v = [view frame];
3816   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3818   fringe_extended_p = WINDOW_FRINGE_EXTENDED_P (window);
3820   XSETWINDOW (win, window);
3821   block_input ();
3823   /* we want at least 5 lines to display a scrollbar */
3824   if (WINDOW_TOTAL_LINES (window) < 5)
3825     {
3826       if (!NILP (window->vertical_scroll_bar))
3827         {
3828           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3829           [bar removeFromSuperview];
3830           wset_vertical_scroll_bar (window, Qnil);
3831         }
3832       ns_clear_frame_area (f, sb_left, top, width, height);
3833       unblock_input ();
3834       return;
3835     }
3837   if (NILP (window->vertical_scroll_bar))
3838     {
3839       if (width > 0 && height > 0)
3840         {
3841           if (fringe_extended_p)
3842             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3843           else
3844             ns_clear_frame_area (f, left, top, width, height);
3845         }
3847       bar = [[EmacsScroller alloc] initFrame: r window: win];
3848       wset_vertical_scroll_bar (window, make_save_ptr (bar));
3849     }
3850   else
3851     {
3852       NSRect oldRect;
3853       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3854       oldRect = [bar frame];
3855       r.size.width = oldRect.size.width;
3856       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3857         {
3858           if (oldRect.origin.x != r.origin.x)
3859               ns_clear_frame_area (f, sb_left, top, width, height);
3860           [bar setFrame: r];
3861         }
3862     }
3864   [bar setPosition: position portion: portion whole: whole];
3865   unblock_input ();
3869 static void
3870 ns_condemn_scroll_bars (struct frame *f)
3871 /* --------------------------------------------------------------------------
3872      External (hook): arrange for all frame's scrollbars to be removed
3873      at next call to judge_scroll_bars, except for those redeemed.
3874    -------------------------------------------------------------------------- */
3876   int i;
3877   id view;
3878   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3880   NSTRACE (ns_condemn_scroll_bars);
3882   for (i =[subviews count]-1; i >= 0; i--)
3883     {
3884       view = [subviews objectAtIndex: i];
3885       if ([view isKindOfClass: [EmacsScroller class]])
3886         [view condemn];
3887     }
3891 static void
3892 ns_redeem_scroll_bar (struct window *window)
3893 /* --------------------------------------------------------------------------
3894      External (hook): arrange to spare this window's scrollbar
3895      at next call to judge_scroll_bars.
3896    -------------------------------------------------------------------------- */
3898   id bar;
3899   NSTRACE (ns_redeem_scroll_bar);
3900   if (!NILP (window->vertical_scroll_bar))
3901     {
3902       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3903       [bar reprieve];
3904     }
3908 static void
3909 ns_judge_scroll_bars (struct frame *f)
3910 /* --------------------------------------------------------------------------
3911      External (hook): destroy all scrollbars on frame that weren't
3912      redeemed after call to condemn_scroll_bars.
3913    -------------------------------------------------------------------------- */
3915   int i;
3916   id view;
3917   EmacsView *eview = FRAME_NS_VIEW (f);
3918   NSArray *subviews = [[eview superview] subviews];
3919   BOOL removed = NO;
3921   NSTRACE (ns_judge_scroll_bars);
3922   for (i = [subviews count]-1; i >= 0; --i)
3923     {
3924       view = [subviews objectAtIndex: i];
3925       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3926       [view judge];
3927       removed = YES;
3928     }
3930   if (removed)
3931     [eview updateFrameSize: NO];
3934 /* ==========================================================================
3936     Initialization
3938    ========================================================================== */
3941 x_display_pixel_height (struct ns_display_info *dpyinfo)
3943   NSArray *screens = [NSScreen screens];
3944   NSEnumerator *enumerator = [screens objectEnumerator];
3945   NSScreen *screen;
3946   NSRect frame;
3948   frame = NSZeroRect;
3949   while ((screen = [enumerator nextObject]) != nil)
3950     frame = NSUnionRect (frame, [screen frame]);
3952   return NSHeight (frame);
3956 x_display_pixel_width (struct ns_display_info *dpyinfo)
3958   NSArray *screens = [NSScreen screens];
3959   NSEnumerator *enumerator = [screens objectEnumerator];
3960   NSScreen *screen;
3961   NSRect frame;
3963   frame = NSZeroRect;
3964   while ((screen = [enumerator nextObject]) != nil)
3965     frame = NSUnionRect (frame, [screen frame]);
3967   return NSWidth (frame);
3971 static Lisp_Object ns_string_to_lispmod (const char *s)
3972 /* --------------------------------------------------------------------------
3973      Convert modifier name to lisp symbol
3974    -------------------------------------------------------------------------- */
3976   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3977     return Qmeta;
3978   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3979     return Qsuper;
3980   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3981     return Qcontrol;
3982   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3983     return Qalt;
3984   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3985     return Qhyper;
3986   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3987     return Qnone;
3988   else
3989     return Qnil;
3993 static void
3994 ns_default (const char *parameter, Lisp_Object *result,
3995            Lisp_Object yesval, Lisp_Object noval,
3996            BOOL is_float, BOOL is_modstring)
3997 /* --------------------------------------------------------------------------
3998       Check a parameter value in user's preferences
3999    -------------------------------------------------------------------------- */
4001   const char *value = ns_get_defaults_value (parameter);
4003   if (value)
4004     {
4005       double f;
4006       char *pos;
4007       if (c_strcasecmp (value, "YES") == 0)
4008         *result = yesval;
4009       else if (c_strcasecmp (value, "NO") == 0)
4010         *result = noval;
4011       else if (is_float && (f = strtod (value, &pos), pos != value))
4012         *result = make_float (f);
4013       else if (is_modstring && value)
4014         *result = ns_string_to_lispmod (value);
4015       else fprintf (stderr,
4016                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4017     }
4021 static void
4022 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4023 /* --------------------------------------------------------------------------
4024       Initialize global info and storage for display.
4025    -------------------------------------------------------------------------- */
4027     NSScreen *screen = [NSScreen mainScreen];
4028     NSWindowDepth depth = [screen depth];
4030     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4031     dpyinfo->resy = 72.27;
4032     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4033                                                   NSColorSpaceFromDepth (depth)]
4034                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4035                                                  NSColorSpaceFromDepth (depth)];
4036     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4037     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4038     dpyinfo->color_table->colors = NULL;
4039     dpyinfo->root_window = 42; /* a placeholder.. */
4040     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4041     dpyinfo->n_fonts = 0;
4042     dpyinfo->smallest_font_height = 1;
4043     dpyinfo->smallest_char_width = 1;
4045     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4049 /* This and next define (many of the) public functions in this file. */
4050 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4051          with using despite presence in the "system dependent" redisplay
4052          interface.  In addition, many of the ns_ methods have code that is
4053          shared with all terms, indicating need for further refactoring. */
4054 extern frame_parm_handler ns_frame_parm_handlers[];
4055 static struct redisplay_interface ns_redisplay_interface =
4057   ns_frame_parm_handlers,
4058   x_produce_glyphs,
4059   x_write_glyphs,
4060   x_insert_glyphs,
4061   x_clear_end_of_line,
4062   ns_scroll_run,
4063   ns_after_update_window_line,
4064   ns_update_window_begin,
4065   ns_update_window_end,
4066   0, /* flush_display */
4067   x_clear_window_mouse_face,
4068   x_get_glyph_overhangs,
4069   x_fix_overlapping_area,
4070   ns_draw_fringe_bitmap,
4071   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4072   0, /* destroy_fringe_bitmap */
4073   ns_compute_glyph_string_overhangs,
4074   ns_draw_glyph_string,
4075   ns_define_frame_cursor,
4076   ns_clear_frame_area,
4077   ns_draw_window_cursor,
4078   ns_draw_vertical_window_border,
4079   ns_draw_window_divider,
4080   ns_shift_glyphs_for_insert
4084 static void
4085 ns_delete_display (struct ns_display_info *dpyinfo)
4087   /* TODO... */
4091 /* This function is called when the last frame on a display is deleted. */
4092 static void
4093 ns_delete_terminal (struct terminal *terminal)
4095   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4097   /* Protect against recursive calls.  delete_frame in
4098      delete_terminal calls us back when it deletes our last frame.  */
4099   if (!terminal->name)
4100     return;
4102   block_input ();
4104   x_destroy_all_bitmaps (dpyinfo);
4105   ns_delete_display (dpyinfo);
4106   unblock_input ();
4110 static struct terminal *
4111 ns_create_terminal (struct ns_display_info *dpyinfo)
4112 /* --------------------------------------------------------------------------
4113       Set up use of NS before we make the first connection.
4114    -------------------------------------------------------------------------- */
4116   struct terminal *terminal;
4118   NSTRACE (ns_create_terminal);
4120   terminal = create_terminal ();
4122   terminal->type = output_ns;
4123   terminal->display_info.ns = dpyinfo;
4124   dpyinfo->terminal = terminal;
4126   terminal->rif = &ns_redisplay_interface;
4128   terminal->clear_frame_hook = ns_clear_frame;
4129   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4130   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
4131   terminal->ring_bell_hook = ns_ring_bell;
4132   terminal->reset_terminal_modes_hook = NULL;
4133   terminal->set_terminal_modes_hook = NULL;
4134   terminal->update_begin_hook = ns_update_begin;
4135   terminal->update_end_hook = ns_update_end;
4136   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4137   terminal->read_socket_hook = ns_read_socket;
4138   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4139   terminal->mouse_position_hook = ns_mouse_position;
4140   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4141   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4143   terminal->fullscreen_hook = ns_fullscreen_hook;
4145   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4146   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4147   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4148   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4150   terminal->delete_frame_hook = x_destroy_window;
4151   terminal->delete_terminal_hook = ns_delete_terminal;
4153   return terminal;
4157 struct ns_display_info *
4158 ns_term_init (Lisp_Object display_name)
4159 /* --------------------------------------------------------------------------
4160      Start the Application and get things rolling.
4161    -------------------------------------------------------------------------- */
4163   struct terminal *terminal;
4164   struct ns_display_info *dpyinfo;
4165   static int ns_initialized = 0;
4166   Lisp_Object tmp;
4168   if (ns_initialized) return x_display_list;
4169   ns_initialized = 1;
4171   NSTRACE (ns_term_init);
4173   [outerpool release];
4174   outerpool = [[NSAutoreleasePool alloc] init];
4176   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4177   /*GSDebugAllocationActive (YES); */
4178   block_input ();
4180   baud_rate = 38400;
4181   Fset_input_interrupt_mode (Qnil);
4183   if (selfds[0] == -1)
4184     {
4185       if (emacs_pipe (selfds) != 0)
4186         {
4187           fprintf (stderr, "Failed to create pipe: %s\n",
4188                    emacs_strerror (errno));
4189           emacs_abort ();
4190         }
4192       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4193       FD_ZERO (&select_readfds);
4194       FD_ZERO (&select_writefds);
4195       pthread_mutex_init (&select_mutex, NULL);
4196     }
4198   ns_pending_files = [[NSMutableArray alloc] init];
4199   ns_pending_service_names = [[NSMutableArray alloc] init];
4200   ns_pending_service_args = [[NSMutableArray alloc] init];
4202 /* Start app and create the main menu, window, view.
4203      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4204      The view will then ask the NSApp to stop and return to Emacs. */
4205   [EmacsApp sharedApplication];
4206   if (NSApp == nil)
4207     return NULL;
4208   [NSApp setDelegate: NSApp];
4210   /* Start the select thread.  */
4211   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4212                            toTarget:NSApp
4213                          withObject:nil];
4215   /* debugging: log all notifications */
4216   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4217                                          selector: @selector (logNotification:)
4218                                              name: nil object: nil]; */
4220   dpyinfo = xzalloc (sizeof *dpyinfo);
4222   ns_initialize_display_info (dpyinfo);
4223   terminal = ns_create_terminal (dpyinfo);
4225   terminal->kboard = allocate_kboard (Qns);
4226   /* Don't let the initial kboard remain current longer than necessary.
4227      That would cause problems if a file loaded on startup tries to
4228      prompt in the mini-buffer.  */
4229   if (current_kboard == initial_kboard)
4230     current_kboard = terminal->kboard;
4231   terminal->kboard->reference_count++;
4233   dpyinfo->next = x_display_list;
4234   x_display_list = dpyinfo;
4236   dpyinfo->name_list_element = Fcons (display_name, Qnil);
4238   terminal->name = xstrdup (SSDATA (display_name));
4240   unblock_input ();
4242   if (!inhibit_x_resources)
4243     {
4244       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4245                  Qt, Qnil, NO, NO);
4246       tmp = Qnil;
4247       /* this is a standard variable */
4248       ns_default ("AppleAntiAliasingThreshold", &tmp,
4249                  make_float (10.0), make_float (6.0), YES, NO);
4250       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4251     }
4253   {
4254     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4256     if ( cl == nil )
4257       {
4258         Lisp_Object color_file, color_map, color;
4259         unsigned long c;
4260         char *name;
4262         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4263                          Fsymbol_value (intern ("data-directory")));
4265         color_map = Fx_load_color_file (color_file);
4266         if (NILP (color_map))
4267           fatal ("Could not read %s.\n", SDATA (color_file));
4269         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4270         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4271           {
4272             color = XCAR (color_map);
4273             name = SSDATA (XCAR (color));
4274             c = XINT (XCDR (color));
4275             [cl setColor:
4276                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4277                                             green: GREEN_FROM_ULONG (c) / 255.0
4278                                              blue: BLUE_FROM_ULONG (c) / 255.0
4279                                             alpha: 1.0]
4280                   forKey: [NSString stringWithUTF8String: name]];
4281           }
4282         [cl writeToFile: nil];
4283       }
4284   }
4286   {
4287 #ifdef NS_IMPL_GNUSTEP
4288     Vwindow_system_version = build_string (gnustep_base_version);
4289 #else
4290     /*PSnextrelease (128, c); */
4291     char c[DBL_BUFSIZE_BOUND];
4292     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4293     Vwindow_system_version = make_unibyte_string (c, len);
4294 #endif
4295   }
4297   delete_keyboard_wait_descriptor (0);
4299   ns_app_name = [[NSProcessInfo processInfo] processName];
4301 /* Set up OS X app menu */
4302 #ifdef NS_IMPL_COCOA
4303   {
4304     NSMenu *appMenu;
4305     NSMenuItem *item;
4306     /* set up the application menu */
4307     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4308     [svcsMenu setAutoenablesItems: NO];
4309     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4310     [appMenu setAutoenablesItems: NO];
4311     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4312     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4314     [appMenu insertItemWithTitle: @"About Emacs"
4315                           action: @selector (orderFrontStandardAboutPanel:)
4316                    keyEquivalent: @""
4317                          atIndex: 0];
4318     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4319     [appMenu insertItemWithTitle: @"Preferences..."
4320                           action: @selector (showPreferencesWindow:)
4321                    keyEquivalent: @","
4322                          atIndex: 2];
4323     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4324     item = [appMenu insertItemWithTitle: @"Services"
4325                                  action: @selector (menuDown:)
4326                           keyEquivalent: @""
4327                                 atIndex: 4];
4328     [appMenu setSubmenu: svcsMenu forItem: item];
4329     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4330     [appMenu insertItemWithTitle: @"Hide Emacs"
4331                           action: @selector (hide:)
4332                    keyEquivalent: @"h"
4333                          atIndex: 6];
4334     item =  [appMenu insertItemWithTitle: @"Hide Others"
4335                           action: @selector (hideOtherApplications:)
4336                    keyEquivalent: @"h"
4337                          atIndex: 7];
4338     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4339     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4340     [appMenu insertItemWithTitle: @"Quit Emacs"
4341                           action: @selector (terminate:)
4342                    keyEquivalent: @"q"
4343                          atIndex: 9];
4345     item = [mainMenu insertItemWithTitle: ns_app_name
4346                                   action: @selector (menuDown:)
4347                            keyEquivalent: @""
4348                                  atIndex: 0];
4349     [mainMenu setSubmenu: appMenu forItem: item];
4350     [dockMenu insertItemWithTitle: @"New Frame"
4351                            action: @selector (newFrame:)
4352                     keyEquivalent: @""
4353                           atIndex: 0];
4355     [NSApp setMainMenu: mainMenu];
4356     [NSApp setAppleMenu: appMenu];
4357     [NSApp setServicesMenu: svcsMenu];
4358     /* Needed at least on Cocoa, to get dock menu to show windows */
4359     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4361     [[NSNotificationCenter defaultCenter]
4362       addObserver: mainMenu
4363          selector: @selector (trackingNotification:)
4364              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4365     [[NSNotificationCenter defaultCenter]
4366       addObserver: mainMenu
4367          selector: @selector (trackingNotification:)
4368              name: NSMenuDidEndTrackingNotification object: mainMenu];
4369   }
4370 #endif /* MAC OS X menu setup */
4372   /* Register our external input/output types, used for determining
4373      applicable services and also drag/drop eligibility. */
4374   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4375   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4376                       retain];
4377   ns_drag_types = [[NSArray arrayWithObjects:
4378                             NSStringPboardType,
4379                             NSTabularTextPboardType,
4380                             NSFilenamesPboardType,
4381                             NSURLPboardType, nil] retain];
4383   /* If fullscreen is in init/default-frame-alist, focus isn't set
4384      right for fullscreen windows, so set this.  */
4385   [NSApp activateIgnoringOtherApps:YES];
4387   [NSApp run];
4388   ns_do_open_file = YES;
4390 #ifdef NS_IMPL_GNUSTEP
4391   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4392      We must re-catch it so subprocess works.  */
4393   catch_child_signal ();
4394 #endif
4395   return dpyinfo;
4399 void
4400 ns_term_shutdown (int sig)
4402   [[NSUserDefaults standardUserDefaults] synchronize];
4404   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4405   if (STRINGP (Vauto_save_list_file_name))
4406     unlink (SSDATA (Vauto_save_list_file_name));
4408   if (sig == 0 || sig == SIGTERM)
4409     {
4410       [NSApp terminate: NSApp];
4411     }
4412   else // force a stack trace to happen
4413     {
4414       emacs_abort ();
4415     }
4419 /* ==========================================================================
4421     EmacsApp implementation
4423    ========================================================================== */
4426 @implementation EmacsApp
4428 - (id)init
4430   if (self = [super init])
4431     {
4432 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
4433       self->isFirst = YES;
4434 #endif
4435 #ifdef NS_IMPL_GNUSTEP
4436       self->applicationDidFinishLaunchingCalled = NO;
4437 #endif
4438     }
4440   return self;
4443 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
4444 - (void)run
4446     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4448     if (isFirst) [self finishLaunching];
4449     isFirst = NO;
4451     shouldKeepRunning = YES;
4452     do
4453       {
4454         [pool release];
4455         pool = [[NSAutoreleasePool alloc] init];
4457         NSEvent *event =
4458           [self nextEventMatchingMask:NSAnyEventMask
4459                             untilDate:[NSDate distantFuture]
4460                                inMode:NSDefaultRunLoopMode
4461                               dequeue:YES];
4462         [self sendEvent:event];
4463         [self updateWindows];
4464     } while (shouldKeepRunning);
4466     [pool release];
4469 - (void)stop: (id)sender
4471     shouldKeepRunning = NO;
4472     // Stop possible dialog also.  Noop if no dialog present.
4473     // The file dialog still leaks 7k - 10k on 10.9 though.
4474     [super stop:sender];
4476 #endif
4478 - (void)logNotification: (NSNotification *)notification
4480   const char *name = [[notification name] UTF8String];
4481   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4482       && !strstr (name, "WindowNumber"))
4483     NSLog (@"notification: '%@'", [notification name]);
4487 - (void)sendEvent: (NSEvent *)theEvent
4488 /* --------------------------------------------------------------------------
4489      Called when NSApp is running for each event received.  Used to stop
4490      the loop when we choose, since there's no way to just run one iteration.
4491    -------------------------------------------------------------------------- */
4493   int type = [theEvent type];
4494   NSWindow *window = [theEvent window];
4496 /*  NSTRACE (sendEvent); */
4497 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4499 #ifdef NS_IMPL_GNUSTEP
4500   // Keyboard events aren't propagated to file dialogs for some reason.
4501   if ([NSApp modalWindow] != nil &&
4502       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4503     {
4504       [[NSApp modalWindow] sendEvent: theEvent];
4505       return;
4506     }
4507 #endif
4509   if (type == NSApplicationDefined)
4510     {
4511       switch ([theEvent data2])
4512         {
4513 #ifdef NS_IMPL_COCOA
4514         case NSAPP_DATA2_RUNASSCRIPT:
4515           ns_run_ascript ();
4516           [self stop: self];
4517           return;
4518 #endif
4519         case NSAPP_DATA2_RUNFILEDIALOG:
4520           ns_run_file_dialog ();
4521           [self stop: self];
4522           return;
4523         }
4524     }
4526   if (type == NSCursorUpdate && window == nil)
4527     {
4528       fprintf (stderr, "Dropping external cursor update event.\n");
4529       return;
4530     }
4532   if (type == NSApplicationDefined)
4533     {
4534       /* Events posted by ns_send_appdefined interrupt the run loop here.
4535          But, if a modal window is up, an appdefined can still come through,
4536          (e.g., from a makeKeyWindow event) but stopping self also stops the
4537          modal loop. Just defer it until later. */
4538       if ([NSApp modalWindow] == nil)
4539         {
4540           last_appdefined_event_data = [theEvent data1];
4541           [self stop: self];
4542         }
4543       else
4544         {
4545           send_appdefined = YES;
4546         }
4547     }
4550 #ifdef NS_IMPL_COCOA
4551   /* If no dialog and none of our frames have focus and it is a move, skip it.
4552      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4553      such as Wifi, sound, date or similar.
4554      This prevents "spooky" highlighting in the frame under the menu.  */
4555   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4556     {
4557       struct ns_display_info *di;
4558       BOOL has_focus = NO;
4559       for (di = x_display_list; ! has_focus && di; di = di->next)
4560         has_focus = di->x_focus_frame != 0;
4561       if (! has_focus)
4562         return;
4563     }
4564 #endif
4566   [super sendEvent: theEvent];
4570 - (void)showPreferencesWindow: (id)sender
4572   struct frame *emacsframe = SELECTED_FRAME ();
4573   NSEvent *theEvent = [NSApp currentEvent];
4575   if (!emacs_event)
4576     return;
4577   emacs_event->kind = NS_NONKEY_EVENT;
4578   emacs_event->code = KEY_NS_SHOW_PREFS;
4579   emacs_event->modifiers = 0;
4580   EV_TRAILER (theEvent);
4584 - (void)newFrame: (id)sender
4586   struct frame *emacsframe = SELECTED_FRAME ();
4587   NSEvent *theEvent = [NSApp currentEvent];
4589   if (!emacs_event)
4590     return;
4591   emacs_event->kind = NS_NONKEY_EVENT;
4592   emacs_event->code = KEY_NS_NEW_FRAME;
4593   emacs_event->modifiers = 0;
4594   EV_TRAILER (theEvent);
4598 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4599 - (BOOL) openFile: (NSString *)fileName
4601   struct frame *emacsframe = SELECTED_FRAME ();
4602   NSEvent *theEvent = [NSApp currentEvent];
4604   if (!emacs_event)
4605     return NO;
4607   emacs_event->kind = NS_NONKEY_EVENT;
4608   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4609   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4610   ns_input_line = Qnil; /* can be start or cons start,end */
4611   emacs_event->modifiers =0;
4612   EV_TRAILER (theEvent);
4614   return YES;
4618 /* **************************************************************************
4620       EmacsApp delegate implementation
4622    ************************************************************************** */
4624 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4625 /* --------------------------------------------------------------------------
4626      When application is loaded, terminate event loop in ns_term_init
4627    -------------------------------------------------------------------------- */
4629   NSTRACE (applicationDidFinishLaunching);
4630 #ifdef NS_IMPL_GNUSTEP
4631   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
4632 #endif
4633   [NSApp setServicesProvider: NSApp];
4634   ns_send_appdefined (-2);
4638 /* Termination sequences:
4639     C-x C-c:
4640     Cmd-Q:
4641     MenuBar | File | Exit:
4642     Select Quit from App menubar:
4643         -terminate
4644         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4645         ns_term_shutdown()
4647     Select Quit from Dock menu:
4648     Logout attempt:
4649         -appShouldTerminate
4650           Cancel -> Nothing else
4651           Accept ->
4653           -terminate
4654           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4655           ns_term_shutdown()
4659 - (void) terminate: (id)sender
4661   struct frame *emacsframe = SELECTED_FRAME ();
4663   if (!emacs_event)
4664     return;
4666   emacs_event->kind = NS_NONKEY_EVENT;
4667   emacs_event->code = KEY_NS_POWER_OFF;
4668   emacs_event->arg = Qt; /* mark as non-key event */
4669   EV_TRAILER ((id)nil);
4673 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4675   int ret;
4677   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4678     return NSTerminateNow;
4680     ret = NSRunAlertPanel(ns_app_name,
4681                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4682                           @"Save Buffers and Exit", @"Cancel", nil);
4684     if (ret == NSAlertDefaultReturn)
4685         return NSTerminateNow;
4686     else if (ret == NSAlertAlternateReturn)
4687         return NSTerminateCancel;
4688     return NSTerminateNow;  /* just in case */
4691 static int
4692 not_in_argv (NSString *arg)
4694   int k;
4695   const char *a = [arg UTF8String];
4696   for (k = 1; k < initial_argc; ++k)
4697     if (strcmp (a, initial_argv[k]) == 0) return 0;
4698   return 1;
4701 /*   Notification from the Workspace to open a file */
4702 - (BOOL)application: sender openFile: (NSString *)file
4704   if (ns_do_open_file || not_in_argv (file))
4705     [ns_pending_files addObject: file];
4706   return YES;
4710 /*   Open a file as a temporary file */
4711 - (BOOL)application: sender openTempFile: (NSString *)file
4713   if (ns_do_open_file || not_in_argv (file))
4714     [ns_pending_files addObject: file];
4715   return YES;
4719 /*   Notification from the Workspace to open a file noninteractively (?) */
4720 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4722   if (ns_do_open_file || not_in_argv (file))
4723     [ns_pending_files addObject: file];
4724   return YES;
4727 /*   Notification from the Workspace to open multiple files */
4728 - (void)application: sender openFiles: (NSArray *)fileList
4730   NSEnumerator *files = [fileList objectEnumerator];
4731   NSString *file;
4732   /* Don't open files from the command line unconditionally,
4733      Cocoa parses the command line wrong, --option value tries to open value
4734      if --option is the last option.  */
4735   while ((file = [files nextObject]) != nil)
4736     if (ns_do_open_file || not_in_argv (file))
4737       [ns_pending_files addObject: file];
4739   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4744 /* Handle dock menu requests.  */
4745 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4747   return dockMenu;
4751 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4752 - (void)applicationWillBecomeActive: (NSNotification *)notification
4754   //ns_app_active=YES;
4756 - (void)applicationDidBecomeActive: (NSNotification *)notification
4758   NSTRACE (applicationDidBecomeActive);
4760 #ifdef NS_IMPL_GNUSTEP
4761   if (! applicationDidFinishLaunchingCalled)
4762     [self applicationDidFinishLaunching:notification];
4763 #endif
4764   //ns_app_active=YES;
4766   ns_update_auto_hide_menu_bar ();
4767   // No constraining takes place when the application is not active.
4768   ns_constrain_all_frames ();
4770 - (void)applicationDidResignActive: (NSNotification *)notification
4772   //ns_app_active=NO;
4773   ns_send_appdefined (-1);
4778 /* ==========================================================================
4780     EmacsApp aux handlers for managing event loop
4782    ========================================================================== */
4785 - (void)timeout_handler: (NSTimer *)timedEntry
4786 /* --------------------------------------------------------------------------
4787      The timeout specified to ns_select has passed.
4788    -------------------------------------------------------------------------- */
4790   /*NSTRACE (timeout_handler); */
4791   ns_send_appdefined (-2);
4794 #ifdef NS_IMPL_GNUSTEP
4795 - (void)sendFromMainThread:(id)unused
4797   ns_send_appdefined (nextappdefined);
4799 #endif
4801 - (void)fd_handler:(id)unused
4802 /* --------------------------------------------------------------------------
4803      Check data waiting on file descriptors and terminate if so
4804    -------------------------------------------------------------------------- */
4806   int result;
4807   int waiting = 1, nfds;
4808   char c;
4810   fd_set readfds, writefds, *wfds;
4811   struct timespec timeout, *tmo;
4812   NSAutoreleasePool *pool = nil;
4814   /* NSTRACE (fd_handler); */
4816   for (;;)
4817     {
4818       [pool release];
4819       pool = [[NSAutoreleasePool alloc] init];
4821       if (waiting)
4822         {
4823           fd_set fds;
4824           FD_ZERO (&fds);
4825           FD_SET (selfds[0], &fds);
4826           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4827           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4828             waiting = 0;
4829         }
4830       else
4831         {
4832           pthread_mutex_lock (&select_mutex);
4833           nfds = select_nfds;
4835           if (select_valid & SELECT_HAVE_READ)
4836             readfds = select_readfds;
4837           else
4838             FD_ZERO (&readfds);
4840           if (select_valid & SELECT_HAVE_WRITE)
4841             {
4842               writefds = select_writefds;
4843               wfds = &writefds;
4844             }
4845           else
4846             wfds = NULL;
4847           if (select_valid & SELECT_HAVE_TMO)
4848             {
4849               timeout = select_timeout;
4850               tmo = &timeout;
4851             }
4852           else
4853             tmo = NULL;
4855           pthread_mutex_unlock (&select_mutex);
4857           FD_SET (selfds[0], &readfds);
4858           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4860           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4862           if (result == 0)
4863             ns_send_appdefined (-2);
4864           else if (result > 0)
4865             {
4866               if (FD_ISSET (selfds[0], &readfds))
4867                 {
4868                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4869                     waiting = 1;
4870                 }
4871               else
4872                 {
4873                   pthread_mutex_lock (&select_mutex);
4874                   if (select_valid & SELECT_HAVE_READ)
4875                     select_readfds = readfds;
4876                   if (select_valid & SELECT_HAVE_WRITE)
4877                     select_writefds = writefds;
4878                   if (select_valid & SELECT_HAVE_TMO)
4879                     select_timeout = timeout;
4880                   pthread_mutex_unlock (&select_mutex);
4882                   ns_send_appdefined (result);
4883                 }
4884             }
4885           waiting = 1;
4886         }
4887     }
4892 /* ==========================================================================
4894     Service provision
4896    ========================================================================== */
4898 /* called from system: queue for next pass through event loop */
4899 - (void)requestService: (NSPasteboard *)pboard
4900               userData: (NSString *)userData
4901                  error: (NSString **)error
4903   [ns_pending_service_names addObject: userData];
4904   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4905       SSDATA (ns_string_from_pasteboard (pboard))]];
4909 /* called from ns_read_socket to clear queue */
4910 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4912   struct frame *emacsframe = SELECTED_FRAME ();
4913   NSEvent *theEvent = [NSApp currentEvent];
4915   if (!emacs_event)
4916     return NO;
4918   emacs_event->kind = NS_NONKEY_EVENT;
4919   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4920   ns_input_spi_name = build_string ([name UTF8String]);
4921   ns_input_spi_arg = build_string ([arg UTF8String]);
4922   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4923   EV_TRAILER (theEvent);
4925   return YES;
4929 @end  /* EmacsApp */
4933 /* ==========================================================================
4935     EmacsView implementation
4937    ========================================================================== */
4940 @implementation EmacsView
4942 /* needed to inform when window closed from LISP */
4943 - (void) setWindowClosing: (BOOL)closing
4945   windowClosing = closing;
4949 - (void)dealloc
4951   NSTRACE (EmacsView_dealloc);
4952   [toolbar release];
4953   if (fs_state == FULLSCREEN_BOTH)
4954     [nonfs_window release];
4955   [super dealloc];
4959 /* called on font panel selection */
4960 - (void)changeFont: (id)sender
4962   NSEvent *e = [[self window] currentEvent];
4963   struct face *face = FRAME_DEFAULT_FACE (emacsframe);
4964   struct font *font = face->font;
4965   id newFont;
4966   CGFloat size;
4967   NSFont *nsfont;
4969   NSTRACE (changeFont);
4971   if (!emacs_event)
4972     return;
4974   if (EQ (font->driver->type, Qns))
4975     nsfont = ((struct nsfont_info *)font)->nsfont;
4976 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
4977   else
4978     nsfont = (NSFont *) macfont_get_nsctfont (font);
4979 #endif
4981   if ((newFont = [sender convertFont: nsfont]))
4982     {
4983       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4985       emacs_event->kind = NS_NONKEY_EVENT;
4986       emacs_event->modifiers = 0;
4987       emacs_event->code = KEY_NS_CHANGE_FONT;
4989       size = [newFont pointSize];
4990       ns_input_fontsize = make_number (lrint (size));
4991       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4992       EV_TRAILER (e);
4993     }
4997 - (BOOL)acceptsFirstResponder
4999   NSTRACE (acceptsFirstResponder);
5000   return YES;
5004 - (void)resetCursorRects
5006   NSRect visible = [self visibleRect];
5007   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5008   NSTRACE (resetCursorRects);
5010   if (currentCursor == nil)
5011     currentCursor = [NSCursor arrowCursor];
5013   if (!NSIsEmptyRect (visible))
5014     [self addCursorRect: visible cursor: currentCursor];
5015   [currentCursor setOnMouseEntered: YES];
5020 /*****************************************************************************/
5021 /* Keyboard handling. */
5022 #define NS_KEYLOG 0
5024 - (void)keyDown: (NSEvent *)theEvent
5026   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5027   int code;
5028   unsigned fnKeysym = 0;
5029   static NSMutableArray *nsEvArray;
5030 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5031   static BOOL firstTime = YES;
5032 #endif
5033   int left_is_none;
5034   unsigned int flags = [theEvent modifierFlags];
5036   NSTRACE (keyDown);
5038   /* Rhapsody and OS X give up and down events for the arrow keys */
5039   if (ns_fake_keydown == YES)
5040     ns_fake_keydown = NO;
5041   else if ([theEvent type] != NSKeyDown)
5042     return;
5044   if (!emacs_event)
5045     return;
5047  if (![[self window] isKeyWindow]
5048      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5049      /* we must avoid an infinite loop here. */
5050      && (EmacsView *)[[theEvent window] delegate] != self)
5051    {
5052      /* XXX: There is an occasional condition in which, when Emacs display
5053          updates a different frame from the current one, and temporarily
5054          selects it, then processes some interrupt-driven input
5055          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5056          for some reason that window has its first responder set to the NSView
5057          most recently updated (I guess), which is not the correct one. */
5058      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5059      return;
5060    }
5062   if (nsEvArray == nil)
5063     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5065   [NSCursor setHiddenUntilMouseMoves: YES];
5067   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5068     {
5069       clear_mouse_face (hlinfo);
5070       hlinfo->mouse_face_hidden = 1;
5071     }
5073   if (!processingCompose)
5074     {
5075       /* When using screen sharing, no left or right information is sent,
5076          so use Left key in those cases.  */
5077       int is_left_key, is_right_key;
5079       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5080         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5082       /* (Carbon way: [theEvent keyCode]) */
5084       /* is it a "function key"? */
5085       fnKeysym = (code < 0x00ff && (flags&NSNumericPadKeyMask))
5086         ? ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask)
5087         : ns_convert_key (code);
5089       if (fnKeysym)
5090         {
5091           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5092              because Emacs treats Delete and KP-Delete same (in simple.el). */
5093           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5094 #ifdef NS_IMPL_GNUSTEP
5095               /*  GNUstep uses incompatible keycodes, even for those that are
5096                   supposed to be hardware independent.  Just check for delete.
5097                   Keypad delete does not have keysym 0xFFFF.
5098                   See http://savannah.gnu.org/bugs/?25395
5099               */
5100               || (fnKeysym == 0xFFFF && code == 127)
5101 #endif
5102             )
5103             code = 0xFF08; /* backspace */
5104           else
5105             code = fnKeysym;
5106         }
5108       /* are there modifiers? */
5109       emacs_event->modifiers = 0;
5111       if (flags & NSHelpKeyMask)
5112           emacs_event->modifiers |= hyper_modifier;
5114       if (flags & NSShiftKeyMask)
5115         emacs_event->modifiers |= shift_modifier;
5117       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5118       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5119         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5121       if (is_right_key)
5122         emacs_event->modifiers |= parse_solitary_modifier
5123           (EQ (ns_right_command_modifier, Qleft)
5124            ? ns_command_modifier
5125            : ns_right_command_modifier);
5127       if (is_left_key)
5128         {
5129           emacs_event->modifiers |= parse_solitary_modifier
5130             (ns_command_modifier);
5132           /* if super (default), take input manager's word so things like
5133              dvorak / qwerty layout work */
5134           if (EQ (ns_command_modifier, Qsuper)
5135               && !fnKeysym
5136               && [[theEvent characters] length] != 0)
5137             {
5138               /* XXX: the code we get will be unshifted, so if we have
5139                  a shift modifier, must convert ourselves */
5140               if (!(flags & NSShiftKeyMask))
5141                 code = [[theEvent characters] characterAtIndex: 0];
5142 #if 0
5143               /* this is ugly and also requires linking w/Carbon framework
5144                  (for LMGetKbdType) so for now leave this rare (?) case
5145                  undealt with.. in future look into CGEvent methods */
5146               else
5147                 {
5148                   long smv = GetScriptManagerVariable (smKeyScript);
5149                   Handle uchrHandle = GetResource
5150                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5151                   UInt32 dummy = 0;
5152                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5153                                  [[theEvent characters] characterAtIndex: 0],
5154                                  kUCKeyActionDisplay,
5155                                  (flags & ~NSCommandKeyMask) >> 8,
5156                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5157                                  &dummy, 1, &dummy, &code);
5158                   code &= 0xFF;
5159                 }
5160 #endif
5161             }
5162         }
5164       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5165       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5166         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5168       if (is_right_key)
5169           emacs_event->modifiers |= parse_solitary_modifier
5170               (EQ (ns_right_control_modifier, Qleft)
5171                ? ns_control_modifier
5172                : ns_right_control_modifier);
5174       if (is_left_key)
5175         emacs_event->modifiers |= parse_solitary_modifier
5176           (ns_control_modifier);
5178       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5179           emacs_event->modifiers |=
5180             parse_solitary_modifier (ns_function_modifier);
5182       left_is_none = NILP (ns_alternate_modifier)
5183         || EQ (ns_alternate_modifier, Qnone);
5185       is_right_key = (flags & NSRightAlternateKeyMask)
5186         == NSRightAlternateKeyMask;
5187       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5188         || (! is_right_key
5189             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5191       if (is_right_key)
5192         {
5193           if ((NILP (ns_right_alternate_modifier)
5194                || EQ (ns_right_alternate_modifier, Qnone)
5195                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5196               && !fnKeysym)
5197             {   /* accept pre-interp alt comb */
5198               if ([[theEvent characters] length] > 0)
5199                 code = [[theEvent characters] characterAtIndex: 0];
5200               /*HACK: clear lone shift modifier to stop next if from firing */
5201               if (emacs_event->modifiers == shift_modifier)
5202                 emacs_event->modifiers = 0;
5203             }
5204           else
5205             emacs_event->modifiers |= parse_solitary_modifier
5206               (EQ (ns_right_alternate_modifier, Qleft)
5207                ? ns_alternate_modifier
5208                : ns_right_alternate_modifier);
5209         }
5211       if (is_left_key) /* default = meta */
5212         {
5213           if (left_is_none && !fnKeysym)
5214             {   /* accept pre-interp alt comb */
5215               if ([[theEvent characters] length] > 0)
5216                 code = [[theEvent characters] characterAtIndex: 0];
5217               /*HACK: clear lone shift modifier to stop next if from firing */
5218               if (emacs_event->modifiers == shift_modifier)
5219                 emacs_event->modifiers = 0;
5220             }
5221           else
5222               emacs_event->modifiers |=
5223                 parse_solitary_modifier (ns_alternate_modifier);
5224         }
5226   if (NS_KEYLOG)
5227     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5228              code, fnKeysym, flags, emacs_event->modifiers);
5230       /* if it was a function key or had modifiers, pass it directly to emacs */
5231       if (fnKeysym || (emacs_event->modifiers
5232                        && (emacs_event->modifiers != shift_modifier)
5233                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5234 /*[[theEvent characters] length] */
5235         {
5236           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5237           if (code < 0x20)
5238             code |= (1<<28)|(3<<16);
5239           else if (code == 0x7f)
5240             code |= (1<<28)|(3<<16);
5241           else if (!fnKeysym)
5242             emacs_event->kind = code > 0xFF
5243               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5245           emacs_event->code = code;
5246           EV_TRAILER (theEvent);
5247           processingCompose = NO;
5248           return;
5249         }
5250     }
5253 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5254   /* if we get here we should send the key for input manager processing */
5255   /* Disable warning, there is nothing a user can do about it anyway, and
5256      it does not seem to matter.  */
5257 #if 0
5258   if (firstTime && [[NSInputManager currentInputManager]
5259                      wantsToDelayTextChangeNotifications] == NO)
5260     fprintf (stderr,
5261           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5262 #endif
5263   firstTime = NO;
5264 #endif
5265   if (NS_KEYLOG && !processingCompose)
5266     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5268   processingCompose = YES;
5269   [nsEvArray addObject: theEvent];
5270   [self interpretKeyEvents: nsEvArray];
5271   [nsEvArray removeObject: theEvent];
5275 #ifdef NS_IMPL_COCOA
5276 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5277    decided not to send key-down for.
5278    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5279    This only applies on Tiger and earlier.
5280    If it matches one of these, send it on to keyDown. */
5281 -(void)keyUp: (NSEvent *)theEvent
5283   int flags = [theEvent modifierFlags];
5284   int code = [theEvent keyCode];
5285   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5286       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5287     {
5288       if (NS_KEYLOG)
5289         fprintf (stderr, "keyUp: passed test");
5290       ns_fake_keydown = YES;
5291       [self keyDown: theEvent];
5292     }
5294 #endif
5297 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5300 /* <NSTextInput>: called when done composing;
5301    NOTE: also called when we delete over working text, followed immed.
5302          by doCommandBySelector: deleteBackward: */
5303 - (void)insertText: (id)aString
5305   int code;
5306   int len = [(NSString *)aString length];
5307   int i;
5309   if (NS_KEYLOG)
5310     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5311   processingCompose = NO;
5313   if (!emacs_event)
5314     return;
5316   /* first, clear any working text */
5317   if (workingText != nil)
5318     [self deleteWorkingText];
5320   /* now insert the string as keystrokes */
5321   for (i =0; i<len; i++)
5322     {
5323       code = [aString characterAtIndex: i];
5324       /* TODO: still need this? */
5325       if (code == 0x2DC)
5326         code = '~'; /* 0x7E */
5327       if (code != 32) /* Space */
5328         emacs_event->modifiers = 0;
5329       emacs_event->kind
5330         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5331       emacs_event->code = code;
5332       EV_TRAILER ((id)nil);
5333     }
5337 /* <NSTextInput>: inserts display of composing characters */
5338 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5340   NSString *str = [aString respondsToSelector: @selector (string)] ?
5341     [aString string] : aString;
5342   if (NS_KEYLOG)
5343     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5344            str, (unsigned long)[str length],
5345            (unsigned long)selRange.length,
5346            (unsigned long)selRange.location);
5348   if (workingText != nil)
5349     [self deleteWorkingText];
5350   if ([str length] == 0)
5351     return;
5353   if (!emacs_event)
5354     return;
5356   processingCompose = YES;
5357   workingText = [str copy];
5358   ns_working_text = build_string ([workingText UTF8String]);
5360   emacs_event->kind = NS_TEXT_EVENT;
5361   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5362   EV_TRAILER ((id)nil);
5366 /* delete display of composing characters [not in <NSTextInput>] */
5367 - (void)deleteWorkingText
5369   if (workingText == nil)
5370     return;
5371   if (NS_KEYLOG)
5372     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5373   [workingText release];
5374   workingText = nil;
5375   processingCompose = NO;
5377   if (!emacs_event)
5378     return;
5380   emacs_event->kind = NS_TEXT_EVENT;
5381   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5382   EV_TRAILER ((id)nil);
5386 - (BOOL)hasMarkedText
5388   return workingText != nil;
5392 - (NSRange)markedRange
5394   NSRange rng = workingText != nil
5395     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5396   if (NS_KEYLOG)
5397     NSLog (@"markedRange request");
5398   return rng;
5402 - (void)unmarkText
5404   if (NS_KEYLOG)
5405     NSLog (@"unmark (accept) text");
5406   [self deleteWorkingText];
5407   processingCompose = NO;
5411 /* used to position char selection windows, etc. */
5412 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5414   NSRect rect;
5415   NSPoint pt;
5416   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5417   if (NS_KEYLOG)
5418     NSLog (@"firstRectForCharRange request");
5420   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5421   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5422   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5423   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5424                                        +FRAME_LINE_HEIGHT (emacsframe));
5426   pt = [self convertPoint: pt toView: nil];
5427   pt = [[self window] convertBaseToScreen: pt];
5428   rect.origin = pt;
5429   return rect;
5433 - (NSInteger)conversationIdentifier
5435   return (NSInteger)self;
5439 - (void)doCommandBySelector: (SEL)aSelector
5441   if (NS_KEYLOG)
5442     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5444   processingCompose = NO;
5445   if (aSelector == @selector (deleteBackward:))
5446     {
5447       /* happens when user backspaces over an ongoing composition:
5448          throw a 'delete' into the event queue */
5449       if (!emacs_event)
5450         return;
5451       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5452       emacs_event->code = 0xFF08;
5453       EV_TRAILER ((id)nil);
5454     }
5457 - (NSArray *)validAttributesForMarkedText
5459   static NSArray *arr = nil;
5460   if (arr == nil) arr = [NSArray new];
5461  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5462   return arr;
5465 - (NSRange)selectedRange
5467   if (NS_KEYLOG)
5468     NSLog (@"selectedRange request");
5469   return NSMakeRange (NSNotFound, 0);
5472 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5473     GNUSTEP_GUI_MINOR_VERSION > 22
5474 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5475 #else
5476 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5477 #endif
5479   if (NS_KEYLOG)
5480     NSLog (@"characterIndexForPoint request");
5481   return 0;
5484 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5486   static NSAttributedString *str = nil;
5487   if (str == nil) str = [NSAttributedString new];
5488   if (NS_KEYLOG)
5489     NSLog (@"attributedSubstringFromRange request");
5490   return str;
5493 /* End <NSTextInput> impl. */
5494 /*****************************************************************************/
5497 /* This is what happens when the user presses a mouse button.  */
5498 - (void)mouseDown: (NSEvent *)theEvent
5500   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5501   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5503   NSTRACE (mouseDown);
5505   [self deleteWorkingText];
5507   if (!emacs_event)
5508     return;
5510   dpyinfo->last_mouse_frame = emacsframe;
5511   /* appears to be needed to prevent spurious movement events generated on
5512      button clicks */
5513   emacsframe->mouse_moved = 0;
5515   if ([theEvent type] == NSScrollWheel)
5516     {
5517       CGFloat delta = [theEvent deltaY];
5518       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5519       if (delta == 0)
5520         {
5521           delta = [theEvent deltaX];
5522           if (delta == 0)
5523             {
5524               NSTRACE (deltaIsZero);
5525               return;
5526             }
5527           emacs_event->kind = HORIZ_WHEEL_EVENT;
5528         }
5529       else
5530         emacs_event->kind = WHEEL_EVENT;
5532       emacs_event->code = 0;
5533       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5534         ((delta > 0) ? up_modifier : down_modifier);
5535     }
5536   else
5537     {
5538       emacs_event->kind = MOUSE_CLICK_EVENT;
5539       emacs_event->code = EV_BUTTON (theEvent);
5540       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5541                              | EV_UDMODIFIERS (theEvent);
5542     }
5543   XSETINT (emacs_event->x, lrint (p.x));
5544   XSETINT (emacs_event->y, lrint (p.y));
5545   EV_TRAILER (theEvent);
5549 - (void)rightMouseDown: (NSEvent *)theEvent
5551   NSTRACE (rightMouseDown);
5552   [self mouseDown: theEvent];
5556 - (void)otherMouseDown: (NSEvent *)theEvent
5558   NSTRACE (otherMouseDown);
5559   [self mouseDown: theEvent];
5563 - (void)mouseUp: (NSEvent *)theEvent
5565   NSTRACE (mouseUp);
5566   [self mouseDown: theEvent];
5570 - (void)rightMouseUp: (NSEvent *)theEvent
5572   NSTRACE (rightMouseUp);
5573   [self mouseDown: theEvent];
5577 - (void)otherMouseUp: (NSEvent *)theEvent
5579   NSTRACE (otherMouseUp);
5580   [self mouseDown: theEvent];
5584 - (void) scrollWheel: (NSEvent *)theEvent
5586   NSTRACE (scrollWheel);
5587   [self mouseDown: theEvent];
5591 /* Tell emacs the mouse has moved. */
5592 - (void)mouseMoved: (NSEvent *)e
5594   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5595   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5596   Lisp_Object frame;
5597   NSPoint pt;
5599 //  NSTRACE (mouseMoved);
5601   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
5602   pt = [self convertPoint: [e locationInWindow] fromView: nil];
5603   dpyinfo->last_mouse_motion_x = pt.x;
5604   dpyinfo->last_mouse_motion_y = pt.y;
5606   /* update any mouse face */
5607   if (hlinfo->mouse_face_hidden)
5608     {
5609       hlinfo->mouse_face_hidden = 0;
5610       clear_mouse_face (hlinfo);
5611     }
5613   /* tooltip handling */
5614   previous_help_echo_string = help_echo_string;
5615   help_echo_string = Qnil;
5617   if (!NILP (Vmouse_autoselect_window))
5618     {
5619       NSTRACE (mouse_autoselect_window);
5620       static Lisp_Object last_mouse_window;
5621       Lisp_Object window
5622         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
5624       if (WINDOWP (window)
5625           && !EQ (window, last_mouse_window)
5626           && !EQ (window, selected_window)
5627           && (focus_follows_mouse
5628               || (EQ (XWINDOW (window)->frame,
5629                       XWINDOW (selected_window)->frame))))
5630         {
5631           NSTRACE (in_window);
5632           emacs_event->kind = SELECT_WINDOW_EVENT;
5633           emacs_event->frame_or_window = window;
5634           EV_TRAILER2 (e);
5635         }
5636       /* Remember the last window where we saw the mouse.  */
5637       last_mouse_window = window;
5638     }
5640   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
5641     help_echo_string = previous_help_echo_string;
5643   XSETFRAME (frame, emacsframe);
5644   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5645     {
5646       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5647          (note_mouse_highlight), which is called through the
5648          note_mouse_movement () call above */
5649       gen_help_event (help_echo_string, frame, help_echo_window,
5650                       help_echo_object, help_echo_pos);
5651     }
5652   else
5653     {
5654       help_echo_string = Qnil;
5655       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5656     }
5658   if (emacsframe->mouse_moved && send_appdefined)
5659     ns_send_appdefined (-1);
5663 - (void)mouseDragged: (NSEvent *)e
5665   NSTRACE (mouseDragged);
5666   [self mouseMoved: e];
5670 - (void)rightMouseDragged: (NSEvent *)e
5672   NSTRACE (rightMouseDragged);
5673   [self mouseMoved: e];
5677 - (void)otherMouseDragged: (NSEvent *)e
5679   NSTRACE (otherMouseDragged);
5680   [self mouseMoved: e];
5684 - (BOOL)windowShouldClose: (id)sender
5686   NSEvent *e =[[self window] currentEvent];
5688   NSTRACE (windowShouldClose);
5689   windowClosing = YES;
5690   if (!emacs_event)
5691     return NO;
5692   emacs_event->kind = DELETE_WINDOW_EVENT;
5693   emacs_event->modifiers = 0;
5694   emacs_event->code = 0;
5695   EV_TRAILER (e);
5696   /* Don't close this window, let this be done from lisp code.  */
5697   return NO;
5700 - (void) updateFrameSize: (BOOL) delay;
5702   NSWindow *window = [self window];
5703   NSRect wr = [window frame];
5704   int extra = 0;
5705   int oldc = cols, oldr = rows;
5706   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
5707   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5708   int neww, newh;
5710   NSTRACE (updateFrameSize);
5711   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
5713   if (! [self isFullscreen])
5714     {
5715 #ifdef NS_IMPL_GNUSTEP
5716       // GNUStep does not always update the tool bar height.  Force it.
5717       if (toolbar) update_frame_tool_bar (emacsframe);
5718 #endif
5720       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5721         + FRAME_TOOLBAR_HEIGHT (emacsframe);
5722     }
5724   neww = (int)wr.size.width - emacsframe->border_width;
5725   newh = (int)wr.size.height - extra;
5727   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
5728   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
5730   if (cols < MINWIDTH)
5731     cols = MINWIDTH;
5733   if (rows < MINHEIGHT)
5734     rows = MINHEIGHT;
5736   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5737     {
5738       NSView *view = FRAME_NS_VIEW (emacsframe);
5739       NSWindow *win = [view window];
5740       NSSize sz = [win resizeIncrements];
5742       change_frame_size (emacsframe,
5743                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
5744                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
5745                          0, delay, 0, 1);
5746       SET_FRAME_GARBAGED (emacsframe);
5747       cancel_mouse_face (emacsframe);
5749       // Did resize increments change because of a font change?
5750       if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5751           sz.height != FRAME_LINE_HEIGHT (emacsframe))
5752         {
5753           sz.width = FRAME_COLUMN_WIDTH (emacsframe);
5754           sz.height = FRAME_LINE_HEIGHT (emacsframe);
5755           [win setResizeIncrements: sz];
5757           NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
5758         }
5760       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5761       [self windowDidMove:nil];   // Update top/left.
5762     }
5765 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5766 /* normalize frame to gridded text size */
5768   int extra = 0;
5770   NSTRACE (windowWillResize);
5771   NSTRACE_SIZE ("Original size", frameSize);
5772 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5774   if (fs_state == FULLSCREEN_MAXIMIZED
5775       && (maximized_width != (int)frameSize.width
5776           || maximized_height != (int)frameSize.height))
5777     [self setFSValue: FULLSCREEN_NONE];
5778   else if (fs_state == FULLSCREEN_WIDTH
5779            && maximized_width != (int)frameSize.width)
5780     [self setFSValue: FULLSCREEN_NONE];
5781   else if (fs_state == FULLSCREEN_HEIGHT
5782            && maximized_height != (int)frameSize.height)
5783     [self setFSValue: FULLSCREEN_NONE];
5784   if (fs_state == FULLSCREEN_NONE)
5785     maximized_width = maximized_height = -1;
5787   if (! [self isFullscreen])
5788     {
5789       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5790         + FRAME_TOOLBAR_HEIGHT (emacsframe);
5791     }
5793   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
5794   if (cols < MINWIDTH)
5795     cols = MINWIDTH;
5797   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5798                                            frameSize.height - extra);
5799   if (rows < MINHEIGHT)
5800     rows = MINHEIGHT;
5801 #ifdef NS_IMPL_COCOA
5802   {
5803     /* this sets window title to have size in it; the wm does this under GS */
5804     NSRect r = [[self window] frame];
5805     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5806       {
5807         if (old_title != 0)
5808           {
5809             xfree (old_title);
5810             old_title = 0;
5811           }
5812       }
5813     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5814       {
5815         char *size_title;
5816         NSWindow *window = [self window];
5817         if (old_title == 0)
5818           {
5819             char *t = strdup ([[[self window] title] UTF8String]);
5820             char *pos = strstr (t, "  â€”  ");
5821             if (pos)
5822               *pos = '\0';
5823             old_title = t;
5824           }
5825         size_title = xmalloc (strlen (old_title) + 40);
5826         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5827         [window setTitle: [NSString stringWithUTF8String: size_title]];
5828         [window display];
5829         xfree (size_title);
5830       }
5831   }
5832 #endif /* NS_IMPL_COCOA */
5833 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5835   return frameSize;
5839 - (void)windowDidResize: (NSNotification *)notification
5841   if (! [self fsIsNative])
5842     {
5843       NSWindow *theWindow = [notification object];
5844       /* We can get notification on the non-FS window when in
5845          fullscreen mode.  */
5846       if ([self window] != theWindow) return;
5847     }
5849 #ifdef NS_IMPL_GNUSTEP
5850   NSWindow *theWindow = [notification object];
5852    /* In GNUstep, at least currently, it's possible to get a didResize
5853       without getting a willResize.. therefore we need to act as if we got
5854       the willResize now */
5855   NSSize sz = [theWindow frame].size;
5856   sz = [self windowWillResize: theWindow toSize: sz];
5857 #endif /* NS_IMPL_GNUSTEP */
5859   NSTRACE (windowDidResize);
5860 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5862 if (cols > 0 && rows > 0)
5863     {
5864       [self updateFrameSize: YES];
5865     }
5867   ns_send_appdefined (-1);
5870 #ifdef NS_IMPL_COCOA
5871 - (void)viewDidEndLiveResize
5873   [super viewDidEndLiveResize];
5874   if (old_title != 0)
5875     {
5876       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
5877       xfree (old_title);
5878       old_title = 0;
5879     }
5880   maximizing_resize = NO;
5882 #endif /* NS_IMPL_COCOA */
5885 - (void)windowDidBecomeKey: (NSNotification *)notification
5886 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5888   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5889   struct frame *old_focus = dpyinfo->x_focus_frame;
5891   NSTRACE (windowDidBecomeKey);
5893   if (emacsframe != old_focus)
5894     dpyinfo->x_focus_frame = emacsframe;
5896   ns_frame_rehighlight (emacsframe);
5898   if (emacs_event)
5899     {
5900       emacs_event->kind = FOCUS_IN_EVENT;
5901       EV_TRAILER ((id)nil);
5902     }
5906 - (void)windowDidResignKey: (NSNotification *)notification
5907 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5909   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5910   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
5911   NSTRACE (windowDidResignKey);
5913   if (is_focus_frame)
5914     dpyinfo->x_focus_frame = 0;
5916   ns_frame_rehighlight (emacsframe);
5918   /* FIXME: for some reason needed on second and subsequent clicks away
5919             from sole-frame Emacs to get hollow box to show */
5920   if (!windowClosing && [[self window] isVisible] == YES)
5921     {
5922       x_update_cursor (emacsframe, 1);
5923       x_set_frame_alpha (emacsframe);
5924     }
5926   if (emacs_event && is_focus_frame)
5927     {
5928       [self deleteWorkingText];
5929       emacs_event->kind = FOCUS_OUT_EVENT;
5930       EV_TRAILER ((id)nil);
5931     }
5935 - (void)windowWillMiniaturize: sender
5937   NSTRACE (windowWillMiniaturize);
5941 - (BOOL)isFlipped
5943   return YES;
5947 - (BOOL)isOpaque
5949   return NO;
5953 - initFrameFromEmacs: (struct frame *)f
5955   NSRect r, wr;
5956   Lisp_Object tem;
5957   NSWindow *win;
5958   NSSize sz;
5959   NSColor *col;
5960   NSString *name;
5962   NSTRACE (initFrameFromEmacs);
5964   windowClosing = NO;
5965   processingCompose = NO;
5966   scrollbarsNeedingUpdate = 0;
5967   fs_state = FULLSCREEN_NONE;
5968   fs_before_fs = next_maximized = -1;
5969 #ifdef HAVE_NATIVE_FS
5970   fs_is_native = ns_use_native_fullscreen;
5971 #else
5972   fs_is_native = NO;
5973 #endif
5974   maximized_width = maximized_height = -1;
5975   nonfs_window = nil;
5977 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5979   ns_userRect = NSMakeRect (0, 0, 0, 0);
5980   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5981                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5982   [self initWithFrame: r];
5983   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5985   FRAME_NS_VIEW (f) = self;
5986   emacsframe = f;
5987 #ifdef NS_IMPL_COCOA
5988   old_title = 0;
5989   maximizing_resize = NO;
5990 #endif
5992   win = [[EmacsWindow alloc]
5993             initWithContentRect: r
5994                       styleMask: (NSResizableWindowMask |
5995 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5996                                   NSTitledWindowMask |
5997 #endif
5998                                   NSMiniaturizableWindowMask |
5999                                   NSClosableWindowMask)
6000                         backing: NSBackingStoreBuffered
6001                           defer: YES];
6003 #ifdef HAVE_NATIVE_FS
6004     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6005 #endif
6007   wr = [win frame];
6008   bwidth = f->border_width = wr.size.width - r.size.width;
6009   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6011   [win setAcceptsMouseMovedEvents: YES];
6012   [win setDelegate: self];
6013   [win useOptimizedDrawing: YES];
6015   sz.width = FRAME_COLUMN_WIDTH (f);
6016   sz.height = FRAME_LINE_HEIGHT (f);
6017   [win setResizeIncrements: sz];
6019   [[win contentView] addSubview: self];
6021   if (ns_drag_types)
6022     [self registerForDraggedTypes: ns_drag_types];
6024   tem = f->name;
6025   name = [NSString stringWithUTF8String:
6026                    NILP (tem) ? "Emacs" : SSDATA (tem)];
6027   [win setTitle: name];
6029   /* toolbar support */
6030   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6031                          [NSString stringWithFormat: @"Emacs Frame %d",
6032                                    ns_window_num]];
6033   [win setToolbar: toolbar];
6034   [toolbar setVisible: NO];
6035 #ifdef NS_IMPL_COCOA
6036   {
6037     NSButton *toggleButton;
6038   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6039   [toggleButton setTarget: self];
6040   [toggleButton setAction: @selector (toggleToolbar: )];
6041   }
6042 #endif
6043   FRAME_TOOLBAR_HEIGHT (f) = 0;
6045   tem = f->icon_name;
6046   if (!NILP (tem))
6047     [win setMiniwindowTitle:
6048            [NSString stringWithUTF8String: SSDATA (tem)]];
6050   {
6051     NSScreen *screen = [win screen];
6053     if (screen != 0)
6054       [win setFrameTopLeftPoint: NSMakePoint
6055            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6056             IN_BOUND (-SCREENMAX,
6057                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
6058   }
6060   [win makeFirstResponder: self];
6062   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6063                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6064   [win setBackgroundColor: col];
6065   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6066     [win setOpaque: NO];
6068   [self allocateGState];
6070   [NSApp registerServicesMenuSendTypes: ns_send_types
6071                            returnTypes: nil];
6073   ns_window_num++;
6074   return self;
6078 - (void)windowDidMove: sender
6080   NSWindow *win = [self window];
6081   NSRect r = [win frame];
6082   NSArray *screens = [NSScreen screens];
6083   NSScreen *screen = [screens objectAtIndex: 0];
6085   NSTRACE (windowDidMove);
6087   if (!emacsframe->output_data.ns)
6088     return;
6089   if (screen != nil)
6090     {
6091       emacsframe->left_pos = r.origin.x;
6092       emacsframe->top_pos =
6093         [screen frame].size.height - (r.origin.y + r.size.height);
6094     }
6098 /* Called AFTER method below, but before our windowWillResize call there leads
6099    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
6100    location so set_window_size moves the frame. */
6101 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6103   emacsframe->output_data.ns->zooming = 1;
6104   return YES;
6108 /* Override to do something slightly nonstandard, but nice.  First click on
6109    zoom button will zoom vertically.  Second will zoom completely.  Third
6110    returns to original. */
6111 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6112                         defaultFrame:(NSRect)defaultFrame
6114   NSRect result = [sender frame];
6116   NSTRACE (windowWillUseStandardFrame);
6118   if (fs_before_fs != -1) /* Entering fullscreen */
6119       {
6120         result = defaultFrame;
6121       }
6122   else if (next_maximized == FULLSCREEN_HEIGHT
6123       || (next_maximized == -1
6124           && abs (defaultFrame.size.height - result.size.height)
6125           > FRAME_LINE_HEIGHT (emacsframe)))
6126     {
6127       /* first click */
6128       ns_userRect = result;
6129       maximized_height = result.size.height = defaultFrame.size.height;
6130       maximized_width = -1;
6131       result.origin.y = defaultFrame.origin.y;
6132       [self setFSValue: FULLSCREEN_HEIGHT];
6133 #ifdef NS_IMPL_COCOA
6134       maximizing_resize = YES;
6135 #endif
6136     }
6137   else if (next_maximized == FULLSCREEN_WIDTH)
6138     {
6139       ns_userRect = result;
6140       maximized_width = result.size.width = defaultFrame.size.width;
6141       maximized_height = -1;
6142       result.origin.x = defaultFrame.origin.x;
6143       [self setFSValue: FULLSCREEN_WIDTH];
6144     }
6145   else if (next_maximized == FULLSCREEN_MAXIMIZED
6146            || (next_maximized == -1
6147                && abs (defaultFrame.size.width - result.size.width)
6148                > FRAME_COLUMN_WIDTH (emacsframe)))
6149     {
6150       result = defaultFrame;  /* second click */
6151       maximized_width = result.size.width;
6152       maximized_height = result.size.height;
6153       [self setFSValue: FULLSCREEN_MAXIMIZED];
6154 #ifdef NS_IMPL_COCOA
6155       maximizing_resize = YES;
6156 #endif
6157     }
6158   else
6159     {
6160       /* restore */
6161       result = ns_userRect.size.height ? ns_userRect : result;
6162       ns_userRect = NSMakeRect (0, 0, 0, 0);
6163 #ifdef NS_IMPL_COCOA
6164       maximizing_resize = fs_state != FULLSCREEN_NONE;
6165 #endif
6166       [self setFSValue: FULLSCREEN_NONE];
6167       maximized_width = maximized_height = -1;
6168     }
6170   if (fs_before_fs == -1) next_maximized = -1;
6171   [self windowWillResize: sender toSize: result.size];
6172   return result;
6176 - (void)windowDidDeminiaturize: sender
6178   NSTRACE (windowDidDeminiaturize);
6179   if (!emacsframe->output_data.ns)
6180     return;
6182   SET_FRAME_ICONIFIED (emacsframe, 0);
6183   SET_FRAME_VISIBLE (emacsframe, 1);
6184   windows_or_buffers_changed = 63;
6186   if (emacs_event)
6187     {
6188       emacs_event->kind = DEICONIFY_EVENT;
6189       EV_TRAILER ((id)nil);
6190     }
6194 - (void)windowDidExpose: sender
6196   NSTRACE (windowDidExpose);
6197   if (!emacsframe->output_data.ns)
6198     return;
6200   SET_FRAME_VISIBLE (emacsframe, 1);
6201   SET_FRAME_GARBAGED (emacsframe);
6203   if (send_appdefined)
6204     ns_send_appdefined (-1);
6208 - (void)windowDidMiniaturize: sender
6210   NSTRACE (windowDidMiniaturize);
6211   if (!emacsframe->output_data.ns)
6212     return;
6214   SET_FRAME_ICONIFIED (emacsframe, 1);
6215   SET_FRAME_VISIBLE (emacsframe, 0);
6217   if (emacs_event)
6218     {
6219       emacs_event->kind = ICONIFY_EVENT;
6220       EV_TRAILER ((id)nil);
6221     }
6224 #ifdef HAVE_NATIVE_FS
6225 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6226       willUseFullScreenPresentationOptions:
6227   (NSApplicationPresentationOptions)proposedOptions
6229   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6231 #endif
6233 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6235   fs_before_fs = fs_state;
6238 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6240   [self setFSValue: FULLSCREEN_BOTH];
6241   if (! [self fsIsNative])
6242     {
6243       [self windowDidBecomeKey:notification];
6244       [nonfs_window orderOut:self];
6245     }
6246   else
6247     {
6248       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
6249 #ifdef NS_IMPL_COCOA
6250 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6251       unsigned val = (unsigned)[NSApp presentationOptions];
6253       // OSX 10.7 bug fix, the menu won't appear without this.
6254       // val is non-zero on other OSX versions.
6255       if (val == 0)
6256         {
6257           NSApplicationPresentationOptions options
6258             = NSApplicationPresentationAutoHideDock
6259             | NSApplicationPresentationAutoHideMenuBar
6260             | NSApplicationPresentationFullScreen
6261             | NSApplicationPresentationAutoHideToolbar;
6263           [NSApp setPresentationOptions: options];
6264         }
6265 #endif
6266 #endif
6267       [toolbar setVisible:tbar_visible];
6268     }
6271 - (void)windowWillExitFullScreen:(NSNotification *)notification
6273   if (next_maximized != -1)
6274     fs_before_fs = next_maximized;
6277 - (void)windowDidExitFullScreen:(NSNotification *)notification
6279   [self setFSValue: fs_before_fs];
6280   fs_before_fs = -1;
6281 #ifdef HAVE_NATIVE_FS
6282   [self updateCollectionBehaviour];
6283 #endif
6284   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6285     {
6286       [toolbar setVisible:YES];
6287       update_frame_tool_bar (emacsframe);
6288       [self updateFrameSize:YES];
6289       [[self window] display];
6290     }
6291   else
6292     [toolbar setVisible:NO];
6294   if (next_maximized != -1)
6295     [[self window] performZoom:self];
6298 - (BOOL)fsIsNative
6300   return fs_is_native;
6303 - (BOOL)isFullscreen
6305   if (! fs_is_native) return nonfs_window != nil;
6306 #ifdef HAVE_NATIVE_FS
6307   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6308 #else
6309   return NO;
6310 #endif
6313 #ifdef HAVE_NATIVE_FS
6314 - (void)updateCollectionBehaviour
6316   if (! [self isFullscreen])
6317     {
6318       NSWindow *win = [self window];
6319       NSWindowCollectionBehavior b = [win collectionBehavior];
6320       if (ns_use_native_fullscreen)
6321         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6322       else
6323         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6325       [win setCollectionBehavior: b];
6326       fs_is_native = ns_use_native_fullscreen;
6327     }
6329 #endif
6331 - (void)toggleFullScreen: (id)sender
6333   NSWindow *w, *fw;
6334   BOOL onFirstScreen;
6335   struct frame *f;
6336   NSSize sz;
6337   NSRect r, wr;
6338   NSColor *col;
6340   if (fs_is_native)
6341     {
6342 #ifdef HAVE_NATIVE_FS
6343       [[self window] toggleFullScreen:sender];
6344 #endif
6345       return;
6346     }
6348   w = [self window];
6349   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6350   f = emacsframe;
6351   wr = [w frame];
6352   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6353                                  (FRAME_DEFAULT_FACE (f)),
6354                                  f);
6356   sz.width = FRAME_COLUMN_WIDTH (f);
6357   sz.height = FRAME_LINE_HEIGHT (f);
6359   if (fs_state != FULLSCREEN_BOTH)
6360     {
6361       /* Hide dock and menubar if we are on the primary screen.  */
6362       if (onFirstScreen)
6363         {
6364 #if defined (NS_IMPL_COCOA) && \
6365   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6366           NSApplicationPresentationOptions options
6367             = NSApplicationPresentationAutoHideDock
6368             | NSApplicationPresentationAutoHideMenuBar;
6370           [NSApp setPresentationOptions: options];
6371 #else
6372           [NSMenu setMenuBarVisible:NO];
6373 #endif
6374         }
6376       fw = [[EmacsFSWindow alloc]
6377                        initWithContentRect:[w contentRectForFrameRect:wr]
6378                                  styleMask:NSBorderlessWindowMask
6379                                    backing:NSBackingStoreBuffered
6380                                      defer:YES
6381                                     screen:[w screen]];
6383       [fw setContentView:[w contentView]];
6384       [fw setTitle:[w title]];
6385       [fw setDelegate:self];
6386       [fw setAcceptsMouseMovedEvents: YES];
6387       [fw useOptimizedDrawing: YES];
6388       [fw setResizeIncrements: sz];
6389       [fw setBackgroundColor: col];
6390       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6391         [fw setOpaque: NO];
6393       f->border_width = 0;
6394       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6395       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6396       FRAME_TOOLBAR_HEIGHT (f) = 0;
6398       nonfs_window = w;
6400       [self windowWillEnterFullScreen:nil];
6401       [fw makeKeyAndOrderFront:NSApp];
6402       [fw makeFirstResponder:self];
6403       [w orderOut:self];
6404       r = [fw frameRectForContentRect:[[fw screen] frame]];
6405       [fw setFrame: r display:YES animate:YES];
6406       [self windowDidEnterFullScreen:nil];
6407       [fw display];
6408     }
6409   else
6410     {
6411       fw = w;
6412       w = nonfs_window;
6413       nonfs_window = nil;
6415       if (onFirstScreen)
6416         {
6417 #if defined (NS_IMPL_COCOA) && \
6418   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6419           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6420 #else
6421           [NSMenu setMenuBarVisible:YES];
6422 #endif
6423         }
6425       [w setContentView:[fw contentView]];
6426       [w setResizeIncrements: sz];
6427       [w setBackgroundColor: col];
6428       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6429         [w setOpaque: NO];
6431       f->border_width = bwidth;
6432       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6433       if (FRAME_EXTERNAL_TOOL_BAR (f))
6434         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6436       [self windowWillExitFullScreen:nil];
6437       [fw setFrame: [w frame] display:YES animate:YES];
6438       [fw close];
6439       [w makeKeyAndOrderFront:NSApp];
6440       [self windowDidExitFullScreen:nil];
6441       [self updateFrameSize:YES];
6442     }
6445 - (void)handleFS
6447   if (fs_state != emacsframe->want_fullscreen)
6448     {
6449       if (fs_state == FULLSCREEN_BOTH)
6450         {
6451           [self toggleFullScreen:self];
6452         }
6454       switch (emacsframe->want_fullscreen)
6455         {
6456         case FULLSCREEN_BOTH:
6457           [self toggleFullScreen:self];
6458           break;
6459         case FULLSCREEN_WIDTH:
6460           next_maximized = FULLSCREEN_WIDTH;
6461           if (fs_state != FULLSCREEN_BOTH)
6462             [[self window] performZoom:self];
6463           break;
6464         case FULLSCREEN_HEIGHT:
6465           next_maximized = FULLSCREEN_HEIGHT;
6466           if (fs_state != FULLSCREEN_BOTH)
6467             [[self window] performZoom:self];
6468           break;
6469         case FULLSCREEN_MAXIMIZED:
6470           next_maximized = FULLSCREEN_MAXIMIZED;
6471           if (fs_state != FULLSCREEN_BOTH)
6472             [[self window] performZoom:self];
6473           break;
6474         case FULLSCREEN_NONE:
6475           if (fs_state != FULLSCREEN_BOTH)
6476             {
6477               next_maximized = FULLSCREEN_NONE;
6478               [[self window] performZoom:self];
6479             }
6480           break;
6481         }
6483       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6484     }
6488 - (void) setFSValue: (int)value
6490   Lisp_Object lval = Qnil;
6491   switch (value)
6492     {
6493     case FULLSCREEN_BOTH:
6494       lval = Qfullboth;
6495       break;
6496     case FULLSCREEN_WIDTH:
6497       lval = Qfullwidth;
6498       break;
6499     case FULLSCREEN_HEIGHT:
6500       lval = Qfullheight;
6501       break;
6502     case FULLSCREEN_MAXIMIZED:
6503       lval = Qmaximized;
6504       break;
6505     }
6506   store_frame_param (emacsframe, Qfullscreen, lval);
6507   fs_state = value;
6510 - (void)mouseEntered: (NSEvent *)theEvent
6512   NSTRACE (mouseEntered);
6513   if (emacsframe)
6514     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6515       = EV_TIMESTAMP (theEvent);
6519 - (void)mouseExited: (NSEvent *)theEvent
6521   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6523   NSTRACE (mouseExited);
6525   if (!hlinfo)
6526     return;
6528   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6529     = EV_TIMESTAMP (theEvent);
6531   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6532     {
6533       clear_mouse_face (hlinfo);
6534       hlinfo->mouse_face_mouse_frame = 0;
6535     }
6539 - menuDown: sender
6541   NSTRACE (menuDown);
6542   if (context_menu_value == -1)
6543     context_menu_value = [sender tag];
6544   else
6545     {
6546       NSInteger tag = [sender tag];
6547       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6548                                     emacsframe->menu_bar_vector,
6549                                     (void *)tag);
6550     }
6552   ns_send_appdefined (-1);
6553   return self;
6557 - (EmacsToolbar *)toolbar
6559   return toolbar;
6563 /* this gets called on toolbar button click */
6564 - toolbarClicked: (id)item
6566   NSEvent *theEvent;
6567   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6569   NSTRACE (toolbarClicked);
6571   if (!emacs_event)
6572     return self;
6574   /* send first event (for some reason two needed) */
6575   theEvent = [[self window] currentEvent];
6576   emacs_event->kind = TOOL_BAR_EVENT;
6577   XSETFRAME (emacs_event->arg, emacsframe);
6578   EV_TRAILER (theEvent);
6580   emacs_event->kind = TOOL_BAR_EVENT;
6581 /*   XSETINT (emacs_event->code, 0); */
6582   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6583                            idx + TOOL_BAR_ITEM_KEY);
6584   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6585   EV_TRAILER (theEvent);
6586   return self;
6590 - toggleToolbar: (id)sender
6592   if (!emacs_event)
6593     return self;
6595   emacs_event->kind = NS_NONKEY_EVENT;
6596   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6597   EV_TRAILER ((id)nil);
6598   return self;
6602 - (void)drawRect: (NSRect)rect
6604   int x = NSMinX (rect), y = NSMinY (rect);
6605   int width = NSWidth (rect), height = NSHeight (rect);
6607   NSTRACE (drawRect);
6609   if (!emacsframe || !emacsframe->output_data.ns)
6610     return;
6612   ns_clear_frame_area (emacsframe, x, y, width, height);
6613   expose_frame (emacsframe, x, y, width, height);
6615   /*
6616     drawRect: may be called (at least in OS X 10.5) for invisible
6617     views as well for some reason.  Thus, do not infer visibility
6618     here.
6620     emacsframe->async_visible = 1;
6621     emacsframe->async_iconified = 0;
6622   */
6626 /* NSDraggingDestination protocol methods.  Actually this is not really a
6627    protocol, but a category of Object.  O well...  */
6629 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6631   NSTRACE (draggingEntered);
6632   return NSDragOperationGeneric;
6636 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6638   return YES;
6642 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6644   id pb;
6645   int x, y;
6646   NSString *type;
6647   NSEvent *theEvent = [[self window] currentEvent];
6648   NSPoint position;
6649   NSDragOperation op = [sender draggingSourceOperationMask];
6650   int modifiers = 0;
6652   NSTRACE (performDragOperation);
6654   if (!emacs_event)
6655     return NO;
6657   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6658   x = lrint (position.x);  y = lrint (position.y);
6660   pb = [sender draggingPasteboard];
6661   type = [pb availableTypeFromArray: ns_drag_types];
6663   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
6664       // URL drags contain all operations (0xf), don't allow all to be set.
6665       (op & 0xf) != 0xf)
6666     {
6667       if (op & NSDragOperationLink)
6668         modifiers |= NSControlKeyMask;
6669       if (op & NSDragOperationCopy)
6670         modifiers |= NSAlternateKeyMask;
6671       if (op & NSDragOperationGeneric)
6672         modifiers |= NSCommandKeyMask;
6673     }
6675   modifiers = EV_MODIFIERS2 (modifiers);
6676   if (type == 0)
6677     {
6678       return NO;
6679     }
6680   else if ([type isEqualToString: NSFilenamesPboardType])
6681     {
6682       NSArray *files;
6683       NSEnumerator *fenum;
6684       NSString *file;
6686       if (!(files = [pb propertyListForType: type]))
6687         return NO;
6689       fenum = [files objectEnumerator];
6690       while ( (file = [fenum nextObject]) )
6691         {
6692           emacs_event->kind = DRAG_N_DROP_EVENT;
6693           XSETINT (emacs_event->x, x);
6694           XSETINT (emacs_event->y, y);
6695           ns_input_file = append2 (ns_input_file,
6696                                    build_string ([file UTF8String]));
6697           emacs_event->modifiers = modifiers;
6698           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
6699           EV_TRAILER (theEvent);
6700         }
6701       return YES;
6702     }
6703   else if ([type isEqualToString: NSURLPboardType])
6704     {
6705       NSURL *url = [NSURL URLFromPasteboard: pb];
6706       if (url == nil) return NO;
6708       emacs_event->kind = DRAG_N_DROP_EVENT;
6709       XSETINT (emacs_event->x, x);
6710       XSETINT (emacs_event->y, y);
6711       emacs_event->modifiers = modifiers;
6712       emacs_event->arg =  list2 (Qurl,
6713                                  build_string ([[url absoluteString]
6714                                                  UTF8String]));
6715       EV_TRAILER (theEvent);
6717       if ([url isFileURL] != NO)
6718         {
6719           NSString *file = [url path];
6720           ns_input_file = append2 (ns_input_file,
6721                                    build_string ([file UTF8String]));
6722         }
6723       return YES;
6724     }
6725   else if ([type isEqualToString: NSStringPboardType]
6726            || [type isEqualToString: NSTabularTextPboardType])
6727     {
6728       NSString *data;
6730       if (! (data = [pb stringForType: type]))
6731         return NO;
6733       emacs_event->kind = DRAG_N_DROP_EVENT;
6734       XSETINT (emacs_event->x, x);
6735       XSETINT (emacs_event->y, y);
6736       emacs_event->modifiers = modifiers;
6737       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
6738       EV_TRAILER (theEvent);
6739       return YES;
6740     }
6741   else
6742     {
6743       error ("Invalid data type in dragging pasteboard.");
6744       return NO;
6745     }
6749 - (id) validRequestorForSendType: (NSString *)typeSent
6750                       returnType: (NSString *)typeReturned
6752   NSTRACE (validRequestorForSendType);
6753   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6754       && typeReturned == nil)
6755     {
6756       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6757         return self;
6758     }
6760   return [super validRequestorForSendType: typeSent
6761                                returnType: typeReturned];
6765 /* The next two methods are part of NSServicesRequests informal protocol,
6766    supposedly called when a services menu item is chosen from this app.
6767    But this should not happen because we override the services menu with our
6768    own entries which call ns-perform-service.
6769    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6770    So let's at least stub them out until further investigation can be done. */
6772 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6774   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6775      be written into the buffer in place of the existing selection..
6776      ordinary service calls go through functions defined in ns-win.el */
6777   return NO;
6780 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6782   NSArray *typesDeclared;
6783   Lisp_Object val;
6785   /* We only support NSStringPboardType */
6786   if ([types containsObject:NSStringPboardType] == NO) {
6787     return NO;
6788   }
6790   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6791   if (CONSP (val) && SYMBOLP (XCAR (val)))
6792     {
6793       val = XCDR (val);
6794       if (CONSP (val) && NILP (XCDR (val)))
6795         val = XCAR (val);
6796     }
6797   if (! STRINGP (val))
6798     return NO;
6800   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6801   [pb declareTypes:typesDeclared owner:nil];
6802   ns_string_to_pasteboard (pb, val);
6803   return YES;
6807 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6808    (gives a miniaturized version of the window); currently we use the latter for
6809    frames whose active buffer doesn't correspond to any file
6810    (e.g., '*scratch*') */
6811 - setMiniwindowImage: (BOOL) setMini
6813   id image = [[self window] miniwindowImage];
6814   NSTRACE (setMiniwindowImage);
6816   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6817      about "AppleDockIconEnabled" notwithstanding, however the set message
6818      below has its effect nonetheless. */
6819   if (image != emacsframe->output_data.ns->miniimage)
6820     {
6821       if (image && [image isKindOfClass: [EmacsImage class]])
6822         [image release];
6823       [[self window] setMiniwindowImage:
6824                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6825     }
6827   return self;
6831 - (void) setRows: (int) r andColumns: (int) c
6833   rows = r;
6834   cols = c;
6837 @end  /* EmacsView */
6841 /* ==========================================================================
6843     EmacsWindow implementation
6845    ========================================================================== */
6847 @implementation EmacsWindow
6849 #ifdef NS_IMPL_COCOA
6850 - (id)accessibilityAttributeValue:(NSString *)attribute
6852   Lisp_Object str = Qnil;
6853   struct frame *f = SELECTED_FRAME ();
6854   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
6856   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6857     return NSAccessibilityTextFieldRole;
6859   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6860       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6861     {
6862       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6863     }
6864   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6865     {
6866       if (! NILP (BVAR (curbuf, mark_active)))
6867           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6869       if (NILP (str))
6870         {
6871           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6872           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6873           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6875           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6876             str = make_uninit_multibyte_string (range, byte_range);
6877           else
6878             str = make_uninit_string (range);
6879           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6880              Is this a problem?  */
6881           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6882         }
6883     }
6886   if (! NILP (str))
6887     {
6888       if (CONSP (str) && SYMBOLP (XCAR (str)))
6889         {
6890           str = XCDR (str);
6891           if (CONSP (str) && NILP (XCDR (str)))
6892             str = XCAR (str);
6893         }
6894       if (STRINGP (str))
6895         {
6896           const char *utfStr = SSDATA (str);
6897           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6898           return nsStr;
6899         }
6900     }
6902   return [super accessibilityAttributeValue:attribute];
6904 #endif /* NS_IMPL_COCOA */
6906 /* If we have multiple monitors, one above the other, we don't want to
6907    restrict the height to just one monitor.  So we override this.  */
6908 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6910   /* When making the frame visible for the first time or if there is just
6911      one screen, we want to constrain.  Other times not.  */
6912   NSUInteger nr_screens = [[NSScreen screens] count];
6913   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6914   NSTRACE (constrainFrameRect);
6915   NSTRACE_RECT ("input", frameRect);
6917   if (ns_menu_bar_should_be_hidden ())
6918     return frameRect;
6920   /* The default implementation does two things 1) ensure that the top
6921      of the rectangle is below the menu bar (or below the top of the
6922      screen) and 2) resizes windows larger than the screen. As we
6923      don't want the latter, a smaller rectangle is used. */
6924 #define FAKE_HEIGHT 64
6925   float old_top = frameRect.origin.y + frameRect.size.height;
6926   NSRect r;
6927   r.size.height = FAKE_HEIGHT;
6928   r.size.width = frameRect.size.width;
6929   r.origin.x = frameRect.origin.x;
6930   r.origin.y = old_top - FAKE_HEIGHT;
6932   NSTRACE_RECT ("input to super", r);
6934   r = [super constrainFrameRect:r toScreen:screen];
6936   NSTRACE_RECT ("output from super", r);
6938   float new_top = r.origin.y + FAKE_HEIGHT;
6939   if (new_top < old_top)
6940   {
6941     frameRect.origin.y = new_top - frameRect.size.height;
6942   }
6944   NSTRACE_RECT ("output", frameRect);
6946   return frameRect;
6947 #undef FAKE_HEIGHT
6950 @end /* EmacsWindow */
6953 @implementation EmacsFSWindow
6955 - (BOOL)canBecomeKeyWindow
6957   return YES;
6960 - (BOOL)canBecomeMainWindow
6962   return YES;
6965 @end
6967 /* ==========================================================================
6969     EmacsScroller implementation
6971    ========================================================================== */
6974 @implementation EmacsScroller
6976 /* for repeat button push */
6977 #define SCROLL_BAR_FIRST_DELAY 0.5
6978 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6980 + (CGFloat) scrollerWidth
6982   /* TODO: if we want to allow variable widths, this is the place to do it,
6983            however neither GNUstep nor Cocoa support it very well */
6984   return [NSScroller scrollerWidth];
6988 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6990   NSTRACE (EmacsScroller_initFrame);
6992   r.size.width = [EmacsScroller scrollerWidth];
6993   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6994   [self setContinuous: YES];
6995   [self setEnabled: YES];
6997   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6998      locked against the top and bottom edges, and right edge on OS X, where
6999      scrollers are on right. */
7000 #ifdef NS_IMPL_GNUSTEP
7001   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
7002 #else
7003   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
7004 #endif
7006   win = nwin;
7007   condemned = NO;
7008   pixel_height = NSHeight (r);
7009   if (pixel_height == 0) pixel_height = 1;
7010   min_portion = 20 / pixel_height;
7012   frame = XFRAME (XWINDOW (win)->frame);
7013   if (FRAME_LIVE_P (frame))
7014     {
7015       int i;
7016       EmacsView *view = FRAME_NS_VIEW (frame);
7017       NSView *sview = [[view window] contentView];
7018       NSArray *subs = [sview subviews];
7020       /* disable optimization stopping redraw of other scrollbars */
7021       view->scrollbarsNeedingUpdate = 0;
7022       for (i =[subs count]-1; i >= 0; i--)
7023         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
7024           view->scrollbarsNeedingUpdate++;
7025       [sview addSubview: self];
7026     }
7028 /*  [self setFrame: r]; */
7030   return self;
7034 - (void)setFrame: (NSRect)newRect
7036   NSTRACE (EmacsScroller_setFrame);
7037 /*  block_input (); */
7038   pixel_height = NSHeight (newRect);
7039   if (pixel_height == 0) pixel_height = 1;
7040   min_portion = 20 / pixel_height;
7041   [super setFrame: newRect];
7042   [self display];
7043 /*  unblock_input (); */
7047 - (void)dealloc
7049   NSTRACE (EmacsScroller_dealloc);
7050   if (!NILP (win))
7051     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
7052   [super dealloc];
7056 - condemn
7058   NSTRACE (condemn);
7059   condemned =YES;
7060   return self;
7064 - reprieve
7066   NSTRACE (reprieve);
7067   condemned =NO;
7068   return self;
7072 - judge
7074   NSTRACE (judge);
7075   if (condemned)
7076     {
7077       EmacsView *view;
7078       block_input ();
7079       /* ensure other scrollbar updates after deletion */
7080       view = (EmacsView *)FRAME_NS_VIEW (frame);
7081       if (view != nil)
7082         view->scrollbarsNeedingUpdate++;
7083       [self removeFromSuperview];
7084       [self release];
7085       unblock_input ();
7086     }
7087   return self;
7091 - (void)resetCursorRects
7093   NSRect visible = [self visibleRect];
7094   NSTRACE (resetCursorRects);
7096   if (!NSIsEmptyRect (visible))
7097     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
7098   [[NSCursor arrowCursor] setOnMouseEntered: YES];
7102 - (int) checkSamePosition: (int) position portion: (int) portion
7103                     whole: (int) whole
7105   return em_position ==position && em_portion ==portion && em_whole ==whole
7106     && portion != whole; /* needed for resize empty buf */
7110 - setPosition: (int)position portion: (int)portion whole: (int)whole
7112   NSTRACE (setPosition);
7114   em_position = position;
7115   em_portion = portion;
7116   em_whole = whole;
7118   if (portion >= whole)
7119     {
7120 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
7121       [self setKnobProportion: 1.0];
7122       [self setDoubleValue: 1.0];
7123 #else
7124       [self setFloatValue: 0.0 knobProportion: 1.0];
7125 #endif
7126     }
7127   else
7128     {
7129       float pos;
7130       CGFloat por;
7131       portion = max ((float)whole*min_portion/pixel_height, portion);
7132       pos = (float)position / (whole - portion);
7133       por = (CGFloat)portion/whole;
7134 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
7135       [self setKnobProportion: por];
7136       [self setDoubleValue: pos];
7137 #else
7138       [self setFloatValue: pos knobProportion: por];
7139 #endif
7140     }
7142   /* Events may come here even if the event loop is not running.
7143      If we don't enter the event loop, the scroll bar will not update.
7144      So send SIGIO to ourselves.  */
7145   if (apploopnr == 0) raise (SIGIO);
7147   return self;
7150 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
7151      drag events will go directly to the EmacsScroller.  Leaving in for now. */
7152 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
7153                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
7155   *part = last_hit_part;
7156   *window = win;
7157   XSETINT (*y, pixel_height);
7158   if ([self floatValue] > 0.999F)
7159     XSETINT (*x, pixel_height);
7160   else
7161     XSETINT (*x, pixel_height * [self floatValue]);
7165 /* set up emacs_event */
7166 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
7168   if (!emacs_event)
7169     return;
7171   emacs_event->part = last_hit_part;
7172   emacs_event->code = 0;
7173   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
7174   emacs_event->frame_or_window = win;
7175   emacs_event->timestamp = EV_TIMESTAMP (e);
7176   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
7177   emacs_event->arg = Qnil;
7178   XSETINT (emacs_event->x, loc * pixel_height);
7179   XSETINT (emacs_event->y, pixel_height-20);
7181   if (q_event_ptr)
7182     {
7183       n_emacs_events_pending++;
7184       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7185     }
7186   else
7187     hold_event (emacs_event);
7188   EVENT_INIT (*emacs_event);
7189   ns_send_appdefined (-1);
7193 /* called manually thru timer to implement repeated button action w/hold-down */
7194 - repeatScroll: (NSTimer *)scrollEntry
7196   NSEvent *e = [[self window] currentEvent];
7197   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
7198   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7200   /* clear timer if need be */
7201   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7202     {
7203         [scroll_repeat_entry invalidate];
7204         [scroll_repeat_entry release];
7205         scroll_repeat_entry = nil;
7207         if (inKnob)
7208           return self;
7210         scroll_repeat_entry
7211           = [[NSTimer scheduledTimerWithTimeInterval:
7212                         SCROLL_BAR_CONTINUOUS_DELAY
7213                                             target: self
7214                                           selector: @selector (repeatScroll:)
7215                                           userInfo: 0
7216                                            repeats: YES]
7217               retain];
7218     }
7220   [self sendScrollEventAtLoc: 0 fromEvent: e];
7221   return self;
7225 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
7226    mouseDragged events without going into a modal loop. */
7227 - (void)mouseDown: (NSEvent *)e
7229   NSRect sr, kr;
7230   /* hitPart is only updated AFTER event is passed on */
7231   NSScrollerPart part = [self testPart: [e locationInWindow]];
7232   CGFloat inc = 0.0, loc, kloc, pos;
7233   int edge = 0;
7235   NSTRACE (EmacsScroller_mouseDown);
7237   switch (part)
7238     {
7239     case NSScrollerDecrementPage:
7240         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7241     case NSScrollerIncrementPage:
7242         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7243     case NSScrollerDecrementLine:
7244       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7245     case NSScrollerIncrementLine:
7246       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7247     case NSScrollerKnob:
7248       last_hit_part = scroll_bar_handle; break;
7249     case NSScrollerKnobSlot:  /* GNUstep-only */
7250       last_hit_part = scroll_bar_move_ratio; break;
7251     default:  /* NSScrollerNoPart? */
7252       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7253                (long) part);
7254       return;
7255     }
7257   if (inc != 0.0)
7258     {
7259       pos = 0;      /* ignored */
7261       /* set a timer to repeat, as we can't let superclass do this modally */
7262       scroll_repeat_entry
7263         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7264                                             target: self
7265                                           selector: @selector (repeatScroll:)
7266                                           userInfo: 0
7267                                            repeats: YES]
7268             retain];
7269     }
7270   else
7271     {
7272       /* handle, or on GNUstep possibly slot */
7273       NSEvent *fake_event;
7275       /* compute float loc in slot and mouse offset on knob */
7276       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7277                       toView: nil];
7278       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7279       if (loc <= 0.0)
7280         {
7281           loc = 0.0;
7282           edge = -1;
7283         }
7284       else if (loc >= NSHeight (sr))
7285         {
7286           loc = NSHeight (sr);
7287           edge = 1;
7288         }
7290       if (edge)
7291         kloc = 0.5 * edge;
7292       else
7293         {
7294           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7295                           toView: nil];
7296           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7297         }
7298       last_mouse_offset = kloc;
7300       /* if knob, tell emacs a location offset by knob pos
7301          (to indicate top of handle) */
7302       if (part == NSScrollerKnob)
7303           pos = (loc - last_mouse_offset) / NSHeight (sr);
7304       else
7305         /* else this is a slot click on GNUstep: go straight there */
7306         pos = loc / NSHeight (sr);
7308       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7309       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7310                                       location: [e locationInWindow]
7311                                  modifierFlags: [e modifierFlags]
7312                                      timestamp: [e timestamp]
7313                                   windowNumber: [e windowNumber]
7314                                        context: [e context]
7315                                    eventNumber: [e eventNumber]
7316                                     clickCount: [e clickCount]
7317                                       pressure: [e pressure]];
7318       [super mouseUp: fake_event];
7319     }
7321   if (part != NSScrollerKnob)
7322     [self sendScrollEventAtLoc: pos fromEvent: e];
7326 /* Called as we manually track scroller drags, rather than superclass. */
7327 - (void)mouseDragged: (NSEvent *)e
7329     NSRect sr;
7330     double loc, pos;
7332     NSTRACE (EmacsScroller_mouseDragged);
7334       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7335                       toView: nil];
7336       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7338       if (loc <= 0.0)
7339         {
7340           loc = 0.0;
7341         }
7342       else if (loc >= NSHeight (sr) + last_mouse_offset)
7343         {
7344           loc = NSHeight (sr) + last_mouse_offset;
7345         }
7347       pos = (loc - last_mouse_offset) / NSHeight (sr);
7348       [self sendScrollEventAtLoc: pos fromEvent: e];
7352 - (void)mouseUp: (NSEvent *)e
7354   if (scroll_repeat_entry)
7355     {
7356       [scroll_repeat_entry invalidate];
7357       [scroll_repeat_entry release];
7358       scroll_repeat_entry = nil;
7359     }
7360   last_hit_part = 0;
7364 /* treat scrollwheel events in the bar as though they were in the main window */
7365 - (void) scrollWheel: (NSEvent *)theEvent
7367   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7368   [view mouseDown: theEvent];
7371 @end  /* EmacsScroller */
7374 #ifdef NS_IMPL_GNUSTEP
7375 /* Dummy class to get rid of startup warnings.  */
7376 @implementation EmacsDocument
7378 @end
7379 #endif
7382 /* ==========================================================================
7384    Font-related functions; these used to be in nsfaces.m
7386    ========================================================================== */
7389 Lisp_Object
7390 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7392   struct font *font = XFONT_OBJECT (font_object);
7393   EmacsView *view = FRAME_NS_VIEW (f);
7395   if (fontset < 0)
7396     fontset = fontset_from_font (font_object);
7397   FRAME_FONTSET (f) = fontset;
7399   if (FRAME_FONT (f) == font)
7400     /* This font is already set in frame F.  There's nothing more to
7401        do.  */
7402     return font_object;
7404   FRAME_FONT (f) = font;
7406   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7407   FRAME_COLUMN_WIDTH (f) = font->average_width;
7408   FRAME_LINE_HEIGHT (f) = font->height;
7410   compute_fringe_widths (f, 1);
7412   /* Compute the scroll bar width in character columns.  */
7413   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7414     {
7415       int wid = FRAME_COLUMN_WIDTH (f);
7416       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7417         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7418     }
7419   else
7420     {
7421       int wid = FRAME_COLUMN_WIDTH (f);
7422       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7423     }
7425   /* Now make the frame display the given font.  */
7426   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
7427     x_set_window_size (f, 0, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
7428                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 1);
7430   return font_object;
7434 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7435 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7436          in 1.43. */
7438 const char *
7439 ns_xlfd_to_fontname (const char *xlfd)
7440 /* --------------------------------------------------------------------------
7441     Convert an X font name (XLFD) to an NS font name.
7442     Only family is used.
7443     The string returned is temporarily allocated.
7444    -------------------------------------------------------------------------- */
7446   char *name = xmalloc (180);
7447   int i, len;
7448   const char *ret;
7450   if (!strncmp (xlfd, "--", 2))
7451     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7452   else
7453     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7455   /* stopgap for malformed XLFD input */
7456   if (strlen (name) == 0)
7457     strcpy (name, "Monaco");
7459   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7460      also uppercase after '-' or ' ' */
7461   name[0] = c_toupper (name[0]);
7462   for (len =strlen (name), i =0; i<len; i++)
7463     {
7464       if (name[i] == '$')
7465         {
7466           name[i] = '-';
7467           if (i+1<len)
7468             name[i+1] = c_toupper (name[i+1]);
7469         }
7470       else if (name[i] == '_')
7471         {
7472           name[i] = ' ';
7473           if (i+1<len)
7474             name[i+1] = c_toupper (name[i+1]);
7475         }
7476     }
7477 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7478   ret = [[NSString stringWithUTF8String: name] UTF8String];
7479   xfree (name);
7480   return ret;
7484 void
7485 syms_of_nsterm (void)
7487   NSTRACE (syms_of_nsterm);
7489   ns_antialias_threshold = 10.0;
7491   /* from 23+ we need to tell emacs what modifiers there are.. */
7492   DEFSYM (Qmodifier_value, "modifier-value");
7493   DEFSYM (Qalt, "alt");
7494   DEFSYM (Qhyper, "hyper");
7495   DEFSYM (Qmeta, "meta");
7496   DEFSYM (Qsuper, "super");
7497   DEFSYM (Qcontrol, "control");
7498   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7500   DEFSYM (Qfile, "file");
7501   DEFSYM (Qurl, "url");
7503   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7504   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7505   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7506   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7507   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7509   DEFVAR_LISP ("ns-input-file", ns_input_file,
7510               "The file specified in the last NS event.");
7511   ns_input_file =Qnil;
7513   DEFVAR_LISP ("ns-working-text", ns_working_text,
7514               "String for visualizing working composition sequence.");
7515   ns_working_text =Qnil;
7517   DEFVAR_LISP ("ns-input-font", ns_input_font,
7518               "The font specified in the last NS event.");
7519   ns_input_font =Qnil;
7521   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7522               "The fontsize specified in the last NS event.");
7523   ns_input_fontsize =Qnil;
7525   DEFVAR_LISP ("ns-input-line", ns_input_line,
7526                "The line specified in the last NS event.");
7527   ns_input_line =Qnil;
7529   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7530                "The service name specified in the last NS event.");
7531   ns_input_spi_name =Qnil;
7533   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7534                "The service argument specified in the last NS event.");
7535   ns_input_spi_arg =Qnil;
7537   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7538                "This variable describes the behavior of the alternate or option key.\n\
7539 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7540 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7541 at all, allowing it to be used at a lower level for accented character entry.");
7542   ns_alternate_modifier = Qmeta;
7544   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7545                "This variable describes the behavior of the right alternate or option key.\n\
7546 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7547 Set to left means be the same key as `ns-alternate-modifier'.\n\
7548 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7549 at all, allowing it to be used at a lower level for accented character entry.");
7550   ns_right_alternate_modifier = Qleft;
7552   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7553                "This variable describes the behavior of the command key.\n\
7554 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7555   ns_command_modifier = Qsuper;
7557   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7558                "This variable describes the behavior of the right command key.\n\
7559 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7560 Set to left means be the same key as `ns-command-modifier'.\n\
7561 Set to none means that the command / option key is not interpreted by Emacs\n\
7562 at all, allowing it to be used at a lower level for accented character entry.");
7563   ns_right_command_modifier = Qleft;
7565   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7566                "This variable describes the behavior of the control key.\n\
7567 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7568   ns_control_modifier = Qcontrol;
7570   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7571                "This variable describes the behavior of the right control key.\n\
7572 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7573 Set to left means be the same key as `ns-control-modifier'.\n\
7574 Set to none means that the control / option key is not interpreted by Emacs\n\
7575 at all, allowing it to be used at a lower level for accented character entry.");
7576   ns_right_control_modifier = Qleft;
7578   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7579                "This variable describes the behavior of the function key (on laptops).\n\
7580 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7581 Set to none means that the function key is not interpreted by Emacs at all,\n\
7582 allowing it to be used at a lower level for accented character entry.");
7583   ns_function_modifier = Qnone;
7585   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7586                "Non-nil (the default) means to render text antialiased.");
7587   ns_antialias_text = Qt;
7589   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7590                "Whether to confirm application quit using dialog.");
7591   ns_confirm_quit = Qnil;
7593   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7594                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7595 Only works on OSX 10.6 or later.  */);
7596   ns_auto_hide_menu_bar = Qnil;
7598   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7599      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7600 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7601 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7602 Default is t for OSX >= 10.7, nil otherwise. */);
7603 #ifdef HAVE_NATIVE_FS
7604   ns_use_native_fullscreen = YES;
7605 #else
7606   ns_use_native_fullscreen = NO;
7607 #endif
7608   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7610   /* TODO: move to common code */
7611   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7612                doc: /* Which toolkit scroll bars Emacs uses, if any.
7613 A value of nil means Emacs doesn't use toolkit scroll bars.
7614 With the X Window system, the value is a symbol describing the
7615 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7616 With MS Windows or Nextstep, the value is t.  */);
7617   Vx_toolkit_scroll_bars = Qt;
7619   DEFVAR_BOOL ("x-use-underline-position-properties",
7620                x_use_underline_position_properties,
7621      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7622 A value of nil means ignore them.  If you encounter fonts with bogus
7623 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7624 to 4.1, set this to nil. */);
7625   x_use_underline_position_properties = 0;
7627   DEFVAR_BOOL ("x-underline-at-descent-line",
7628                x_underline_at_descent_line,
7629      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7630 A value of nil means to draw the underline according to the value of the
7631 variable `x-use-underline-position-properties', which is usually at the
7632 baseline level.  The default value is nil.  */);
7633   x_underline_at_descent_line = 0;
7635   /* Tell Emacs about this window system.  */
7636   Fprovide (Qns, Qnil);
7638   DEFSYM (Qcocoa, "cocoa");
7639   DEFSYM (Qgnustep, "gnustep");
7641   syms_of_nsfont ();
7642 #ifdef NS_IMPL_COCOA
7643   Fprovide (Qcocoa, Qnil);
7644 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
7645   syms_of_macfont ();
7646 #endif
7647 #else
7648   Fprovide (Qgnustep, Qnil);
7649 #endif