Simplify SELECT_TYPE-related code.
[emacs.git] / src / nsterm.m
blob01ee2319ddf0a4d2cd00bdf1ee03a77ebffd6a92
1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2013 Free Software
4 Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30    interpretation of even the system includes. */
31 #include <config.h>
33 #include <fcntl.h>
34 #include <math.h>
35 #include <pthread.h>
36 #include <sys/types.h>
37 #include <time.h>
38 #include <signal.h>
39 #include <unistd.h>
41 #include <c-ctype.h>
42 #include <c-strcase.h>
43 #include <ftoastr.h>
45 #include "lisp.h"
46 #include "blockinput.h"
47 #include "sysselect.h"
48 #include "nsterm.h"
49 #include "systime.h"
50 #include "character.h"
51 #include "fontset.h"
52 #include "composite.h"
53 #include "ccl.h"
55 #include "termhooks.h"
56 #include "termchar.h"
58 #include "window.h"
59 #include "keyboard.h"
60 #include "buffer.h"
61 #include "font.h"
63 #ifdef NS_IMPL_GNUSTEP
64 #include "process.h"
65 #endif
67 /* call tracing */
68 #if 0
69 int term_trace_num = 0;
70 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
71                                 __FILE__, __LINE__, ++term_trace_num)
72 #else
73 #define NSTRACE(x)
74 #endif
76 extern NSString *NSMenuDidBeginTrackingNotification;
78 /* ==========================================================================
80     Local declarations
82    ========================================================================== */
84 /* Convert a symbol indexed with an NSxxx value to a value as defined
85    in keyboard.c (lispy_function_key). I hope this is a correct way
86    of doing things... */
87 static unsigned convert_ns_to_X_keysym[] =
89   NSHomeFunctionKey,            0x50,
90   NSLeftArrowFunctionKey,       0x51,
91   NSUpArrowFunctionKey,         0x52,
92   NSRightArrowFunctionKey,      0x53,
93   NSDownArrowFunctionKey,       0x54,
94   NSPageUpFunctionKey,          0x55,
95   NSPageDownFunctionKey,        0x56,
96   NSEndFunctionKey,             0x57,
97   NSBeginFunctionKey,           0x58,
98   NSSelectFunctionKey,          0x60,
99   NSPrintFunctionKey,           0x61,
100   NSClearLineFunctionKey,       0x0B,
101   NSExecuteFunctionKey,         0x62,
102   NSInsertFunctionKey,          0x63,
103   NSUndoFunctionKey,            0x65,
104   NSRedoFunctionKey,            0x66,
105   NSMenuFunctionKey,            0x67,
106   NSFindFunctionKey,            0x68,
107   NSHelpFunctionKey,            0x6A,
108   NSBreakFunctionKey,           0x6B,
110   NSF1FunctionKey,              0xBE,
111   NSF2FunctionKey,              0xBF,
112   NSF3FunctionKey,              0xC0,
113   NSF4FunctionKey,              0xC1,
114   NSF5FunctionKey,              0xC2,
115   NSF6FunctionKey,              0xC3,
116   NSF7FunctionKey,              0xC4,
117   NSF8FunctionKey,              0xC5,
118   NSF9FunctionKey,              0xC6,
119   NSF10FunctionKey,             0xC7,
120   NSF11FunctionKey,             0xC8,
121   NSF12FunctionKey,             0xC9,
122   NSF13FunctionKey,             0xCA,
123   NSF14FunctionKey,             0xCB,
124   NSF15FunctionKey,             0xCC,
125   NSF16FunctionKey,             0xCD,
126   NSF17FunctionKey,             0xCE,
127   NSF18FunctionKey,             0xCF,
128   NSF19FunctionKey,             0xD0,
129   NSF20FunctionKey,             0xD1,
130   NSF21FunctionKey,             0xD2,
131   NSF22FunctionKey,             0xD3,
132   NSF23FunctionKey,             0xD4,
133   NSF24FunctionKey,             0xD5,
135   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
136   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
137   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
139   NSTabCharacter,               0x09,
140   0x19,                         0x09,  /* left tab->regular since pass shift */
141   NSCarriageReturnCharacter,    0x0D,
142   NSNewlineCharacter,           0x0D,
143   NSEnterCharacter,             0x8D,
145   0x41|NSNumericPadKeyMask,     0xAE,  /* KP_Decimal */
146   0x43|NSNumericPadKeyMask,     0xAA,  /* KP_Multiply */
147   0x45|NSNumericPadKeyMask,     0xAB,  /* KP_Add */
148   0x4B|NSNumericPadKeyMask,     0xAF,  /* KP_Divide */
149   0x4E|NSNumericPadKeyMask,     0xAD,  /* KP_Subtract */
150   0x51|NSNumericPadKeyMask,     0xBD,  /* KP_Equal */
151   0x52|NSNumericPadKeyMask,     0xB0,  /* KP_0 */
152   0x53|NSNumericPadKeyMask,     0xB1,  /* KP_1 */
153   0x54|NSNumericPadKeyMask,     0xB2,  /* KP_2 */
154   0x55|NSNumericPadKeyMask,     0xB3,  /* KP_3 */
155   0x56|NSNumericPadKeyMask,     0xB4,  /* KP_4 */
156   0x57|NSNumericPadKeyMask,     0xB5,  /* KP_5 */
157   0x58|NSNumericPadKeyMask,     0xB6,  /* KP_6 */
158   0x59|NSNumericPadKeyMask,     0xB7,  /* KP_7 */
159   0x5B|NSNumericPadKeyMask,     0xB8,  /* KP_8 */
160   0x5C|NSNumericPadKeyMask,     0xB9,  /* KP_9 */
162   0x1B,                         0x1B   /* escape */
165 static Lisp_Object Qmodifier_value;
166 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
167 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
169 static Lisp_Object QUTF8_STRING;
171 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
172    the maximum font size to NOT antialias.  On GNUstep there is currently
173    no way to control this behavior. */
174 float ns_antialias_threshold;
176 /* Used to pick up AppleHighlightColor on OS X */
177 NSString *ns_selection_color;
179 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
180 NSString *ns_app_name = @"Emacs";  /* default changed later */
182 /* Display variables */
183 struct ns_display_info *x_display_list; /* Chain of existing displays */
184 Lisp_Object ns_display_name_list;
185 long context_menu_value = 0;
187 /* display update */
188 NSPoint last_mouse_motion_position;
189 static NSRect last_mouse_glyph;
190 static Time last_mouse_movement_time = 0;
191 static Lisp_Object last_mouse_motion_frame;
192 static EmacsScroller *last_mouse_scroll_bar = nil;
193 static struct frame *ns_updating_frame;
194 static NSView *focus_view = NULL;
195 static int ns_window_num = 0;
196 #ifdef NS_IMPL_GNUSTEP
197 static NSRect uRect;
198 #endif
199 static BOOL gsaved = NO;
200 static BOOL ns_fake_keydown = NO;
201 int ns_tmp_flags; /* FIXME */
202 struct nsfont_info *ns_tmp_font; /* FIXME */
203 #ifdef NS_IMPL_COCOA
204 static BOOL ns_menu_bar_is_hidden = NO;
205 #endif
206 /*static int debug_lock = 0; */
208 /* event loop */
209 static BOOL send_appdefined = YES;
210 #define NO_APPDEFINED_DATA (-8)
211 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
212 static NSTimer *timed_entry = 0;
213 static NSTimer *scroll_repeat_entry = nil;
214 static fd_set select_readfds, select_writefds;
215 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
216 static int select_nfds = 0, select_valid = 0;
217 static struct timespec select_timeout = { 0, 0 };
218 static int selfds[2] = { -1, -1 };
219 static pthread_mutex_t select_mutex;
220 static int apploopnr = 0;
221 static NSAutoreleasePool *outerpool;
222 static struct input_event *emacs_event = NULL;
223 static struct input_event *q_event_ptr = NULL;
224 static int n_emacs_events_pending = 0;
225 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
226   *ns_pending_service_args;
227 static BOOL ns_do_open_file = NO;
228 static BOOL ns_last_use_native_fullscreen;
230 static struct {
231   struct input_event *q;
232   int nr, cap;
233 } hold_event_q = {
234   NULL, 0, 0
237 #ifdef NS_IMPL_COCOA
239  * State for pending menu activation:
240  * MENU_NONE     Normal state
241  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
242  *               run lisp to update the menu.
243  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
244  *               will open.
245  */
246 #define MENU_NONE 0
247 #define MENU_PENDING 1
248 #define MENU_OPENING 2
249 static int menu_will_open_state = MENU_NONE;
251 /* Saved position for menu click.  */
252 static CGPoint menu_mouse_point;
253 #endif
255 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
256 #define NS_FUNCTION_KEY_MASK 0x800000
257 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
258 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
259 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
260 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
261 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
262 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
263 #define EV_MODIFIERS(e)                               \
264     ((([e modifierFlags] & NSHelpKeyMask) ?           \
265            hyper_modifier : 0)                        \
266      | (!EQ (ns_right_alternate_modifier, Qleft) && \
267         (([e modifierFlags] & NSRightAlternateKeyMask) \
268          == NSRightAlternateKeyMask) ? \
269            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
270      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
271            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
272      | (([e modifierFlags] & NSShiftKeyMask) ?     \
273            shift_modifier : 0)                        \
274      | (!EQ (ns_right_control_modifier, Qleft) && \
275         (([e modifierFlags] & NSRightControlKeyMask) \
276          == NSRightControlKeyMask) ? \
277            parse_solitary_modifier (ns_right_control_modifier) : 0) \
278      | (([e modifierFlags] & NSControlKeyMask) ?      \
279            parse_solitary_modifier (ns_control_modifier) : 0)     \
280      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
281            parse_solitary_modifier (ns_function_modifier) : 0)    \
282      | (!EQ (ns_right_command_modifier, Qleft) && \
283         (([e modifierFlags] & NSRightCommandKeyMask) \
284          == NSRightCommandKeyMask) ? \
285            parse_solitary_modifier (ns_right_command_modifier) : 0) \
286      | (([e modifierFlags] & NSCommandKeyMask) ?      \
287            parse_solitary_modifier (ns_command_modifier):0))
289 #define EV_UDMODIFIERS(e)                                      \
290     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
291      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
292      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
293      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
294      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
295      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
296      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
297      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
298      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
300 #define EV_BUTTON(e)                                                         \
301     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
302       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
303      [e buttonNumber] - 1)
305 /* Convert the time field to a timestamp in milliseconds. */
306 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
308 /* This is a piece of code which is common to all the event handling
309    methods.  Maybe it should even be a function.  */
310 #define EV_TRAILER(e)                                                   \
311     {                                                                   \
312       XSETFRAME (emacs_event->frame_or_window, emacsframe);             \
313       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
314       if (q_event_ptr)                                                  \
315         {                                                               \
316           n_emacs_events_pending++;                                     \
317           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
318         }                                                               \
319       else                                                              \
320         hold_event (emacs_event);                                       \
321       EVENT_INIT (*emacs_event);                                        \
322       ns_send_appdefined (-1);                                          \
323     }
325 /* TODO: get rid of need for these forward declarations */
326 static void ns_condemn_scroll_bars (struct frame *f);
327 static void ns_judge_scroll_bars (struct frame *f);
328 void x_set_frame_alpha (struct frame *f);
331 /* ==========================================================================
333     Utilities
335    ========================================================================== */
337 static void
338 hold_event (struct input_event *event)
340   if (hold_event_q.nr == hold_event_q.cap)
341     {
342       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
343       else hold_event_q.cap *= 2;
344       hold_event_q.q =
345         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
346     }
348   hold_event_q.q[hold_event_q.nr++] = *event;
349   /* Make sure ns_read_socket is called, i.e. we have input.  */
350   raise (SIGIO);
351   send_appdefined = YES;
354 static Lisp_Object
355 append2 (Lisp_Object list, Lisp_Object item)
356 /* --------------------------------------------------------------------------
357    Utility to append to a list
358    -------------------------------------------------------------------------- */
360   Lisp_Object array[2];
361   array[0] = list;
362   array[1] = list1 (item);
363   return Fnconc (2, &array[0]);
367 const char *
368 ns_etc_directory (void)
369 /* If running as a self-contained app bundle, return as a string the
370    filename of the etc directory, if present; else nil.  */
372   NSBundle *bundle = [NSBundle mainBundle];
373   NSString *resourceDir = [bundle resourcePath];
374   NSString *resourcePath;
375   NSFileManager *fileManager = [NSFileManager defaultManager];
376   BOOL isDir;
378   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
379   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
380     {
381       if (isDir) return [resourcePath UTF8String];
382     }
383   return NULL;
387 const char *
388 ns_exec_path (void)
389 /* If running as a self-contained app bundle, return as a path string
390    the filenames of the libexec and bin directories, ie libexec:bin.
391    Otherwise, return nil.
392    Normally, Emacs does not add its own bin/ directory to the PATH.
393    However, a self-contained NS build has a different layout, with
394    bin/ and libexec/ subdirectories in the directory that contains
395    Emacs.app itself.
396    We put libexec first, because init_callproc_1 uses the first
397    element to initialize exec-directory.  An alternative would be
398    for init_callproc to check for invocation-directory/libexec.
401   NSBundle *bundle = [NSBundle mainBundle];
402   NSString *resourceDir = [bundle resourcePath];
403   NSString *binDir = [bundle bundlePath];
404   NSString *resourcePath, *resourcePaths;
405   NSRange range;
406   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
407   NSFileManager *fileManager = [NSFileManager defaultManager];
408   NSArray *paths;
409   NSEnumerator *pathEnum;
410   BOOL isDir;
412   range = [resourceDir rangeOfString: @"Contents"];
413   if (range.location != NSNotFound)
414     {
415       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
416 #ifdef NS_IMPL_COCOA
417       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
418 #endif
419     }
421   paths = [binDir stringsByAppendingPaths:
422                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
423   pathEnum = [paths objectEnumerator];
424   resourcePaths = @"";
426   while ((resourcePath = [pathEnum nextObject]))
427     {
428       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
429         if (isDir)
430           {
431             if ([resourcePaths length] > 0)
432               resourcePaths
433                 = [resourcePaths stringByAppendingString: pathSeparator];
434             resourcePaths
435               = [resourcePaths stringByAppendingString: resourcePath];
436           }
437     }
438   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
440   return NULL;
444 const char *
445 ns_load_path (void)
446 /* If running as a self-contained app bundle, return as a path string
447    the filenames of the site-lisp, lisp and leim directories.
448    Ie, site-lisp:lisp:leim.  Otherwise, return nil.  */
450   NSBundle *bundle = [NSBundle mainBundle];
451   NSString *resourceDir = [bundle resourcePath];
452   NSString *resourcePath, *resourcePaths;
453   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
454   NSFileManager *fileManager = [NSFileManager defaultManager];
455   BOOL isDir;
456   NSArray *paths = [resourceDir stringsByAppendingPaths:
457                               [NSArray arrayWithObjects:
458                                          @"site-lisp", @"lisp", @"leim", nil]];
459   NSEnumerator *pathEnum = [paths objectEnumerator];
460   resourcePaths = @"";
462   /* Hack to skip site-lisp.  */
463   if (no_site_lisp) resourcePath = [pathEnum nextObject];
465   while ((resourcePath = [pathEnum nextObject]))
466     {
467       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
468         if (isDir)
469           {
470             if ([resourcePaths length] > 0)
471               resourcePaths
472                 = [resourcePaths stringByAppendingString: pathSeparator];
473             resourcePaths
474               = [resourcePaths stringByAppendingString: resourcePath];
475           }
476     }
477   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
479   return NULL;
482 static void
483 ns_timeout (int usecs)
484 /* --------------------------------------------------------------------------
485      Blocking timer utility used by ns_ring_bell
486    -------------------------------------------------------------------------- */
488   struct timespec wakeup = timespec_add (current_timespec (),
489                                          make_timespec (0, usecs * 1000));
491   /* Keep waiting until past the time wakeup.  */
492   while (1)
493     {
494       struct timespec timeout, now = current_timespec ();
495       if (timespec_cmp (wakeup, now) <= 0)
496         break;
497       timeout = timespec_sub (wakeup, now);
499       /* Try to wait that long--but we might wake up sooner.  */
500       pselect (0, NULL, NULL, NULL, &timeout, NULL);
501     }
505 void
506 ns_release_object (void *obj)
507 /* --------------------------------------------------------------------------
508     Release an object (callable from C)
509    -------------------------------------------------------------------------- */
511     [(id)obj release];
515 void
516 ns_retain_object (void *obj)
517 /* --------------------------------------------------------------------------
518     Retain an object (callable from C)
519    -------------------------------------------------------------------------- */
521     [(id)obj retain];
525 void *
526 ns_alloc_autorelease_pool (void)
527 /* --------------------------------------------------------------------------
528      Allocate a pool for temporary objects (callable from C)
529    -------------------------------------------------------------------------- */
531   return [[NSAutoreleasePool alloc] init];
535 void
536 ns_release_autorelease_pool (void *pool)
537 /* --------------------------------------------------------------------------
538      Free a pool and temporary objects it refers to (callable from C)
539    -------------------------------------------------------------------------- */
541   ns_release_object (pool);
546 /* ==========================================================================
548     Focus (clipping) and screen update
550    ========================================================================== */
553 // Window constraining
554 // -------------------
556 // To ensure that the windows are not placed under the menu bar, they
557 // are typically moved by the call-back constrainFrameRect. However,
558 // by overriding it, it's possible to inhibit this, leaving the window
559 // in it's original position.
561 // It's possible to hide the menu bar. However, technically, it's only
562 // possible to hide it when the application is active. To ensure that
563 // this work properly, the menu bar and window constraining are
564 // deferred until the application becomes active.
566 // Even though it's not possible to manually move a window above the
567 // top of the screen, it is allowed if it's done programmatically,
568 // when the menu is hidden. This allows the editable area to cover the
569 // full screen height.
571 // Test cases
572 // ----------
574 // Use the following extra files:
576 //    init.el:
577 //       ;; Hide menu and place frame slightly above the top of the screen.
578 //       (setq ns-auto-hide-menu-bar t)
579 //       (set-frame-position (selected-frame) 0 -20)
581 // Test 1:
583 //    emacs -Q -l init.el
585 //    Result: No menu bar, and the title bar should be above the screen.
587 // Test 2:
589 //    emacs -Q
591 //    Result: Menu bar visible, frame placed immediately below the menu.
594 static void
595 ns_constrain_all_frames (void)
597   Lisp_Object tail, frame;
599   FOR_EACH_FRAME (tail, frame)
600     {
601       struct frame *f = XFRAME (frame);
602       if (FRAME_NS_P (f))
603         {
604           NSView *view = FRAME_NS_VIEW (f);
605           /* This no-op will trigger the default window placing
606            * constraint system. */
607           f->output_data.ns->dont_constrain = 0;
608           [[view window] setFrameOrigin:[[view window] frame].origin];
609         }
610     }
614 /* True, if the menu bar should be hidden.  */
616 static BOOL
617 ns_menu_bar_should_be_hidden (void)
619   return !NILP (ns_auto_hide_menu_bar)
620     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
624 /* Show or hide the menu bar, based on user setting.  */
626 static void
627 ns_update_auto_hide_menu_bar (void)
629 #ifdef NS_IMPL_COCOA
630 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
631   block_input ();
633   NSTRACE (ns_update_auto_hide_menu_bar);
635   if (NSApp != nil
636       && [NSApp isActive]
637       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
638     {
639       // Note, "setPresentationOptions" triggers an error unless the
640       // application is active.
641       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
643       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
644         {
645           NSApplicationPresentationOptions options
646             = NSApplicationPresentationAutoHideDock;
648           if (menu_bar_should_be_hidden)
649             options |= NSApplicationPresentationAutoHideMenuBar;
651           [NSApp setPresentationOptions: options];
653           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
655           if (!ns_menu_bar_is_hidden)
656             {
657               ns_constrain_all_frames ();
658             }
659         }
660     }
662   unblock_input ();
663 #endif
664 #endif
668 static void
669 ns_update_begin (struct frame *f)
670 /* --------------------------------------------------------------------------
671    Prepare for a grouped sequence of drawing calls
672    external (RIF) call; whole frame, called before update_window_begin
673    -------------------------------------------------------------------------- */
675   NSView *view = FRAME_NS_VIEW (f);
676   NSTRACE (ns_update_begin);
678   ns_update_auto_hide_menu_bar ();
680   ns_updating_frame = f;
681   [view lockFocus];
683   /* drawRect may have been called for say the minibuffer, and then clip path
684      is for the minibuffer.  But the display engine may draw more because
685      we have set the frame as garbaged.  So reset clip path to the whole
686      view.  */
687 #ifdef NS_IMPL_COCOA
688   {
689     NSBezierPath *bp;
690     NSRect r = [view frame];
691     NSRect cr = [[view window] frame];
692     /* If a large frame size is set, r may be larger than the window frame
693        before constrained.  In that case don't change the clip path, as we
694        will clear in to the tool bar and title bar.  */
695     if (r.size.height
696         + FRAME_NS_TITLEBAR_HEIGHT (f)
697         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
698       {
699         bp = [[NSBezierPath bezierPathWithRect: r] retain];
700         [bp setClip];
701         [bp release];
702       }
703   }
704 #endif
706 #ifdef NS_IMPL_GNUSTEP
707   uRect = NSMakeRect (0, 0, 0, 0);
708 #endif
712 static void
713 ns_update_window_begin (struct window *w)
714 /* --------------------------------------------------------------------------
715    Prepare for a grouped sequence of drawing calls
716    external (RIF) call; for one window, called after update_begin
717    -------------------------------------------------------------------------- */
719   struct frame *f = XFRAME (WINDOW_FRAME (w));
720   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
722   NSTRACE (ns_update_window_begin);
723   set_output_cursor (&w->cursor);
725   block_input ();
727   if (f == hlinfo->mouse_face_mouse_frame)
728     {
729       /* Don't do highlighting for mouse motion during the update.  */
730       hlinfo->mouse_face_defer = 1;
732         /* If the frame needs to be redrawn,
733            simply forget about any prior mouse highlighting.  */
734       if (FRAME_GARBAGED_P (f))
735         hlinfo->mouse_face_window = Qnil;
737       /* (further code for mouse faces ifdef'd out in other terms elided) */
738     }
740   unblock_input ();
744 static void
745 ns_update_window_end (struct window *w, bool cursor_on_p,
746                       bool mouse_face_overwritten_p)
747 /* --------------------------------------------------------------------------
748    Finished a grouped sequence of drawing calls
749    external (RIF) call; for one window called before update_end
750    -------------------------------------------------------------------------- */
752   /* note: this fn is nearly identical in all terms */
753   if (!w->pseudo_window_p)
754     {
755       block_input ();
757       if (cursor_on_p)
758         display_and_set_cursor (w, 1,
759                                 output_cursor.hpos, output_cursor.vpos,
760                                 output_cursor.x, output_cursor.y);
762       if (draw_window_fringes (w, 1))
763         x_draw_vertical_border (w);
765       unblock_input ();
766     }
768   /* If a row with mouse-face was overwritten, arrange for
769      frame_up_to_date to redisplay the mouse highlight.  */
770   if (mouse_face_overwritten_p)
771     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
773   NSTRACE (update_window_end);
777 static void
778 ns_update_end (struct frame *f)
779 /* --------------------------------------------------------------------------
780    Finished a grouped sequence of drawing calls
781    external (RIF) call; for whole frame, called after update_window_end
782    -------------------------------------------------------------------------- */
784   EmacsView *view = FRAME_NS_VIEW (f);
786 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
787   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
789   block_input ();
791   [view unlockFocus];
792   [[view window] flushWindow];
794   unblock_input ();
795   ns_updating_frame = NULL;
796   NSTRACE (ns_update_end);
800 static void
801 ns_flush (struct frame *f)
802 /* --------------------------------------------------------------------------
803    external (RIF) call
804    NS impl is no-op since currently we flush in ns_update_end and elsewhere
805    -------------------------------------------------------------------------- */
807     NSTRACE (ns_flush);
811 static void
812 ns_focus (struct frame *f, NSRect *r, int n)
813 /* --------------------------------------------------------------------------
814    Internal: Focus on given frame.  During small local updates this is used to
815      draw, however during large updates, ns_update_begin and ns_update_end are
816      called to wrap the whole thing, in which case these calls are stubbed out.
817      Except, on GNUstep, we accumulate the rectangle being drawn into, because
818      the back end won't do this automatically, and will just end up flushing
819      the entire window.
820    -------------------------------------------------------------------------- */
822 //  NSTRACE (ns_focus);
823 /* static int c =0;
824    fprintf (stderr, "focus: %d", c++);
825    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
826    fprintf (stderr, "\n"); */
828   if (f != ns_updating_frame)
829     {
830       NSView *view = FRAME_NS_VIEW (f);
831       if (view != focus_view)
832         {
833           if (focus_view != NULL)
834             {
835               [focus_view unlockFocus];
836               [[focus_view window] flushWindow];
837 /*debug_lock--; */
838             }
840           if (view)
841             [view lockFocus];
842           focus_view = view;
843 /*if (view) debug_lock++; */
844         }
845     }
847   /* clipping */
848   if (r)
849     {
850       [[NSGraphicsContext currentContext] saveGraphicsState];
851       if (n == 2)
852         NSRectClipList (r, 2);
853       else
854         NSRectClip (*r);
855       gsaved = YES;
856     }
860 static void
861 ns_unfocus (struct frame *f)
862 /* --------------------------------------------------------------------------
863      Internal: Remove focus on given frame
864    -------------------------------------------------------------------------- */
866 //  NSTRACE (ns_unfocus);
868   if (gsaved)
869     {
870       [[NSGraphicsContext currentContext] restoreGraphicsState];
871       gsaved = NO;
872     }
874   if (f != ns_updating_frame)
875     {
876       if (focus_view != NULL)
877         {
878           [focus_view unlockFocus];
879           [[focus_view window] flushWindow];
880           focus_view = NULL;
881 /*debug_lock--; */
882         }
883     }
887 static void
888 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
889 /* --------------------------------------------------------------------------
890      Internal (but parallels other terms): Focus drawing on given row
891    -------------------------------------------------------------------------- */
893   struct frame *f = XFRAME (WINDOW_FRAME (w));
894   NSRect clip_rect;
895   int window_x, window_y, window_width;
897   window_box (w, area, &window_x, &window_y, &window_width, 0);
899   clip_rect.origin.x = window_x;
900   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
901   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
902   clip_rect.size.width = window_width;
903   clip_rect.size.height = row->visible_height;
905   ns_focus (f, &clip_rect, 1);
909 static void
910 ns_ring_bell (struct frame *f)
911 /* --------------------------------------------------------------------------
912      "Beep" routine
913    -------------------------------------------------------------------------- */
915   NSTRACE (ns_ring_bell);
916   if (visible_bell)
917     {
918       NSAutoreleasePool *pool;
919       struct frame *frame = SELECTED_FRAME ();
920       NSView *view;
922       block_input ();
923       pool = [[NSAutoreleasePool alloc] init];
925       view = FRAME_NS_VIEW (frame);
926       if (view != nil)
927         {
928           NSRect r, surr;
929           NSPoint dim = NSMakePoint (128, 128);
931           r = [view bounds];
932           r.origin.x += (r.size.width - dim.x) / 2;
933           r.origin.y += (r.size.height - dim.y) / 2;
934           r.size.width = dim.x;
935           r.size.height = dim.y;
936           surr = NSInsetRect (r, -2, -2);
937           ns_focus (frame, &surr, 1);
938           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
939           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
940                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
941           NSRectFill (r);
942           [[view window] flushWindow];
943           ns_timeout (150000);
944           [[view window] restoreCachedImage];
945           [[view window] flushWindow];
946           ns_unfocus (frame);
947         }
948       [pool release];
949       unblock_input ();
950     }
951   else
952     {
953       NSBeep ();
954     }
958 static void
959 ns_reset_terminal_modes (struct terminal *terminal)
960 /*  Externally called as hook */
962   NSTRACE (ns_reset_terminal_modes);
966 static void
967 ns_set_terminal_modes (struct terminal *terminal)
968 /*  Externally called as hook */
970   NSTRACE (ns_set_terminal_modes);
975 /* ==========================================================================
977     Frame / window manager related functions
979    ========================================================================== */
982 static void
983 ns_raise_frame (struct frame *f)
984 /* --------------------------------------------------------------------------
985      Bring window to foreground and make it active
986    -------------------------------------------------------------------------- */
988   NSView *view;
989   check_window_system (f);
990   view = FRAME_NS_VIEW (f);
991   block_input ();
992   if (FRAME_VISIBLE_P (f))
993     [[view window] makeKeyAndOrderFront: NSApp];
994   unblock_input ();
998 static void
999 ns_lower_frame (struct frame *f)
1000 /* --------------------------------------------------------------------------
1001      Send window to back
1002    -------------------------------------------------------------------------- */
1004   NSView *view;
1005   check_window_system (f);
1006   view = FRAME_NS_VIEW (f);
1007   block_input ();
1008   [[view window] orderBack: NSApp];
1009   unblock_input ();
1013 static void
1014 ns_frame_raise_lower (struct frame *f, int raise)
1015 /* --------------------------------------------------------------------------
1016      External (hook)
1017    -------------------------------------------------------------------------- */
1019   NSTRACE (ns_frame_raise_lower);
1021   if (raise)
1022     ns_raise_frame (f);
1023   else
1024     ns_lower_frame (f);
1028 static void
1029 ns_frame_rehighlight (struct frame *frame)
1030 /* --------------------------------------------------------------------------
1031      External (hook): called on things like window switching within frame
1032    -------------------------------------------------------------------------- */
1034   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1035   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1037   NSTRACE (ns_frame_rehighlight);
1038   if (dpyinfo->x_focus_frame)
1039     {
1040       dpyinfo->x_highlight_frame
1041         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1042            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1043            : dpyinfo->x_focus_frame);
1044       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1045         {
1046           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1047           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1048         }
1049     }
1050   else
1051       dpyinfo->x_highlight_frame = 0;
1053   if (dpyinfo->x_highlight_frame &&
1054          dpyinfo->x_highlight_frame != old_highlight)
1055     {
1056       if (old_highlight)
1057         {
1058           x_update_cursor (old_highlight, 1);
1059           x_set_frame_alpha (old_highlight);
1060         }
1061       if (dpyinfo->x_highlight_frame)
1062         {
1063           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1064           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1065         }
1066     }
1070 void
1071 x_make_frame_visible (struct frame *f)
1072 /* --------------------------------------------------------------------------
1073      External: Show the window (X11 semantics)
1074    -------------------------------------------------------------------------- */
1076   NSTRACE (x_make_frame_visible);
1077   /* XXX: at some points in past this was not needed, as the only place that
1078      called this (frame.c:Fraise_frame ()) also called raise_lower;
1079      if this ends up the case again, comment this out again. */
1080   if (!FRAME_VISIBLE_P (f))
1081     {
1082       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1084       SET_FRAME_VISIBLE (f, 1);
1085       ns_raise_frame (f);
1087       /* Making a new frame from a fullscreen frame will make the new frame
1088          fullscreen also.  So skip handleFS as this will print an error.  */
1089       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1090           && [view isFullscreen])
1091         return;
1093       if (f->want_fullscreen != FULLSCREEN_NONE)
1094         {
1095           block_input ();
1096           [view handleFS];
1097           unblock_input ();
1098         }
1099     }
1103 void
1104 x_make_frame_invisible (struct frame *f)
1105 /* --------------------------------------------------------------------------
1106      External: Hide the window (X11 semantics)
1107    -------------------------------------------------------------------------- */
1109   NSView *view;
1110   NSTRACE (x_make_frame_invisible);
1111   check_window_system (f);
1112   view = FRAME_NS_VIEW (f);
1113   [[view window] orderOut: NSApp];
1114   SET_FRAME_VISIBLE (f, 0);
1115   SET_FRAME_ICONIFIED (f, 0);
1119 void
1120 x_iconify_frame (struct frame *f)
1121 /* --------------------------------------------------------------------------
1122      External: Iconify window
1123    -------------------------------------------------------------------------- */
1125   NSView *view;
1126   struct ns_display_info *dpyinfo;
1128   NSTRACE (x_iconify_frame);
1129   check_window_system (f);
1130   view = FRAME_NS_VIEW (f);
1131   dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1133   if (dpyinfo->x_highlight_frame == f)
1134     dpyinfo->x_highlight_frame = 0;
1136   if ([[view window] windowNumber] <= 0)
1137     {
1138       /* the window is still deferred.  Make it very small, bring it
1139          on screen and order it out. */
1140       NSRect s = { { 100, 100}, {0, 0} };
1141       NSRect t;
1142       t = [[view window] frame];
1143       [[view window] setFrame: s display: NO];
1144       [[view window] orderBack: NSApp];
1145       [[view window] orderOut: NSApp];
1146       [[view window] setFrame: t display: NO];
1147     }
1148   [[view window] miniaturize: NSApp];
1151 /* Free X resources of frame F.  */
1153 void
1154 x_free_frame_resources (struct frame *f)
1156   NSView *view;
1157   struct ns_display_info *dpyinfo;
1158   Mouse_HLInfo *hlinfo;
1160   NSTRACE (x_free_frame_resources);
1161   check_window_system (f);
1162   view = FRAME_NS_VIEW (f);
1163   dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1164   hlinfo = MOUSE_HL_INFO (f);
1166   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1168   block_input ();
1170   free_frame_menubar (f);
1172   if (FRAME_FACE_CACHE (f))
1173     free_frame_faces (f);
1175   if (f == dpyinfo->x_focus_frame)
1176     dpyinfo->x_focus_frame = 0;
1177   if (f == dpyinfo->x_highlight_frame)
1178     dpyinfo->x_highlight_frame = 0;
1179   if (f == hlinfo->mouse_face_mouse_frame)
1180     reset_mouse_highlight (hlinfo);
1182   if (f->output_data.ns->miniimage != nil)
1183     [f->output_data.ns->miniimage release];
1185   [[view window] close];
1186   [view release];
1188   xfree (f->output_data.ns);
1190   unblock_input ();
1193 void
1194 x_destroy_window (struct frame *f)
1195 /* --------------------------------------------------------------------------
1196      External: Delete the window
1197    -------------------------------------------------------------------------- */
1199   NSTRACE (x_destroy_window);
1200   check_window_system (f);
1201   x_free_frame_resources (f);
1202   ns_window_num--;
1206 void
1207 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1208 /* --------------------------------------------------------------------------
1209      External: Position the window
1210    -------------------------------------------------------------------------- */
1212   NSView *view = FRAME_NS_VIEW (f);
1213   NSArray *screens = [NSScreen screens];
1214   NSScreen *fscreen = [screens objectAtIndex: 0];
1215   NSScreen *screen = [[view window] screen];
1217   NSTRACE (x_set_offset);
1219   block_input ();
1221   f->left_pos = xoff;
1222   f->top_pos = yoff;
1224   if (view != nil && screen && fscreen)
1225     {
1226       f->left_pos = f->size_hint_flags & XNegative
1227         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1228         : f->left_pos;
1229       /* We use visibleFrame here to take menu bar into account.
1230          Ideally we should also adjust left/top with visibleFrame.origin.  */
1232       f->top_pos = f->size_hint_flags & YNegative
1233         ? ([screen visibleFrame].size.height + f->top_pos
1234            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1235            - FRAME_TOOLBAR_HEIGHT (f))
1236         : f->top_pos;
1237 #ifdef NS_IMPL_GNUSTEP
1238       if (f->left_pos < 100)
1239         f->left_pos = 100;  /* don't overlap menu */
1240 #endif
1241       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1242          menu bar.  */
1243       f->output_data.ns->dont_constrain = 0;
1244       [[view window] setFrameTopLeftPoint:
1245                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1246                                     SCREENMAXBOUND ([fscreen frame].size.height
1247                                                     - NS_TOP_POS (f)))];
1248       f->size_hint_flags &= ~(XNegative|YNegative);
1249     }
1251   unblock_input ();
1255 void
1256 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1257 /* --------------------------------------------------------------------------
1258      Adjust window pixel size based on given character grid size
1259      Impl is a bit more complex than other terms, need to do some
1260      internal clipping.
1261    -------------------------------------------------------------------------- */
1263   EmacsView *view = FRAME_NS_VIEW (f);
1264   NSWindow *window = [view window];
1265   NSRect wr = [window frame];
1266   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1267   int pixelwidth, pixelheight;
1269   NSTRACE (x_set_window_size);
1271   if (view == nil)
1272     return;
1274 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1276   block_input ();
1278   check_frame_size (f, &rows, &cols);
1280   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1281   compute_fringe_widths (f, 0);
1283   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1284   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1286   /* If we have a toolbar, take its height into account. */
1287   if (tb && ! [view isFullscreen])
1288     {
1289     /* NOTE: previously this would generate wrong result if toolbar not
1290              yet displayed and fixing toolbar_height=32 helped, but
1291              now (200903) seems no longer needed */
1292     FRAME_TOOLBAR_HEIGHT (f) =
1293       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1294         - FRAME_NS_TITLEBAR_HEIGHT (f);
1295 #ifdef NS_IMPL_GNUSTEP
1296       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1297 #endif
1298     }
1299   else
1300     FRAME_TOOLBAR_HEIGHT (f) = 0;
1302   wr.size.width = pixelwidth + f->border_width;
1303   wr.size.height = pixelheight;
1304   if (! [view isFullscreen])
1305     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1306       + FRAME_TOOLBAR_HEIGHT (f);
1308   /* Do not try to constrain to this screen.  We may have multiple
1309      screens, and want Emacs to span those.  Constraining to screen
1310      prevents that, and that is not nice to the user.  */
1311  if (f->output_data.ns->zooming)
1312    f->output_data.ns->zooming = 0;
1313  else
1314    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1316   [view setRows: rows andColumns: cols];
1317   [window setFrame: wr display: YES];
1319 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1321   /* This is a trick to compensate for Emacs' managing the scrollbar area
1322      as a fixed number of standard character columns.  Instead of leaving
1323      blank space for the extra, we chopped it off above.  Now for
1324      left-hand scrollbars, we shift all rendering to the left by the
1325      difference between the real width and Emacs' imagined one.  For
1326      right-hand bars, don't worry about it since the extra is never used.
1327      (Obviously doesn't work for vertically split windows tho..) */
1328   {
1329     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1330       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1331                      - NS_SCROLL_BAR_WIDTH (f), 0)
1332       : NSMakePoint (0, 0);
1333     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1334     [view setBoundsOrigin: origin];
1335   }
1337   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1338   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1339   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1340 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1342   mark_window_cursors_off (XWINDOW (f->root_window));
1343   cancel_mouse_face (f);
1345   unblock_input ();
1349 static void
1350 ns_fullscreen_hook (struct frame *f)
1352   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1354   if (!FRAME_VISIBLE_P (f))
1355     return;
1357    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1358     {
1359       /* Old style fs don't initiate correctly if created from
1360          init/default-frame alist, so use a timer (not nice...).
1361       */
1362       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1363                                      selector: @selector (handleFS)
1364                                      userInfo: nil repeats: NO];
1365       return;
1366     }
1368   block_input ();
1369   [view handleFS];
1370   unblock_input ();
1373 /* ==========================================================================
1375     Color management
1377    ========================================================================== */
1380 NSColor *
1381 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1383   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1384   if (idx < 1 || idx >= color_table->avail)
1385     return nil;
1386   return color_table->colors[idx];
1390 unsigned long
1391 ns_index_color (NSColor *color, struct frame *f)
1393   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1394   ptrdiff_t idx;
1395   ptrdiff_t i;
1397   if (!color_table->colors)
1398     {
1399       color_table->size = NS_COLOR_CAPACITY;
1400       color_table->avail = 1; /* skip idx=0 as marker */
1401       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1402       color_table->colors[0] = nil;
1403       color_table->empty_indices = [[NSMutableSet alloc] init];
1404     }
1406   /* do we already have this color ? */
1407   for (i = 1; i < color_table->avail; i++)
1408     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1409       return i;
1411   if ([color_table->empty_indices count] > 0)
1412     {
1413       NSNumber *index = [color_table->empty_indices anyObject];
1414       [color_table->empty_indices removeObject: index];
1415       idx = [index unsignedLongValue];
1416     }
1417   else
1418     {
1419       if (color_table->avail == color_table->size)
1420         color_table->colors =
1421           xpalloc (color_table->colors, &color_table->size, 1,
1422                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1423       idx = color_table->avail++;
1424     }
1426   color_table->colors[idx] = color;
1427   [color retain];
1428 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1429   return idx;
1433 void
1434 ns_free_indexed_color (unsigned long idx, struct frame *f)
1436   struct ns_color_table *color_table;
1437   NSColor *color;
1438   NSNumber *index;
1440   if (!f)
1441     return;
1443   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1445   if (idx <= 0 || idx >= color_table->size) {
1446     message1 ("ns_free_indexed_color: Color index out of range.\n");
1447     return;
1448   }
1450   index = [NSNumber numberWithUnsignedInt: idx];
1451   if ([color_table->empty_indices containsObject: index]) {
1452     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1453     return;
1454   }
1456   color = color_table->colors[idx];
1457   [color release];
1458   color_table->colors[idx] = nil;
1459   [color_table->empty_indices addObject: index];
1460 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1464 static int
1465 ns_get_color (const char *name, NSColor **col)
1466 /* --------------------------------------------------------------------------
1467      Parse a color name
1468    -------------------------------------------------------------------------- */
1469 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1470    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1471    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1473   NSColor *new = nil;
1474   static char hex[20];
1475   int scaling;
1476   float r = -1.0, g, b;
1477   NSString *nsname = [NSString stringWithUTF8String: name];
1479 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1480   block_input ();
1482   if ([nsname isEqualToString: @"ns_selection_color"])
1483     {
1484       nsname = ns_selection_color;
1485       name = [ns_selection_color UTF8String];
1486     }
1488   /* First, check for some sort of numeric specification. */
1489   hex[0] = '\0';
1491   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1492     {
1493       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1494       [scanner scanFloat: &r];
1495       [scanner scanFloat: &g];
1496       [scanner scanFloat: &b];
1497     }
1498   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1499     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1500   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1501     {
1502       int len = (strlen(name) - 1);
1503       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1504       int i;
1505       scaling = strlen(name+start) / 3;
1506       for (i = 0; i < 3; i++)
1507         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1508                  name + start + i * scaling);
1509       hex[3 * (scaling + 1) - 1] = '\0';
1510     }
1512   if (hex[0])
1513     {
1514       int rr, gg, bb;
1515       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1516       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1517         {
1518           r = rr / fscale;
1519           g = gg / fscale;
1520           b = bb / fscale;
1521         }
1522     }
1524   if (r >= 0.0F)
1525     {
1526       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1527       unblock_input ();
1528       return 0;
1529     }
1531   /* Otherwise, color is expected to be from a list */
1532   {
1533     NSEnumerator *lenum, *cenum;
1534     NSString *name;
1535     NSColorList *clist;
1537 #ifdef NS_IMPL_GNUSTEP
1538     /* XXX: who is wrong, the requestor or the implementation? */
1539     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1540         == NSOrderedSame)
1541       nsname = @"highlightColor";
1542 #endif
1544     lenum = [[NSColorList availableColorLists] objectEnumerator];
1545     while ( (clist = [lenum nextObject]) && new == nil)
1546       {
1547         cenum = [[clist allKeys] objectEnumerator];
1548         while ( (name = [cenum nextObject]) && new == nil )
1549           {
1550             if ([name compare: nsname
1551                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1552               new = [clist colorWithKey: name];
1553           }
1554       }
1555   }
1557   if (new)
1558     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1559   unblock_input ();
1560   return new ? 0 : 1;
1565 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1566 /* --------------------------------------------------------------------------
1567      Convert a Lisp string object to a NS color
1568    -------------------------------------------------------------------------- */
1570   NSTRACE (ns_lisp_to_color);
1571   if (STRINGP (color))
1572     return ns_get_color (SSDATA (color), col);
1573   else if (SYMBOLP (color))
1574     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1575   return 1;
1579 Lisp_Object
1580 ns_color_to_lisp (NSColor *col)
1581 /* --------------------------------------------------------------------------
1582      Convert a color to a lisp string with the RGB equivalent
1583    -------------------------------------------------------------------------- */
1585   EmacsCGFloat red, green, blue, alpha, gray;
1586   char buf[1024];
1587   const char *str;
1588   NSTRACE (ns_color_to_lisp);
1590   block_input ();
1591   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1593       if ((str =[[col colorNameComponent] UTF8String]))
1594         {
1595           unblock_input ();
1596           return build_string ((char *)str);
1597         }
1599     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1600         getRed: &red green: &green blue: &blue alpha: &alpha];
1601   if (red ==green && red ==blue)
1602     {
1603       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1604             getWhite: &gray alpha: &alpha];
1605       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1606                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1607       unblock_input ();
1608       return build_string (buf);
1609     }
1611   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1612             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1614   unblock_input ();
1615   return build_string (buf);
1619 void
1620 ns_query_color(void *col, XColor *color_def, int setPixel)
1621 /* --------------------------------------------------------------------------
1622          Get ARGB values out of NSColor col and put them into color_def.
1623          If setPixel, set the pixel to a concatenated version.
1624          and set color_def pixel to the resulting index.
1625    -------------------------------------------------------------------------- */
1627   EmacsCGFloat r, g, b, a;
1629   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1630   color_def->red   = r * 65535;
1631   color_def->green = g * 65535;
1632   color_def->blue  = b * 65535;
1634   if (setPixel == YES)
1635     color_def->pixel
1636       = ARGB_TO_ULONG((int)(a*255),
1637                       (int)(r*255), (int)(g*255), (int)(b*255));
1641 bool
1642 ns_defined_color (struct frame *f,
1643                   const char *name,
1644                   XColor *color_def,
1645                   bool alloc,
1646                   bool makeIndex)
1647 /* --------------------------------------------------------------------------
1648          Return true if named color found, and set color_def rgb accordingly.
1649          If makeIndex and alloc are nonzero put the color in the color_table,
1650          and set color_def pixel to the resulting index.
1651          If makeIndex is zero, set color_def pixel to ARGB.
1652          Return false if not found
1653    -------------------------------------------------------------------------- */
1655   NSColor *col;
1656   NSTRACE (ns_defined_color);
1658   block_input ();
1659   if (ns_get_color (name, &col) != 0) /* Color not found  */
1660     {
1661       unblock_input ();
1662       return 0;
1663     }
1664   if (makeIndex && alloc)
1665     color_def->pixel = ns_index_color (col, f);
1666   ns_query_color (col, color_def, !makeIndex);
1667   unblock_input ();
1668   return 1;
1672 void
1673 x_set_frame_alpha (struct frame *f)
1674 /* --------------------------------------------------------------------------
1675      change the entire-frame transparency
1676    -------------------------------------------------------------------------- */
1678   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1679   double alpha = 1.0;
1680   double alpha_min = 1.0;
1682   if (dpyinfo->x_highlight_frame == f)
1683     alpha = f->alpha[0];
1684   else
1685     alpha = f->alpha[1];
1687   if (FLOATP (Vframe_alpha_lower_limit))
1688     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1689   else if (INTEGERP (Vframe_alpha_lower_limit))
1690     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1692   if (alpha < 0.0)
1693     return;
1694   else if (1.0 < alpha)
1695     alpha = 1.0;
1696   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1697     alpha = alpha_min;
1699 #ifdef NS_IMPL_COCOA
1700   {
1701     EmacsView *view = FRAME_NS_VIEW (f);
1702   [[view window] setAlphaValue: alpha];
1703   }
1704 #endif
1708 /* ==========================================================================
1710     Mouse handling
1712    ========================================================================== */
1715 void
1716 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1717 /* --------------------------------------------------------------------------
1718      Programmatically reposition mouse pointer in pixel coordinates
1719    -------------------------------------------------------------------------- */
1721   NSTRACE (x_set_mouse_pixel_position);
1722   ns_raise_frame (f);
1723 #if 0
1724   /* FIXME: this does not work, and what about GNUstep? */
1725 #ifdef NS_IMPL_COCOA
1726   [FRAME_NS_VIEW (f) lockFocus];
1727   PSsetmouse ((float)pix_x, (float)pix_y);
1728   [FRAME_NS_VIEW (f) unlockFocus];
1729 #endif
1730 #endif
1734 void
1735 x_set_mouse_position (struct frame *f, int h, int v)
1736 /* --------------------------------------------------------------------------
1737      Programmatically reposition mouse pointer in character coordinates
1738    -------------------------------------------------------------------------- */
1740   int pix_x, pix_y;
1742   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1743   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1745   if (pix_x < 0) pix_x = 0;
1746   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1748   if (pix_y < 0) pix_y = 0;
1749   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1751   x_set_mouse_pixel_position (f, pix_x, pix_y);
1755 static int
1756 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1757 /*   ------------------------------------------------------------------------
1758      Called by EmacsView on mouseMovement events.  Passes on
1759      to emacs mainstream code if we moved off of a rect of interest
1760      known as last_mouse_glyph.
1761      ------------------------------------------------------------------------ */
1763 //  NSTRACE (note_mouse_movement);
1765   XSETFRAME (last_mouse_motion_frame, frame);
1767   /* Note, this doesn't get called for enter/leave, since we don't have a
1768      position.  Those are taken care of in the corresponding NSView methods. */
1770   /* has movement gone beyond last rect we were tracking? */
1771   if (x < last_mouse_glyph.origin.x ||
1772       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1773       y < last_mouse_glyph.origin.y ||
1774       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1775     {
1776       ns_update_begin(frame);
1777       frame->mouse_moved = 1;
1778       note_mouse_highlight (frame, x, y);
1779       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1780       ns_update_end(frame);
1781       return 1;
1782     }
1784   return 0;
1788 static void
1789 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1790                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1791                    Time *time)
1792 /* --------------------------------------------------------------------------
1793     External (hook): inform emacs about mouse position and hit parts.
1794     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1795     x & y should be position in the scrollbar (the whole bar, not the handle)
1796     and length of scrollbar respectively
1797    -------------------------------------------------------------------------- */
1799   id view;
1800   NSPoint position;
1801   Lisp_Object frame, tail;
1802   struct frame *f;
1803   struct ns_display_info *dpyinfo;
1805   NSTRACE (ns_mouse_position);
1807   if (*fp == NULL)
1808     {
1809       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1810       return;
1811     }
1813   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1815   block_input ();
1817   if (last_mouse_scroll_bar != nil && insist == 0)
1818     {
1819       /* TODO: we do not use this path at the moment because drag events will
1820            go directly to the EmacsScroller.  Leaving code in for now. */
1821       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1822                                               x: x y: y];
1823       if (time) *time = last_mouse_movement_time;
1824       last_mouse_scroll_bar = nil;
1825     }
1826   else
1827     {
1828       /* Clear the mouse-moved flag for every frame on this display.  */
1829       FOR_EACH_FRAME (tail, frame)
1830         if (FRAME_NS_P (XFRAME (frame))
1831             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1832           XFRAME (frame)->mouse_moved = 0;
1834       last_mouse_scroll_bar = nil;
1835       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1836         f = last_mouse_frame;
1837       else
1838         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1839                                     : SELECTED_FRAME ();
1841       if (f && FRAME_NS_P (f))
1842         {
1843           view = FRAME_NS_VIEW (*fp);
1845           position = [[view window] mouseLocationOutsideOfEventStream];
1846           position = [view convertPoint: position fromView: nil];
1847           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1848 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1850           if (bar_window) *bar_window = Qnil;
1851           if (part) *part = 0; /*scroll_bar_handle; */
1853           if (x) XSETINT (*x, lrint (position.x));
1854           if (y) XSETINT (*y, lrint (position.y));
1855           if (time) *time = last_mouse_movement_time;
1856           *fp = f;
1857         }
1858     }
1860   unblock_input ();
1864 static void
1865 ns_frame_up_to_date (struct frame *f)
1866 /* --------------------------------------------------------------------------
1867     External (hook): Fix up mouse highlighting right after a full update.
1868     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1869    -------------------------------------------------------------------------- */
1871   NSTRACE (ns_frame_up_to_date);
1873   if (FRAME_NS_P (f))
1874     {
1875       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1876       if (f == hlinfo->mouse_face_mouse_frame)
1877         {
1878           block_input ();
1879           ns_update_begin(f);
1880           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1881                                 hlinfo->mouse_face_mouse_x,
1882                                 hlinfo->mouse_face_mouse_y);
1883           ns_update_end(f);
1884           unblock_input ();
1885         }
1886     }
1890 static void
1891 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1892 /* --------------------------------------------------------------------------
1893     External (RIF): set frame mouse pointer type.
1894    -------------------------------------------------------------------------- */
1896   NSTRACE (ns_define_frame_cursor);
1897   if (FRAME_POINTER_TYPE (f) != cursor)
1898     {
1899       EmacsView *view = FRAME_NS_VIEW (f);
1900       FRAME_POINTER_TYPE (f) = cursor;
1901       [[view window] invalidateCursorRectsForView: view];
1902       /* Redisplay assumes this function also draws the changed frame
1903          cursor, but this function doesn't, so do it explicitly.  */
1904       x_update_cursor (f, 1);
1905     }
1910 /* ==========================================================================
1912     Keyboard handling
1914    ========================================================================== */
1917 static unsigned
1918 ns_convert_key (unsigned code)
1919 /* --------------------------------------------------------------------------
1920     Internal call used by NSView-keyDown.
1921    -------------------------------------------------------------------------- */
1923   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1924                                 / sizeof (convert_ns_to_X_keysym[0]));
1925   unsigned keysym;
1926   /* An array would be faster, but less easy to read. */
1927   for (keysym = 0; keysym < last_keysym; keysym += 2)
1928     if (code == convert_ns_to_X_keysym[keysym])
1929       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1930   return 0;
1931 /* if decide to use keyCode and Carbon table, use this line:
1932      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1936 char *
1937 x_get_keysym_name (int keysym)
1938 /* --------------------------------------------------------------------------
1939     Called by keyboard.c.  Not sure if the return val is important, except
1940     that it be unique.
1941    -------------------------------------------------------------------------- */
1943   static char value[16];
1944   NSTRACE (x_get_keysym_name);
1945   sprintf (value, "%d", keysym);
1946   return value;
1951 /* ==========================================================================
1953     Block drawing operations
1955    ========================================================================== */
1958 static void
1959 ns_redraw_scroll_bars (struct frame *f)
1961   int i;
1962   id view;
1963   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1964   NSTRACE (ns_redraw_scroll_bars);
1965   for (i =[subviews count]-1; i >= 0; i--)
1966     {
1967       view = [subviews objectAtIndex: i];
1968       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1969       [view display];
1970     }
1974 void
1975 ns_clear_frame (struct frame *f)
1976 /* --------------------------------------------------------------------------
1977       External (hook): Erase the entire frame
1978    -------------------------------------------------------------------------- */
1980   NSView *view = FRAME_NS_VIEW (f);
1981   NSRect r;
1983   NSTRACE (ns_clear_frame);
1985  /* comes on initial frame because we have
1986     after-make-frame-functions = select-frame */
1987  if (!FRAME_DEFAULT_FACE (f))
1988    return;
1990   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1992   output_cursor.hpos = output_cursor.vpos = 0;
1993   output_cursor.x = -1;
1995   r = [view bounds];
1997   block_input ();
1998   ns_focus (f, &r, 1);
1999   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2000   NSRectFill (r);
2001   ns_unfocus (f);
2003   /* as of 2006/11 or so this is now needed */
2004   ns_redraw_scroll_bars (f);
2005   unblock_input ();
2009 static void
2010 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2011 /* --------------------------------------------------------------------------
2012     External (RIF):  Clear section of frame
2013    -------------------------------------------------------------------------- */
2015   NSRect r = NSMakeRect (x, y, width, height);
2016   NSView *view = FRAME_NS_VIEW (f);
2017   struct face *face = FRAME_DEFAULT_FACE (f);
2019   if (!view || !face)
2020     return;
2022   NSTRACE (ns_clear_frame_area);
2024   r = NSIntersectionRect (r, [view frame]);
2025   ns_focus (f, &r, 1);
2026   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2028   NSRectFill (r);
2030   ns_unfocus (f);
2031   return;
2035 static void
2036 ns_scroll_run (struct window *w, struct run *run)
2037 /* --------------------------------------------------------------------------
2038     External (RIF):  Insert or delete n lines at line vpos
2039    -------------------------------------------------------------------------- */
2041   struct frame *f = XFRAME (w->frame);
2042   int x, y, width, height, from_y, to_y, bottom_y;
2044   NSTRACE (ns_scroll_run);
2046   /* begin copy from other terms */
2047   /* Get frame-relative bounding box of the text display area of W,
2048      without mode lines.  Include in this box the left and right
2049      fringe of W.  */
2050   window_box (w, -1, &x, &y, &width, &height);
2052   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2053   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2054   bottom_y = y + height;
2056   if (to_y < from_y)
2057     {
2058       /* Scrolling up.  Make sure we don't copy part of the mode
2059          line at the bottom.  */
2060       if (from_y + run->height > bottom_y)
2061         height = bottom_y - from_y;
2062       else
2063         height = run->height;
2064     }
2065   else
2066     {
2067       /* Scrolling down.  Make sure we don't copy over the mode line.
2068          at the bottom.  */
2069       if (to_y + run->height > bottom_y)
2070         height = bottom_y - to_y;
2071       else
2072         height = run->height;
2073     }
2074   /* end copy from other terms */
2076   if (height == 0)
2077       return;
2079   block_input ();
2081   x_clear_cursor (w);
2083   {
2084     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2085     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2086     NSPoint dstOrigin = NSMakePoint (x, to_y);
2088     ns_focus (f, &dstRect, 1);
2089     NSCopyBits (0, srcRect , dstOrigin);
2090     ns_unfocus (f);
2091   }
2093   unblock_input ();
2097 static void
2098 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2099 /* --------------------------------------------------------------------------
2100     External (RIF): preparatory to fringe update after text was updated
2101    -------------------------------------------------------------------------- */
2103   struct frame *f;
2104   int width, height;
2106   NSTRACE (ns_after_update_window_line);
2108   /* begin copy from other terms */
2109   eassert (w);
2111   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2112     desired_row->redraw_fringe_bitmaps_p = 1;
2114   /* When a window has disappeared, make sure that no rest of
2115      full-width rows stays visible in the internal border.  */
2116   if (windows_or_buffers_changed
2117       && desired_row->full_width_p
2118       && (f = XFRAME (w->frame),
2119           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2120           width != 0)
2121       && (height = desired_row->visible_height,
2122           height > 0))
2123     {
2124       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2126       block_input ();
2127       ns_clear_frame_area (f, 0, y, width, height);
2128       ns_clear_frame_area (f,
2129                            FRAME_PIXEL_WIDTH (f) - width,
2130                            y, width, height);
2131       unblock_input ();
2132     }
2136 static void
2137 ns_shift_glyphs_for_insert (struct frame *f,
2138                            int x, int y, int width, int height,
2139                            int shift_by)
2140 /* --------------------------------------------------------------------------
2141     External (RIF): copy an area horizontally, don't worry about clearing src
2142    -------------------------------------------------------------------------- */
2144   NSRect srcRect = NSMakeRect (x, y, width, height);
2145   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2146   NSPoint dstOrigin = dstRect.origin;
2148   NSTRACE (ns_shift_glyphs_for_insert);
2150   ns_focus (f, &dstRect, 1);
2151   NSCopyBits (0, srcRect, dstOrigin);
2152   ns_unfocus (f);
2157 /* ==========================================================================
2159     Character encoding and metrics
2161    ========================================================================== */
2164 static void
2165 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2166 /* --------------------------------------------------------------------------
2167      External (RIF); compute left/right overhang of whole string and set in s
2168    -------------------------------------------------------------------------- */
2170   struct font *font = s->font;
2172   if (s->char2b)
2173     {
2174       struct font_metrics metrics;
2175       unsigned int codes[2];
2176       codes[0] = *(s->char2b);
2177       codes[1] = *(s->char2b + s->nchars - 1);
2179       font->driver->text_extents (font, codes, 2, &metrics);
2180       s->left_overhang = -metrics.lbearing;
2181       s->right_overhang
2182         = metrics.rbearing > metrics.width
2183         ? metrics.rbearing - metrics.width : 0;
2184     }
2185   else
2186     {
2187       s->left_overhang = 0;
2188       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2189         FONT_HEIGHT (font) * 0.2 : 0;
2190     }
2195 /* ==========================================================================
2197     Fringe and cursor drawing
2199    ========================================================================== */
2202 extern int max_used_fringe_bitmap;
2203 static void
2204 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2205                       struct draw_fringe_bitmap_params *p)
2206 /* --------------------------------------------------------------------------
2207     External (RIF); fringe-related
2208    -------------------------------------------------------------------------- */
2210   struct frame *f = XFRAME (WINDOW_FRAME (w));
2211   struct face *face = p->face;
2212   static EmacsImage **bimgs = NULL;
2213   static int nBimgs = 0;
2215   /* grow bimgs if needed */
2216   if (nBimgs < max_used_fringe_bitmap)
2217     {
2218       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2219       memset (bimgs + nBimgs, 0,
2220               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2221       nBimgs = max_used_fringe_bitmap;
2222     }
2224   /* Must clip because of partially visible lines.  */
2225   ns_clip_to_row (w, row, -1, YES);
2227   if (!p->overlay_p)
2228     {
2229       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2231       /* If the fringe is adjacent to the left (right) scroll bar of a
2232          leftmost (rightmost, respectively) window, then extend its
2233          background to the gap between the fringe and the bar.  */
2234       if ((WINDOW_LEFTMOST_P (w)
2235            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2236           || (WINDOW_RIGHTMOST_P (w)
2237               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2238         {
2239           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2241           if (sb_width > 0)
2242             {
2243               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2244               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2245                                     * FRAME_COLUMN_WIDTH (f));
2247               if (bx < 0)
2248                 {
2249                   /* Bitmap fills the fringe.  */
2250                   if (bar_area_x + bar_area_width == p->x)
2251                     bx = bar_area_x + sb_width;
2252                   else if (p->x + p->wd == bar_area_x)
2253                     bx = bar_area_x;
2254                   if (bx >= 0)
2255                     {
2256                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2258                       nx = bar_area_width - sb_width;
2259                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2260                                                             row->y));
2261                       ny = row->visible_height;
2262                     }
2263                 }
2264               else
2265                 {
2266                   if (bar_area_x + bar_area_width == bx)
2267                     {
2268                       bx = bar_area_x + sb_width;
2269                       nx += bar_area_width - sb_width;
2270                     }
2271                   else if (bx + nx == bar_area_x)
2272                     nx += bar_area_width - sb_width;
2273                 }
2274             }
2275         }
2277       if (bx >= 0 && nx > 0)
2278         {
2279           NSRect r = NSMakeRect (bx, by, nx, ny);
2280           NSRectClip (r);
2281           [ns_lookup_indexed_color (face->background, f) set];
2282           NSRectFill (r);
2283         }
2284     }
2286   if (p->which)
2287     {
2288       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2289       EmacsImage *img = bimgs[p->which - 1];
2291       if (!img)
2292         {
2293           unsigned short *bits = p->bits + p->dh;
2294           int len = p->h;
2295           int i;
2296           unsigned char *cbits = xmalloc (len);
2298           for (i = 0; i < len; i++)
2299             cbits[i] = ~(bits[i] & 0xff);
2300           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2301                                            flip: NO];
2302           bimgs[p->which - 1] = img;
2303           xfree (cbits);
2304         }
2306       NSRectClip (r);
2307       /* Since we composite the bitmap instead of just blitting it, we need
2308          to erase the whole background. */
2309       [ns_lookup_indexed_color(face->background, f) set];
2310       NSRectFill (r);
2311       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2312 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2313       [img drawInRect: r
2314               fromRect: NSZeroRect
2315              operation: NSCompositeSourceOver
2316               fraction: 1.0
2317            respectFlipped: YES
2318                 hints: nil];
2319 #else
2320       {
2321         NSPoint pt = r.origin;
2322         pt.y += p->h;
2323         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2324       }
2325 #endif
2326     }
2327   ns_unfocus (f);
2331 static void
2332 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2333                        int x, int y, enum text_cursor_kinds cursor_type,
2334                        int cursor_width, bool on_p, bool active_p)
2335 /* --------------------------------------------------------------------------
2336      External call (RIF): draw cursor.
2337      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2338    -------------------------------------------------------------------------- */
2340   NSRect r, s;
2341   int fx, fy, h, cursor_height;
2342   struct frame *f = WINDOW_XFRAME (w);
2343   struct glyph *phys_cursor_glyph;
2344   struct glyph *cursor_glyph;
2345   struct face *face;
2346   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2348   /* If cursor is out of bounds, don't draw garbage.  This can happen
2349      in mini-buffer windows when switching between echo area glyphs
2350      and mini-buffer.  */
2352   NSTRACE (dumpcursor);
2354   if (!on_p)
2355     return;
2357   w->phys_cursor_type = cursor_type;
2358   w->phys_cursor_on_p = on_p;
2360   if (cursor_type == NO_CURSOR)
2361     {
2362       w->phys_cursor_width = 0;
2363       return;
2364     }
2366   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2367     {
2368       if (glyph_row->exact_window_width_line_p
2369           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2370         {
2371           glyph_row->cursor_in_fringe_p = 1;
2372           draw_fringe_bitmap (w, glyph_row, 0);
2373         }
2374       return;
2375     }
2377   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2378      (other terminals do it the other way round).  We must set
2379      w->phys_cursor_width to the cursor width.  For bar cursors, that
2380      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2381   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2383   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2384      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2385   if (cursor_type == BAR_CURSOR)
2386     {
2387       if (cursor_width < 1)
2388         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2389       w->phys_cursor_width = cursor_width;
2390     }
2391   /* If we have an HBAR, "cursor_width" MAY specify height. */
2392   else if (cursor_type == HBAR_CURSOR)
2393     {
2394       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2395       fy += h - cursor_height;
2396       h = cursor_height;
2397     }
2399   r.origin.x = fx, r.origin.y = fy;
2400   r.size.height = h;
2401   r.size.width = w->phys_cursor_width;
2403   /* TODO: only needed in rare cases with last-resort font in HELLO..
2404      should we do this more efficiently? */
2405   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2408   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2409   if (face && NS_FACE_BACKGROUND (face)
2410       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2411     {
2412       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2413       hollow_color = FRAME_CURSOR_COLOR (f);
2414     }
2415   else
2416     [FRAME_CURSOR_COLOR (f) set];
2418 #ifdef NS_IMPL_COCOA
2419   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2420            atomic.  Cleaner ways of doing this should be investigated.
2421            One way would be to set a global variable DRAWING_CURSOR
2422            when making the call to draw_phys..(), don't focus in that
2423            case, then move the ns_unfocus() here after that call. */
2424   NSDisableScreenUpdates ();
2425 #endif
2427   switch (cursor_type)
2428     {
2429     case NO_CURSOR:
2430       break;
2431     case FILLED_BOX_CURSOR:
2432       NSRectFill (r);
2433       break;
2434     case HOLLOW_BOX_CURSOR:
2435       NSRectFill (r);
2436       [hollow_color set];
2437       NSRectFill (NSInsetRect (r, 1, 1));
2438       [FRAME_CURSOR_COLOR (f) set];
2439       break;
2440     case HBAR_CURSOR:
2441       NSRectFill (r);
2442       break;
2443     case BAR_CURSOR:
2444       s = r;
2445       /* If the character under cursor is R2L, draw the bar cursor
2446          on the right of its glyph, rather than on the left.  */
2447       cursor_glyph = get_phys_cursor_glyph (w);
2448       if ((cursor_glyph->resolved_level & 1) != 0)
2449         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2451       NSRectFill (s);
2452       break;
2453     }
2454   ns_unfocus (f);
2456   /* draw the character under the cursor */
2457   if (cursor_type != NO_CURSOR)
2458     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2460 #ifdef NS_IMPL_COCOA
2461   NSEnableScreenUpdates ();
2462 #endif
2467 static void
2468 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2469 /* --------------------------------------------------------------------------
2470      External (RIF): Draw a vertical line.
2471    -------------------------------------------------------------------------- */
2473   struct frame *f = XFRAME (WINDOW_FRAME (w));
2474   struct face *face;
2475   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2477   NSTRACE (ns_draw_vertical_window_border);
2479   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2480   if (face)
2481       [ns_lookup_indexed_color(face->foreground, f) set];
2483   ns_focus (f, &r, 1);
2484   NSRectFill(r);
2485   ns_unfocus (f);
2489 void
2490 show_hourglass (struct atimer *timer)
2492   if (hourglass_shown_p)
2493     return;
2495   block_input ();
2497   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2499   hourglass_shown_p = 1;
2500   unblock_input ();
2504 void
2505 hide_hourglass (void)
2507   if (!hourglass_shown_p)
2508     return;
2510   block_input ();
2512   /* TODO: remove NSProgressIndicator from all frames */
2514   hourglass_shown_p = 0;
2515   unblock_input ();
2520 /* ==========================================================================
2522     Glyph drawing operations
2524    ========================================================================== */
2526 static int
2527 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2528 /* --------------------------------------------------------------------------
2529     Wrapper utility to account for internal border width on full-width lines,
2530     and allow top full-width rows to hit the frame top.  nr should be pointer
2531     to two successive NSRects.  Number of rects actually used is returned.
2532    -------------------------------------------------------------------------- */
2534   int n = get_glyph_string_clip_rects (s, nr, 2);
2535   return n;
2538 /* --------------------------------------------------------------------
2539    Draw a wavy line under glyph string s. The wave fills wave_height
2540    pixels from y.
2542                     x          wave_length = 2
2543                                  --
2544                 y    *   *   *   *   *
2545                      |* * * * * * * * *
2546     wave_height = 3  | *   *   *   *
2547   --------------------------------------------------------------------- */
2549 static void
2550 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2552   int wave_height = 3, wave_length = 2;
2553   int y, dx, dy, odd, xmax;
2554   NSPoint a, b;
2555   NSRect waveClip;
2557   dx = wave_length;
2558   dy = wave_height - 1;
2559   y =  s->ybase - wave_height + 3;
2560   xmax = x + width;
2562   /* Find and set clipping rectangle */
2563   waveClip = NSMakeRect (x, y, width, wave_height);
2564   [[NSGraphicsContext currentContext] saveGraphicsState];
2565   NSRectClip (waveClip);
2567   /* Draw the waves */
2568   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2569   b.x = a.x + dx;
2570   odd = (int)(a.x/dx) % 2;
2571   a.y = b.y = y + 0.5;
2573   if (odd)
2574     a.y += dy;
2575   else
2576     b.y += dy;
2578   while (a.x <= xmax)
2579     {
2580       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2581       a.x = b.x, a.y = b.y;
2582       b.x += dx, b.y = y + 0.5 + odd*dy;
2583       odd = !odd;
2584     }
2586   /* Restore previous clipping rectangle(s) */
2587   [[NSGraphicsContext currentContext] restoreGraphicsState];
2592 void
2593 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2594                          NSColor *defaultCol, CGFloat width, CGFloat x)
2595 /* --------------------------------------------------------------------------
2596    Draw underline, overline, and strike-through on glyph string s.
2597    -------------------------------------------------------------------------- */
2599   if (s->for_overlaps)
2600     return;
2602   /* Do underline. */
2603   if (face->underline_p)
2604     {
2605       if (s->face->underline_type == FACE_UNDER_WAVE)
2606         {
2607           if (face->underline_defaulted_p)
2608             [defaultCol set];
2609           else
2610             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2612           ns_draw_underwave (s, width, x);
2613         }
2614       else if (s->face->underline_type == FACE_UNDER_LINE)
2615         {
2617           NSRect r;
2618           unsigned long thickness, position;
2620           /* If the prev was underlined, match its appearance. */
2621           if (s->prev && s->prev->face->underline_p
2622               && s->prev->face->underline_type == FACE_UNDER_LINE
2623               && s->prev->underline_thickness > 0)
2624             {
2625               thickness = s->prev->underline_thickness;
2626               position = s->prev->underline_position;
2627             }
2628           else
2629             {
2630               struct font *font;
2631               unsigned long descent;
2633               font=s->font;
2634               descent = s->y + s->height - s->ybase;
2636               /* Use underline thickness of font, defaulting to 1. */
2637               thickness = (font && font->underline_thickness > 0)
2638                 ? font->underline_thickness : 1;
2640               /* Determine the offset of underlining from the baseline. */
2641               if (x_underline_at_descent_line)
2642                 position = descent - thickness;
2643               else if (x_use_underline_position_properties
2644                        && font && font->underline_position >= 0)
2645                 position = font->underline_position;
2646               else if (font)
2647                 position = lround (font->descent / 2);
2648               else
2649                 position = underline_minimum_offset;
2651               position = max (position, underline_minimum_offset);
2653               /* Ensure underlining is not cropped. */
2654               if (descent <= position)
2655                 {
2656                   position = descent - 1;
2657                   thickness = 1;
2658                 }
2659               else if (descent < position + thickness)
2660                 thickness = 1;
2661             }
2663           s->underline_thickness = thickness;
2664           s->underline_position = position;
2666           r = NSMakeRect (x, s->ybase + position, width, thickness);
2668           if (face->underline_defaulted_p)
2669             [defaultCol set];
2670           else
2671             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2672           NSRectFill (r);
2673         }
2674     }
2675   /* Do overline. We follow other terms in using a thickness of 1
2676      and ignoring overline_margin. */
2677   if (face->overline_p)
2678     {
2679       NSRect r;
2680       r = NSMakeRect (x, s->y, width, 1);
2682       if (face->overline_color_defaulted_p)
2683         [defaultCol set];
2684       else
2685         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2686       NSRectFill (r);
2687     }
2689   /* Do strike-through.  We follow other terms for thickness and
2690      vertical position.*/
2691   if (face->strike_through_p)
2692     {
2693       NSRect r;
2694       unsigned long dy;
2696       dy = lrint ((s->height - 1) / 2);
2697       r = NSMakeRect (x, s->y + dy, width, 1);
2699       if (face->strike_through_color_defaulted_p)
2700         [defaultCol set];
2701       else
2702         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2703       NSRectFill (r);
2704     }
2707 static void
2708 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2709              char left_p, char right_p)
2710 /* --------------------------------------------------------------------------
2711     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2712     Note we can't just use an NSDrawRect command, because of the possibility
2713     of some sides not being drawn, and because the rect will be filled.
2714    -------------------------------------------------------------------------- */
2716   NSRect s = r;
2717   [col set];
2719   /* top, bottom */
2720   s.size.height = thickness;
2721   NSRectFill (s);
2722   s.origin.y += r.size.height - thickness;
2723   NSRectFill (s);
2725   s.size.height = r.size.height;
2726   s.origin.y = r.origin.y;
2728   /* left, right (optional) */
2729   s.size.width = thickness;
2730   if (left_p)
2731     NSRectFill (s);
2732   if (right_p)
2733     {
2734       s.origin.x += r.size.width - thickness;
2735       NSRectFill (s);
2736     }
2740 static void
2741 ns_draw_relief (NSRect r, int thickness, char raised_p,
2742                char top_p, char bottom_p, char left_p, char right_p,
2743                struct glyph_string *s)
2744 /* --------------------------------------------------------------------------
2745     Draw a relief rect inside r, optionally leaving some sides open.
2746     Note we can't just use an NSDrawBezel command, because of the possibility
2747     of some sides not being drawn, and because the rect will be filled.
2748    -------------------------------------------------------------------------- */
2750   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2751   NSColor *newBaseCol = nil;
2752   NSRect sr = r;
2754   NSTRACE (ns_draw_relief);
2756   /* set up colors */
2758   if (s->face->use_box_color_for_shadows_p)
2759     {
2760       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2761     }
2762 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2763            && s->img->pixmap
2764            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2765        {
2766          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2767        } */
2768   else
2769     {
2770       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2771     }
2773   if (newBaseCol == nil)
2774     newBaseCol = [NSColor grayColor];
2776   if (newBaseCol != baseCol)  /* TODO: better check */
2777     {
2778       [baseCol release];
2779       baseCol = [newBaseCol retain];
2780       [lightCol release];
2781       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2782       [darkCol release];
2783       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2784     }
2786   [(raised_p ? lightCol : darkCol) set];
2788   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2790   /* top */
2791   sr.size.height = thickness;
2792   if (top_p) NSRectFill (sr);
2794   /* left */
2795   sr.size.height = r.size.height;
2796   sr.size.width = thickness;
2797   if (left_p) NSRectFill (sr);
2799   [(raised_p ? darkCol : lightCol) set];
2801   /* bottom */
2802   sr.size.width = r.size.width;
2803   sr.size.height = thickness;
2804   sr.origin.y += r.size.height - thickness;
2805   if (bottom_p) NSRectFill (sr);
2807   /* right */
2808   sr.size.height = r.size.height;
2809   sr.origin.y = r.origin.y;
2810   sr.size.width = thickness;
2811   sr.origin.x += r.size.width - thickness;
2812   if (right_p) NSRectFill (sr);
2816 static void
2817 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2818 /* --------------------------------------------------------------------------
2819       Function modeled after x_draw_glyph_string_box ().
2820       Sets up parameters for drawing.
2821    -------------------------------------------------------------------------- */
2823   int right_x, last_x;
2824   char left_p, right_p;
2825   struct glyph *last_glyph;
2826   NSRect r;
2827   int thickness;
2828   struct face *face;
2830   if (s->hl == DRAW_MOUSE_FACE)
2831     {
2832       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2833       if (!face)
2834         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2835     }
2836   else
2837     face = s->face;
2839   thickness = face->box_line_width;
2841   NSTRACE (ns_dumpglyphs_box_or_relief);
2843   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2844             ? WINDOW_RIGHT_EDGE_X (s->w)
2845             : window_box_right (s->w, s->area));
2846   last_glyph = (s->cmp || s->img
2847                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2849   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2850               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2852   left_p = (s->first_glyph->left_box_line_p
2853             || (s->hl == DRAW_MOUSE_FACE
2854                 && (s->prev == NULL || s->prev->hl != s->hl)));
2855   right_p = (last_glyph->right_box_line_p
2856              || (s->hl == DRAW_MOUSE_FACE
2857                  && (s->next == NULL || s->next->hl != s->hl)));
2859   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2861   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2862   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2863     {
2864       ns_draw_box (r, abs (thickness),
2865                    ns_lookup_indexed_color (face->box_color, s->f),
2866                   left_p, right_p);
2867     }
2868   else
2869     {
2870       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2871                      1, 1, left_p, right_p, s);
2872     }
2876 static void
2877 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2878 /* --------------------------------------------------------------------------
2879       Modeled after x_draw_glyph_string_background, which draws BG in
2880       certain cases.  Others are left to the text rendering routine.
2881    -------------------------------------------------------------------------- */
2883   NSTRACE (ns_maybe_dumpglyphs_background);
2885   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2886     {
2887       int box_line_width = max (s->face->box_line_width, 0);
2888       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2889           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2890         {
2891           struct face *face;
2892           if (s->hl == DRAW_MOUSE_FACE)
2893             {
2894               face = FACE_FROM_ID (s->f,
2895                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2896               if (!face)
2897                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2898             }
2899           else
2900             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2901           if (!face->stipple)
2902             [(NS_FACE_BACKGROUND (face) != 0
2903               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2904               : FRAME_BACKGROUND_COLOR (s->f)) set];
2905           else
2906             {
2907               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2908               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2909             }
2911           if (s->hl != DRAW_CURSOR)
2912             {
2913               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2914                                     s->background_width,
2915                                     s->height-2*box_line_width);
2916               NSRectFill (r);
2917             }
2919           s->background_filled_p = 1;
2920         }
2921     }
2925 static void
2926 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2927 /* --------------------------------------------------------------------------
2928       Renders an image and associated borders.
2929    -------------------------------------------------------------------------- */
2931   EmacsImage *img = s->img->pixmap;
2932   int box_line_vwidth = max (s->face->box_line_width, 0);
2933   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2934   int bg_x, bg_y, bg_height;
2935   int th;
2936   char raised_p;
2937   NSRect br;
2938   struct face *face;
2939   NSColor *tdCol;
2941   NSTRACE (ns_dumpglyphs_image);
2943   if (s->face->box != FACE_NO_BOX
2944       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2945     x += abs (s->face->box_line_width);
2947   bg_x = x;
2948   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2949   bg_height = s->height;
2950   /* other terms have this, but was causing problems w/tabbar mode */
2951   /* - 2 * box_line_vwidth; */
2953   if (s->slice.x == 0) x += s->img->hmargin;
2954   if (s->slice.y == 0) y += s->img->vmargin;
2956   /* Draw BG: if we need larger area than image itself cleared, do that,
2957      otherwise, since we composite the image under NS (instead of mucking
2958      with its background color), we must clear just the image area. */
2959   if (s->hl == DRAW_MOUSE_FACE)
2960     {
2961       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2962       if (!face)
2963        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2964     }
2965   else
2966     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2968   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2970   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2971       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2972     {
2973       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2974       s->background_filled_p = 1;
2975     }
2976   else
2977     {
2978       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2979     }
2981   NSRectFill (br);
2983   /* Draw the image.. do we need to draw placeholder if img ==nil? */
2984   if (img != nil)
2985     {
2986 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2987       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
2988       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
2989                               s->slice.width, s->slice.height);
2990       [img drawInRect: dr
2991              fromRect: ir
2992              operation: NSCompositeSourceOver
2993               fraction: 1.0
2994            respectFlipped: YES
2995                 hints: nil];
2996 #else
2997       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
2998                   operation: NSCompositeSourceOver];
2999 #endif
3000     }
3002   if (s->hl == DRAW_CURSOR)
3003     {
3004     [FRAME_CURSOR_COLOR (s->f) set];
3005     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3006       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3007     else
3008       /* Currently on NS img->mask is always 0. Since
3009          get_window_cursor_type specifies a hollow box cursor when on
3010          a non-masked image we never reach this clause. But we put it
3011          in in anticipation of better support for image masks on
3012          NS. */
3013       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3014     }
3015   else
3016     {
3017       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3018     }
3020   /* Draw underline, overline, strike-through. */
3021   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3023   /* Draw relief, if requested */
3024   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3025     {
3026       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3027         {
3028           th = tool_bar_button_relief >= 0 ?
3029             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3030           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3031         }
3032       else
3033         {
3034           th = abs (s->img->relief);
3035           raised_p = (s->img->relief > 0);
3036         }
3038       r.origin.x = x - th;
3039       r.origin.y = y - th;
3040       r.size.width = s->slice.width + 2*th-1;
3041       r.size.height = s->slice.height + 2*th-1;
3042       ns_draw_relief (r, th, raised_p,
3043                       s->slice.y == 0,
3044                       s->slice.y + s->slice.height == s->img->height,
3045                       s->slice.x == 0,
3046                       s->slice.x + s->slice.width == s->img->width, s);
3047     }
3049   /* If there is no mask, the background won't be seen,
3050      so draw a rectangle on the image for the cursor.
3051      Do this for all images, getting transparency right is not reliable.  */
3052   if (s->hl == DRAW_CURSOR)
3053     {
3054       int thickness = abs (s->img->relief);
3055       if (thickness == 0) thickness = 1;
3056       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3057     }
3061 static void
3062 ns_dumpglyphs_stretch (struct glyph_string *s)
3064   NSRect r[2];
3065   int n, i;
3066   struct face *face;
3067   NSColor *fgCol, *bgCol;
3069   if (!s->background_filled_p)
3070     {
3071       n = ns_get_glyph_string_clip_rect (s, r);
3072       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3074       ns_focus (s->f, r, n);
3076       if (s->hl == DRAW_MOUSE_FACE)
3077        {
3078          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3079          if (!face)
3080            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3081        }
3082       else
3083        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3085       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3086       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3088       for (i = 0; i < n; ++i)
3089         {
3090           if (!s->row->full_width_p)
3091             {
3092               int overrun, leftoverrun;
3094               /* truncate to avoid overwriting fringe and/or scrollbar */
3095               overrun = max (0, (s->x + s->background_width)
3096                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3097                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3098               r[i].size.width -= overrun;
3100               /* truncate to avoid overwriting to left of the window box */
3101               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3102                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3104               if (leftoverrun > 0)
3105                 {
3106                   r[i].origin.x += leftoverrun;
3107                   r[i].size.width -= leftoverrun;
3108                 }
3110               /* XXX: Try to work between problem where a stretch glyph on
3111                  a partially-visible bottom row will clear part of the
3112                  modeline, and another where list-buffers headers and similar
3113                  rows erroneously have visible_height set to 0.  Not sure
3114                  where this is coming from as other terms seem not to show. */
3115               r[i].size.height = min (s->height, s->row->visible_height);
3116             }
3118           [bgCol set];
3120           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3121              overwriting cursor (usually when cursor on a tab) */
3122           if (s->hl == DRAW_CURSOR)
3123             {
3124               CGFloat x, width;
3126               x = r[i].origin.x;
3127               width = s->w->phys_cursor_width;
3128               r[i].size.width -= width;
3129               r[i].origin.x += width;
3131               NSRectFill (r[i]);
3133               /* Draw overlining, etc. on the cursor. */
3134               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3135                 ns_draw_text_decoration (s, face, bgCol, width, x);
3136               else
3137                 ns_draw_text_decoration (s, face, fgCol, width, x);
3138             }
3139           else
3140             {
3141               NSRectFill (r[i]);
3142             }
3144           /* Draw overlining, etc. on the stretch glyph (or the part
3145              of the stretch glyph after the cursor). */
3146           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3147                                    r[i].origin.x);
3148         }
3149       ns_unfocus (s->f);
3150       s->background_filled_p = 1;
3151     }
3155 static void
3156 ns_draw_glyph_string (struct glyph_string *s)
3157 /* --------------------------------------------------------------------------
3158       External (RIF): Main draw-text call.
3159    -------------------------------------------------------------------------- */
3161   /* TODO (optimize): focus for box and contents draw */
3162   NSRect r[2];
3163   int n;
3164   char box_drawn_p = 0;
3166   NSTRACE (ns_draw_glyph_string);
3168   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3169     {
3170       int width;
3171       struct glyph_string *next;
3173       for (width = 0, next = s->next;
3174            next && width < s->right_overhang;
3175            width += next->width, next = next->next)
3176         if (next->first_glyph->type != IMAGE_GLYPH)
3177           {
3178             if (next->first_glyph->type != STRETCH_GLYPH)
3179               {
3180                 n = ns_get_glyph_string_clip_rect (s->next, r);
3181                 ns_focus (s->f, r, n);
3182                 ns_maybe_dumpglyphs_background (s->next, 1);
3183                 ns_unfocus (s->f);
3184               }
3185             else
3186               {
3187                 ns_dumpglyphs_stretch (s->next);
3188               }
3189             next->num_clips = 0;
3190           }
3191     }
3193   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3194         && (s->first_glyph->type == CHAR_GLYPH
3195             || s->first_glyph->type == COMPOSITE_GLYPH))
3196     {
3197       n = ns_get_glyph_string_clip_rect (s, r);
3198       ns_focus (s->f, r, n);
3199       ns_maybe_dumpglyphs_background (s, 1);
3200       ns_dumpglyphs_box_or_relief (s);
3201       ns_unfocus (s->f);
3202       box_drawn_p = 1;
3203     }
3205   switch (s->first_glyph->type)
3206     {
3208     case IMAGE_GLYPH:
3209       n = ns_get_glyph_string_clip_rect (s, r);
3210       ns_focus (s->f, r, n);
3211       ns_dumpglyphs_image (s, r[0]);
3212       ns_unfocus (s->f);
3213       break;
3215     case STRETCH_GLYPH:
3216       ns_dumpglyphs_stretch (s);
3217       break;
3219     case CHAR_GLYPH:
3220     case COMPOSITE_GLYPH:
3221       n = ns_get_glyph_string_clip_rect (s, r);
3222       ns_focus (s->f, r, n);
3224       if (s->for_overlaps || (s->cmp_from > 0
3225                               && ! s->first_glyph->u.cmp.automatic))
3226         s->background_filled_p = 1;
3227       else
3228         ns_maybe_dumpglyphs_background
3229           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3231       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3232                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3233                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3234                       NS_DUMPGLYPH_NORMAL));
3235       ns_tmp_font = (struct nsfont_info *)s->face->font;
3236       if (ns_tmp_font == NULL)
3237           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3239       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3240         {
3241           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3242           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3243           NS_FACE_FOREGROUND (s->face) = tmp;
3244         }
3246       ns_tmp_font->font.driver->draw
3247         (s, 0, s->nchars, s->x, s->y,
3248          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3249          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3251       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3252         {
3253           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3254           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3255           NS_FACE_FOREGROUND (s->face) = tmp;
3256         }
3258       ns_unfocus (s->f);
3259       break;
3261     case GLYPHLESS_GLYPH:
3262       n = ns_get_glyph_string_clip_rect (s, r);
3263       ns_focus (s->f, r, n);
3265       if (s->for_overlaps || (s->cmp_from > 0
3266                               && ! s->first_glyph->u.cmp.automatic))
3267         s->background_filled_p = 1;
3268       else
3269         ns_maybe_dumpglyphs_background
3270           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3271       /* ... */
3272       /* Not yet implemented.  */
3273       /* ... */
3274       ns_unfocus (s->f);
3275       break;
3277     default:
3278       emacs_abort ();
3279     }
3281   /* Draw box if not done already. */
3282   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3283     {
3284       n = ns_get_glyph_string_clip_rect (s, r);
3285       ns_focus (s->f, r, n);
3286       ns_dumpglyphs_box_or_relief (s);
3287       ns_unfocus (s->f);
3288     }
3290   s->num_clips = 0;
3295 /* ==========================================================================
3297     Event loop
3299    ========================================================================== */
3302 static void
3303 ns_send_appdefined (int value)
3304 /* --------------------------------------------------------------------------
3305     Internal: post an appdefined event which EmacsApp-sendEvent will
3306               recognize and take as a command to halt the event loop.
3307    -------------------------------------------------------------------------- */
3309   /*NSTRACE (ns_send_appdefined); */
3311 #ifdef NS_IMPL_GNUSTEP
3312   // GNUStep needs postEvent to happen on the main thread.
3313   if (! [[NSThread currentThread] isMainThread])
3314     {
3315       EmacsApp *app = (EmacsApp *)NSApp;
3316       app->nextappdefined = value;
3317       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3318                             withObject:nil
3319                          waitUntilDone:YES];
3320       return;
3321     }
3322 #endif
3324   /* Only post this event if we haven't already posted one.  This will end
3325        the [NXApp run] main loop after having processed all events queued at
3326        this moment.  */
3327   if (send_appdefined)
3328     {
3329       NSEvent *nxev;
3331       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3332       send_appdefined = NO;
3334       /* Don't need wakeup timer any more */
3335       if (timed_entry)
3336         {
3337           [timed_entry invalidate];
3338           [timed_entry release];
3339           timed_entry = nil;
3340         }
3342       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3343                                 location: NSMakePoint (0, 0)
3344                            modifierFlags: 0
3345                                timestamp: 0
3346                             windowNumber: [[NSApp mainWindow] windowNumber]
3347                                  context: [NSApp context]
3348                                  subtype: 0
3349                                    data1: value
3350                                    data2: 0];
3352       /* Post an application defined event on the event queue.  When this is
3353          received the [NXApp run] will return, thus having processed all
3354          events which are currently queued.  */
3355       [NSApp postEvent: nxev atStart: NO];
3356     }
3359 #ifdef HAVE_NATIVE_FS
3360 static void
3361 check_native_fs ()
3363   Lisp_Object frame, tail;
3365   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3366     return;
3368   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3370   /* Clear the mouse-moved flag for every frame on this display.  */
3371   FOR_EACH_FRAME (tail, frame)
3372     {
3373       struct frame *f = XFRAME (frame);
3374       if (FRAME_NS_P (f))
3375         {
3376           EmacsView *view = FRAME_NS_VIEW (f);
3377           [view updateCollectionBehaviour];
3378         }
3379     }
3381 #endif
3383 /* GNUStep and OSX <= 10.4 does not have cancelTracking.  */
3384 #if defined (NS_IMPL_COCOA) && \
3385   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
3386 /* Check if menu open should be cancelled or continued as normal.  */
3387 void
3388 ns_check_menu_open (NSMenu *menu)
3390   /* Click in menu bar? */
3391   NSArray *a = [[NSApp mainMenu] itemArray];
3392   int i;
3393   BOOL found = NO;
3395   if (menu == nil) // Menu tracking ended.
3396     {
3397       if (menu_will_open_state == MENU_OPENING)
3398         menu_will_open_state = MENU_NONE;
3399       return;
3400     }
3402   for (i = 0; ! found && i < [a count]; i++)
3403     found = menu == [[a objectAtIndex:i] submenu];
3404   if (found)
3405     {
3406       if (menu_will_open_state == MENU_NONE && emacs_event)
3407         {
3408           NSEvent *theEvent = [NSApp currentEvent];
3409           struct frame *emacsframe = SELECTED_FRAME ();
3411           [menu cancelTracking];
3412           menu_will_open_state = MENU_PENDING;
3413           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3414           EV_TRAILER (theEvent);
3416           CGEventRef ourEvent = CGEventCreate (NULL);
3417           menu_mouse_point = CGEventGetLocation (ourEvent);
3418           CFRelease (ourEvent);
3419         }
3420       else if (menu_will_open_state == MENU_OPENING)
3421         {
3422           menu_will_open_state = MENU_NONE;
3423         }
3424     }
3427 /* Redo saved menu click if state is MENU_PENDING.  */
3428 void
3429 ns_check_pending_open_menu ()
3431   if (menu_will_open_state == MENU_PENDING)
3432     {
3433       CGEventSourceRef source
3434         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3436       CGEventRef event = CGEventCreateMouseEvent (source,
3437                                                   kCGEventLeftMouseDown,
3438                                                   menu_mouse_point,
3439                                                   kCGMouseButtonLeft);
3440       CGEventSetType (event, kCGEventLeftMouseDown);
3441       CGEventPost (kCGHIDEventTap, event);
3442       CFRelease (event);
3443       CFRelease (source);
3445       menu_will_open_state = MENU_OPENING;
3446     }
3448 #endif /* NS_IMPL_COCOA) && >= MAC_OS_X_VERSION_10_5 */
3450 static int
3451 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3452 /* --------------------------------------------------------------------------
3453      External (hook): Post an event to ourself and keep reading events until
3454      we read it back again.  In effect process all events which were waiting.
3455      From 21+ we have to manage the event buffer ourselves.
3456    -------------------------------------------------------------------------- */
3458   struct input_event ev;
3459   int nevents;
3461 /* NSTRACE (ns_read_socket); */
3463 #ifdef HAVE_NATIVE_FS
3464   check_native_fs ();
3465 #endif
3467   if ([NSApp modalWindow] != nil)
3468     return -1;
3470   if (hold_event_q.nr > 0)
3471     {
3472       int i;
3473       for (i = 0; i < hold_event_q.nr; ++i)
3474         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3475       hold_event_q.nr = 0;
3476       return i;
3477     }
3479   block_input ();
3480   n_emacs_events_pending = 0;
3481   EVENT_INIT (ev);
3482   emacs_event = &ev;
3483   q_event_ptr = hold_quit;
3485   /* we manage autorelease pools by allocate/reallocate each time around
3486      the loop; strict nesting is occasionally violated but seems not to
3487      matter.. earlier methods using full nesting caused major memory leaks */
3488   [outerpool release];
3489   outerpool = [[NSAutoreleasePool alloc] init];
3491   /* If have pending open-file requests, attend to the next one of those. */
3492   if (ns_pending_files && [ns_pending_files count] != 0
3493       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3494     {
3495       [ns_pending_files removeObjectAtIndex: 0];
3496     }
3497   /* Deal with pending service requests. */
3498   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3499     && [(EmacsApp *)
3500          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3501                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3502     {
3503       [ns_pending_service_names removeObjectAtIndex: 0];
3504       [ns_pending_service_args removeObjectAtIndex: 0];
3505     }
3506   else
3507     {
3508       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3509          to ourself, otherwise [NXApp run] will never exit.  */
3510       send_appdefined = YES;
3511       ns_send_appdefined (-1);
3513       if (++apploopnr != 1)
3514         {
3515           emacs_abort ();
3516         }
3517       [NSApp run];
3518       --apploopnr;
3519     }
3521   nevents = n_emacs_events_pending;
3522   n_emacs_events_pending = 0;
3523   emacs_event = q_event_ptr = NULL;
3524   unblock_input ();
3526   return nevents;
3531 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3532            fd_set *exceptfds, struct timespec const *timeout,
3533            sigset_t const *sigmask)
3534 /* --------------------------------------------------------------------------
3535      Replacement for select, checking for events
3536    -------------------------------------------------------------------------- */
3538   int result;
3539   int t, k, nr = 0;
3540   struct input_event event;
3541   char c;
3543 /*  NSTRACE (ns_select); */
3545 #ifdef HAVE_NATIVE_FS
3546   check_native_fs ();
3547 #endif
3549   if (hold_event_q.nr > 0)
3550     {
3551       /* We already have events pending. */
3552       raise (SIGIO);
3553       errno = EINTR;
3554       return -1;
3555     }
3557   for (k = 0; k < nfds+1; k++)
3558     {
3559       if (readfds && FD_ISSET(k, readfds)) ++nr;
3560       if (writefds && FD_ISSET(k, writefds)) ++nr;
3561     }
3563   if (NSApp == nil
3564       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3565     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3567   [outerpool release];
3568   outerpool = [[NSAutoreleasePool alloc] init];
3571   send_appdefined = YES;
3572   if (nr > 0)
3573     {
3574       pthread_mutex_lock (&select_mutex);
3575       select_nfds = nfds;
3576       select_valid = 0;
3577       if (readfds)
3578         {
3579           select_readfds = *readfds;
3580           select_valid += SELECT_HAVE_READ;
3581         }
3582       if (writefds)
3583         {
3584           select_writefds = *writefds;
3585           select_valid += SELECT_HAVE_WRITE;
3586         }
3588       if (timeout)
3589         {
3590           select_timeout = *timeout;
3591           select_valid += SELECT_HAVE_TMO;
3592         }
3594       pthread_mutex_unlock (&select_mutex);
3596       /* Inform fd_handler that select should be called */
3597       c = 'g';
3598       emacs_write_sig (selfds[1], &c, 1);
3599     }
3600   else if (nr == 0 && timeout)
3601     {
3602       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3603       double time = timespectod (*timeout);
3604       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3605                                                       target: NSApp
3606                                                     selector:
3607                                   @selector (timeout_handler:)
3608                                                     userInfo: 0
3609                                                      repeats: NO]
3610                       retain];
3611     }
3612   else /* No timeout and no file descriptors, can this happen?  */
3613     {
3614       /* Send appdefined so we exit from the loop */
3615       ns_send_appdefined (-1);
3616     }
3618   EVENT_INIT (event);
3619   block_input ();
3620   emacs_event = &event;
3621   if (++apploopnr != 1)
3622     {
3623       emacs_abort ();
3624     }
3625   [NSApp run];
3626   --apploopnr;
3627   emacs_event = NULL;
3628   if (nr > 0 && readfds)
3629     {
3630       c = 's';
3631       emacs_write_sig (selfds[1], &c, 1);
3632     }
3633   unblock_input ();
3635   t = last_appdefined_event_data;
3637   if (t != NO_APPDEFINED_DATA)
3638     {
3639       last_appdefined_event_data = NO_APPDEFINED_DATA;
3641       if (t == -2)
3642         {
3643           /* The NX_APPDEFINED event we received was a timeout. */
3644           result = 0;
3645         }
3646       else if (t == -1)
3647         {
3648           /* The NX_APPDEFINED event we received was the result of
3649              at least one real input event arriving.  */
3650           errno = EINTR;
3651           result = -1;
3652         }
3653       else
3654         {
3655           /* Received back from select () in fd_handler; copy the results */
3656           pthread_mutex_lock (&select_mutex);
3657           if (readfds) *readfds = select_readfds;
3658           if (writefds) *writefds = select_writefds;
3659           pthread_mutex_unlock (&select_mutex);
3660           result = t;
3661         }
3662     }
3663   else
3664     {
3665       errno = EINTR;
3666       result = -1;
3667     }
3669   return result;
3674 /* ==========================================================================
3676     Scrollbar handling
3678    ========================================================================== */
3681 static void
3682 ns_set_vertical_scroll_bar (struct window *window,
3683                            int portion, int whole, int position)
3684 /* --------------------------------------------------------------------------
3685       External (hook): Update or add scrollbar
3686    -------------------------------------------------------------------------- */
3688   Lisp_Object win;
3689   NSRect r, v;
3690   struct frame *f = XFRAME (WINDOW_FRAME (window));
3691   EmacsView *view = FRAME_NS_VIEW (f);
3692   int window_y, window_height;
3693   int top, left, height, width, sb_width, sb_left;
3694   EmacsScroller *bar;
3695   BOOL fringe_extended_p;
3697   /* optimization; display engine sends WAY too many of these.. */
3698   if (!NILP (window->vertical_scroll_bar))
3699     {
3700       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3701       if ([bar checkSamePosition: position portion: portion whole: whole])
3702         {
3703           if (view->scrollbarsNeedingUpdate == 0)
3704             {
3705               if (!windows_or_buffers_changed)
3706                   return;
3707             }
3708           else
3709             view->scrollbarsNeedingUpdate--;
3710         }
3711     }
3713   NSTRACE (ns_set_vertical_scroll_bar);
3715   /* Get dimensions.  */
3716   window_box (window, -1, 0, &window_y, 0, &window_height);
3717   top = window_y;
3718   height = window_height;
3719   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3720   left = WINDOW_SCROLL_BAR_AREA_X (window);
3722   /* allow for displaying a skinnier scrollbar than char area allotted */
3723   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3724     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3725   sb_left = left;
3727   r = NSMakeRect (sb_left, top, sb_width, height);
3728   /* the parent view is flipped, so we need to flip y value */
3729   v = [view frame];
3730   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3732   fringe_extended_p = WINDOW_FRINGE_EXTENDED_P (window);
3734   XSETWINDOW (win, window);
3735   block_input ();
3737   /* we want at least 5 lines to display a scrollbar */
3738   if (WINDOW_TOTAL_LINES (window) < 5)
3739     {
3740       if (!NILP (window->vertical_scroll_bar))
3741         {
3742           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3743           [bar removeFromSuperview];
3744           wset_vertical_scroll_bar (window, Qnil);
3745         }
3746       ns_clear_frame_area (f, sb_left, top, width, height);
3747       unblock_input ();
3748       return;
3749     }
3751   if (NILP (window->vertical_scroll_bar))
3752     {
3753       if (width > 0 && height > 0)
3754         {
3755           if (fringe_extended_p)
3756             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3757           else
3758             ns_clear_frame_area (f, left, top, width, height);
3759         }
3761       bar = [[EmacsScroller alloc] initFrame: r window: win];
3762       wset_vertical_scroll_bar (window, make_save_ptr (bar));
3763     }
3764   else
3765     {
3766       NSRect oldRect;
3767       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3768       oldRect = [bar frame];
3769       r.size.width = oldRect.size.width;
3770       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3771         {
3772           if (oldRect.origin.x != r.origin.x)
3773               ns_clear_frame_area (f, sb_left, top, width, height);
3774           [bar setFrame: r];
3775         }
3776     }
3778   [bar setPosition: position portion: portion whole: whole];
3779   unblock_input ();
3783 static void
3784 ns_condemn_scroll_bars (struct frame *f)
3785 /* --------------------------------------------------------------------------
3786      External (hook): arrange for all frame's scrollbars to be removed
3787      at next call to judge_scroll_bars, except for those redeemed.
3788    -------------------------------------------------------------------------- */
3790   int i;
3791   id view;
3792   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3794   NSTRACE (ns_condemn_scroll_bars);
3796   for (i =[subviews count]-1; i >= 0; i--)
3797     {
3798       view = [subviews objectAtIndex: i];
3799       if ([view isKindOfClass: [EmacsScroller class]])
3800         [view condemn];
3801     }
3805 static void
3806 ns_redeem_scroll_bar (struct window *window)
3807 /* --------------------------------------------------------------------------
3808      External (hook): arrange to spare this window's scrollbar
3809      at next call to judge_scroll_bars.
3810    -------------------------------------------------------------------------- */
3812   id bar;
3813   NSTRACE (ns_redeem_scroll_bar);
3814   if (!NILP (window->vertical_scroll_bar))
3815     {
3816       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3817       [bar reprieve];
3818     }
3822 static void
3823 ns_judge_scroll_bars (struct frame *f)
3824 /* --------------------------------------------------------------------------
3825      External (hook): destroy all scrollbars on frame that weren't
3826      redeemed after call to condemn_scroll_bars.
3827    -------------------------------------------------------------------------- */
3829   int i;
3830   id view;
3831   EmacsView *eview = FRAME_NS_VIEW (f);
3832   NSArray *subviews = [[eview superview] subviews];
3833   BOOL removed = NO;
3835   NSTRACE (ns_judge_scroll_bars);
3836   for (i = [subviews count]-1; i >= 0; --i)
3837     {
3838       view = [subviews objectAtIndex: i];
3839       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3840       [view judge];
3841       removed = YES;
3842     }
3844   if (removed)
3845     [eview updateFrameSize: NO];
3848 /* ==========================================================================
3850     Initialization
3852    ========================================================================== */
3855 x_display_pixel_height (struct ns_display_info *dpyinfo)
3857   NSArray *screens = [NSScreen screens];
3858   NSEnumerator *enumerator = [screens objectEnumerator];
3859   NSScreen *screen;
3860   NSRect frame;
3862   frame = NSZeroRect;
3863   while ((screen = [enumerator nextObject]) != nil)
3864     frame = NSUnionRect (frame, [screen frame]);
3866   return NSHeight (frame);
3870 x_display_pixel_width (struct ns_display_info *dpyinfo)
3872   NSArray *screens = [NSScreen screens];
3873   NSEnumerator *enumerator = [screens objectEnumerator];
3874   NSScreen *screen;
3875   NSRect frame;
3877   frame = NSZeroRect;
3878   while ((screen = [enumerator nextObject]) != nil)
3879     frame = NSUnionRect (frame, [screen frame]);
3881   return NSWidth (frame);
3885 static Lisp_Object ns_string_to_lispmod (const char *s)
3886 /* --------------------------------------------------------------------------
3887      Convert modifier name to lisp symbol
3888    -------------------------------------------------------------------------- */
3890   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3891     return Qmeta;
3892   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3893     return Qsuper;
3894   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3895     return Qcontrol;
3896   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3897     return Qalt;
3898   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3899     return Qhyper;
3900   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3901     return Qnone;
3902   else
3903     return Qnil;
3907 static void
3908 ns_default (const char *parameter, Lisp_Object *result,
3909            Lisp_Object yesval, Lisp_Object noval,
3910            BOOL is_float, BOOL is_modstring)
3911 /* --------------------------------------------------------------------------
3912       Check a parameter value in user's preferences
3913    -------------------------------------------------------------------------- */
3915   const char *value = ns_get_defaults_value (parameter);
3917   if (value)
3918     {
3919       double f;
3920       char *pos;
3921       if (c_strcasecmp (value, "YES") == 0)
3922         *result = yesval;
3923       else if (c_strcasecmp (value, "NO") == 0)
3924         *result = noval;
3925       else if (is_float && (f = strtod (value, &pos), pos != value))
3926         *result = make_float (f);
3927       else if (is_modstring && value)
3928         *result = ns_string_to_lispmod (value);
3929       else fprintf (stderr,
3930                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3931     }
3935 static void
3936 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3937 /* --------------------------------------------------------------------------
3938       Initialize global info and storage for display.
3939    -------------------------------------------------------------------------- */
3941     NSScreen *screen = [NSScreen mainScreen];
3942     NSWindowDepth depth = [screen depth];
3944     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3945     dpyinfo->resy = 72.27;
3946     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3947                                                   NSColorSpaceFromDepth (depth)]
3948                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3949                                                  NSColorSpaceFromDepth (depth)];
3950     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3951     dpyinfo->image_cache = make_image_cache ();
3952     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
3953     dpyinfo->color_table->colors = NULL;
3954     dpyinfo->root_window = 42; /* a placeholder.. */
3955     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3956     dpyinfo->n_fonts = 0;
3957     dpyinfo->smallest_font_height = 1;
3958     dpyinfo->smallest_char_width = 1;
3960     reset_mouse_highlight (&dpyinfo->mouse_highlight);
3964 /* This and next define (many of the) public functions in this file. */
3965 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3966          with using despite presence in the "system dependent" redisplay
3967          interface.  In addition, many of the ns_ methods have code that is
3968          shared with all terms, indicating need for further refactoring. */
3969 extern frame_parm_handler ns_frame_parm_handlers[];
3970 static struct redisplay_interface ns_redisplay_interface =
3972   ns_frame_parm_handlers,
3973   x_produce_glyphs,
3974   x_write_glyphs,
3975   x_insert_glyphs,
3976   x_clear_end_of_line,
3977   ns_scroll_run,
3978   ns_after_update_window_line,
3979   ns_update_window_begin,
3980   ns_update_window_end,
3981   x_cursor_to,
3982   ns_flush,
3983   0, /* flush_display_optional */
3984   x_clear_window_mouse_face,
3985   x_get_glyph_overhangs,
3986   x_fix_overlapping_area,
3987   ns_draw_fringe_bitmap,
3988   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3989   0, /* destroy_fringe_bitmap */
3990   ns_compute_glyph_string_overhangs,
3991   ns_draw_glyph_string, /* interface to nsfont.m */
3992   ns_define_frame_cursor,
3993   ns_clear_frame_area,
3994   ns_draw_window_cursor,
3995   ns_draw_vertical_window_border,
3996   ns_shift_glyphs_for_insert
4000 static void
4001 ns_delete_display (struct ns_display_info *dpyinfo)
4003   /* TODO... */
4007 /* This function is called when the last frame on a display is deleted. */
4008 static void
4009 ns_delete_terminal (struct terminal *terminal)
4011   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4013   /* Protect against recursive calls.  delete_frame in
4014      delete_terminal calls us back when it deletes our last frame.  */
4015   if (!terminal->name)
4016     return;
4018   block_input ();
4020   x_destroy_all_bitmaps (dpyinfo);
4021   ns_delete_display (dpyinfo);
4022   unblock_input ();
4026 static struct terminal *
4027 ns_create_terminal (struct ns_display_info *dpyinfo)
4028 /* --------------------------------------------------------------------------
4029       Set up use of NS before we make the first connection.
4030    -------------------------------------------------------------------------- */
4032   struct terminal *terminal;
4034   NSTRACE (ns_create_terminal);
4036   terminal = create_terminal ();
4038   terminal->type = output_ns;
4039   terminal->display_info.ns = dpyinfo;
4040   dpyinfo->terminal = terminal;
4042   terminal->rif = &ns_redisplay_interface;
4044   terminal->clear_frame_hook = ns_clear_frame;
4045   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4046   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
4047   terminal->ring_bell_hook = ns_ring_bell;
4048   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
4049   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
4050   terminal->update_begin_hook = ns_update_begin;
4051   terminal->update_end_hook = ns_update_end;
4052   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4053   terminal->read_socket_hook = ns_read_socket;
4054   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4055   terminal->mouse_position_hook = ns_mouse_position;
4056   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4057   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4059   terminal->fullscreen_hook = ns_fullscreen_hook;
4061   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4062   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4063   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4064   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4066   terminal->delete_frame_hook = x_destroy_window;
4067   terminal->delete_terminal_hook = ns_delete_terminal;
4069   terminal->scroll_region_ok = 1;
4070   terminal->char_ins_del_ok = 1;
4071   terminal->line_ins_del_ok = 1;
4072   terminal->fast_clear_end_of_line = 1;
4073   terminal->memory_below_frame = 0;
4075   return terminal;
4079 struct ns_display_info *
4080 ns_term_init (Lisp_Object display_name)
4081 /* --------------------------------------------------------------------------
4082      Start the Application and get things rolling.
4083    -------------------------------------------------------------------------- */
4085   struct terminal *terminal;
4086   struct ns_display_info *dpyinfo;
4087   static int ns_initialized = 0;
4088   Lisp_Object tmp;
4090   if (ns_initialized) return x_display_list;
4091   ns_initialized = 1;
4093   NSTRACE (ns_term_init);
4095   [outerpool release];
4096   outerpool = [[NSAutoreleasePool alloc] init];
4098   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4099   /*GSDebugAllocationActive (YES); */
4100   block_input ();
4102   baud_rate = 38400;
4103   Fset_input_interrupt_mode (Qnil);
4105   if (selfds[0] == -1)
4106     {
4107       if (emacs_pipe (selfds) != 0)
4108         {
4109           fprintf (stderr, "Failed to create pipe: %s\n",
4110                    emacs_strerror (errno));
4111           emacs_abort ();
4112         }
4114       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4115       FD_ZERO (&select_readfds);
4116       FD_ZERO (&select_writefds);
4117       pthread_mutex_init (&select_mutex, NULL);
4118     }
4120   ns_pending_files = [[NSMutableArray alloc] init];
4121   ns_pending_service_names = [[NSMutableArray alloc] init];
4122   ns_pending_service_args = [[NSMutableArray alloc] init];
4124 /* Start app and create the main menu, window, view.
4125      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4126      The view will then ask the NSApp to stop and return to Emacs. */
4127   [EmacsApp sharedApplication];
4128   if (NSApp == nil)
4129     return NULL;
4130   [NSApp setDelegate: NSApp];
4132   /* Start the select thread.  */
4133   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4134                            toTarget:NSApp
4135                          withObject:nil];
4137   /* debugging: log all notifications */
4138   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4139                                          selector: @selector (logNotification:)
4140                                              name: nil object: nil]; */
4142   dpyinfo = xzalloc (sizeof *dpyinfo);
4144   ns_initialize_display_info (dpyinfo);
4145   terminal = ns_create_terminal (dpyinfo);
4147   terminal->kboard = xmalloc (sizeof *terminal->kboard);
4148   init_kboard (terminal->kboard);
4149   kset_window_system (terminal->kboard, Qns);
4150   terminal->kboard->next_kboard = all_kboards;
4151   all_kboards = terminal->kboard;
4152   /* Don't let the initial kboard remain current longer than necessary.
4153      That would cause problems if a file loaded on startup tries to
4154      prompt in the mini-buffer.  */
4155   if (current_kboard == initial_kboard)
4156     current_kboard = terminal->kboard;
4157   terminal->kboard->reference_count++;
4159   dpyinfo->next = x_display_list;
4160   x_display_list = dpyinfo;
4162   /* Put it on ns_display_name_list */
4163   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4164                                 ns_display_name_list);
4165   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4167   terminal->name = xstrdup (SSDATA (display_name));
4169   unblock_input ();
4171   if (!inhibit_x_resources)
4172     {
4173       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4174                  Qt, Qnil, NO, NO);
4175       tmp = Qnil;
4176       /* this is a standard variable */
4177       ns_default ("AppleAntiAliasingThreshold", &tmp,
4178                  make_float (10.0), make_float (6.0), YES, NO);
4179       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4180     }
4182   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4183                          stringForKey: @"AppleHighlightColor"];
4184   if (ns_selection_color == nil)
4185     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4187   {
4188     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4190     if ( cl == nil )
4191       {
4192         Lisp_Object color_file, color_map, color;
4193         unsigned long c;
4194         char *name;
4196         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4197                          Fsymbol_value (intern ("data-directory")));
4199         color_map = Fx_load_color_file (color_file);
4200         if (NILP (color_map))
4201           fatal ("Could not read %s.\n", SDATA (color_file));
4203         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4204         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4205           {
4206             color = XCAR (color_map);
4207             name = SSDATA (XCAR (color));
4208             c = XINT (XCDR (color));
4209             [cl setColor:
4210                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4211                                             green: GREEN_FROM_ULONG (c) / 255.0
4212                                              blue: BLUE_FROM_ULONG (c) / 255.0
4213                                             alpha: 1.0]
4214                   forKey: [NSString stringWithUTF8String: name]];
4215           }
4216         [cl writeToFile: nil];
4217       }
4218   }
4220   {
4221 #ifdef NS_IMPL_GNUSTEP
4222     Vwindow_system_version = build_string (gnustep_base_version);
4223 #else
4224     /*PSnextrelease (128, c); */
4225     char c[DBL_BUFSIZE_BOUND];
4226     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4227     Vwindow_system_version = make_unibyte_string (c, len);
4228 #endif
4229   }
4231   delete_keyboard_wait_descriptor (0);
4233   ns_app_name = [[NSProcessInfo processInfo] processName];
4235 /* Set up OS X app menu */
4236 #ifdef NS_IMPL_COCOA
4237   {
4238     NSMenu *appMenu;
4239     NSMenuItem *item;
4240     /* set up the application menu */
4241     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4242     [svcsMenu setAutoenablesItems: NO];
4243     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4244     [appMenu setAutoenablesItems: NO];
4245     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4246     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4248     [appMenu insertItemWithTitle: @"About Emacs"
4249                           action: @selector (orderFrontStandardAboutPanel:)
4250                    keyEquivalent: @""
4251                          atIndex: 0];
4252     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4253     [appMenu insertItemWithTitle: @"Preferences..."
4254                           action: @selector (showPreferencesWindow:)
4255                    keyEquivalent: @","
4256                          atIndex: 2];
4257     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4258     item = [appMenu insertItemWithTitle: @"Services"
4259                                  action: @selector (menuDown:)
4260                           keyEquivalent: @""
4261                                 atIndex: 4];
4262     [appMenu setSubmenu: svcsMenu forItem: item];
4263     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4264     [appMenu insertItemWithTitle: @"Hide Emacs"
4265                           action: @selector (hide:)
4266                    keyEquivalent: @"h"
4267                          atIndex: 6];
4268     item =  [appMenu insertItemWithTitle: @"Hide Others"
4269                           action: @selector (hideOtherApplications:)
4270                    keyEquivalent: @"h"
4271                          atIndex: 7];
4272     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4273     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4274     [appMenu insertItemWithTitle: @"Quit Emacs"
4275                           action: @selector (terminate:)
4276                    keyEquivalent: @"q"
4277                          atIndex: 9];
4279     item = [mainMenu insertItemWithTitle: ns_app_name
4280                                   action: @selector (menuDown:)
4281                            keyEquivalent: @""
4282                                  atIndex: 0];
4283     [mainMenu setSubmenu: appMenu forItem: item];
4284     [dockMenu insertItemWithTitle: @"New Frame"
4285                            action: @selector (newFrame:)
4286                     keyEquivalent: @""
4287                           atIndex: 0];
4289     [NSApp setMainMenu: mainMenu];
4290     [NSApp setAppleMenu: appMenu];
4291     [NSApp setServicesMenu: svcsMenu];
4292     /* Needed at least on Cocoa, to get dock menu to show windows */
4293     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4295     [[NSNotificationCenter defaultCenter]
4296       addObserver: mainMenu
4297          selector: @selector (trackingNotification:)
4298              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4299     [[NSNotificationCenter defaultCenter]
4300       addObserver: mainMenu
4301          selector: @selector (trackingNotification:)
4302              name: NSMenuDidEndTrackingNotification object: mainMenu];
4303   }
4304 #endif /* MAC OS X menu setup */
4306   /* Register our external input/output types, used for determining
4307      applicable services and also drag/drop eligibility. */
4308   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4309   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4310                       retain];
4311   ns_drag_types = [[NSArray arrayWithObjects:
4312                             NSStringPboardType,
4313                             NSTabularTextPboardType,
4314                             NSFilenamesPboardType,
4315                             NSURLPboardType,
4316                             NSColorPboardType,
4317                             NSFontPboardType, nil] retain];
4319   /* If fullscreen is in init/default-frame-alist, focus isn't set
4320      right for fullscreen windows, so set this.  */
4321   [NSApp activateIgnoringOtherApps:YES];
4323   [NSApp run];
4324   ns_do_open_file = YES;
4326 #ifdef NS_IMPL_GNUSTEP
4327   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4328      We must re-catch it so subprocess works.  */
4329   catch_child_signal ();
4330 #endif
4331   return dpyinfo;
4335 void
4336 ns_term_shutdown (int sig)
4338   [[NSUserDefaults standardUserDefaults] synchronize];
4340   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4341   if (STRINGP (Vauto_save_list_file_name))
4342     unlink (SSDATA (Vauto_save_list_file_name));
4344   if (sig == 0 || sig == SIGTERM)
4345     {
4346       [NSApp terminate: NSApp];
4347     }
4348   else // force a stack trace to happen
4349     {
4350       emacs_abort ();
4351     }
4355 /* ==========================================================================
4357     EmacsApp implementation
4359    ========================================================================== */
4362 @implementation EmacsApp
4364 - (void)logNotification: (NSNotification *)notification
4366   const char *name = [[notification name] UTF8String];
4367   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4368       && !strstr (name, "WindowNumber"))
4369     NSLog (@"notification: '%@'", [notification name]);
4373 - (void)sendEvent: (NSEvent *)theEvent
4374 /* --------------------------------------------------------------------------
4375      Called when NSApp is running for each event received.  Used to stop
4376      the loop when we choose, since there's no way to just run one iteration.
4377    -------------------------------------------------------------------------- */
4379   int type = [theEvent type];
4380   NSWindow *window = [theEvent window];
4382 /*  NSTRACE (sendEvent); */
4383 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4385 #ifdef NS_IMPL_GNUSTEP
4386   // Keyboard events aren't propagated to file dialogs for some reason.
4387   if ([NSApp modalWindow] != nil &&
4388       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4389     {
4390       [[NSApp modalWindow] sendEvent: theEvent];
4391       return;
4392     }
4393 #endif
4395   if (type == NSApplicationDefined)
4396     {
4397       switch ([theEvent data2])
4398         {
4399 #ifdef NS_IMPL_COCOA
4400         case NSAPP_DATA2_RUNASSCRIPT:
4401           ns_run_ascript ();
4402           [self stop: self];
4403           return;
4404 #endif
4405         case NSAPP_DATA2_RUNFILEDIALOG:
4406           ns_run_file_dialog ();
4407           [self stop: self];
4408           return;
4409         }
4410     }
4412   if (type == NSCursorUpdate && window == nil)
4413     {
4414       fprintf (stderr, "Dropping external cursor update event.\n");
4415       return;
4416     }
4418   if (type == NSApplicationDefined)
4419     {
4420       /* Events posted by ns_send_appdefined interrupt the run loop here.
4421          But, if a modal window is up, an appdefined can still come through,
4422          (e.g., from a makeKeyWindow event) but stopping self also stops the
4423          modal loop. Just defer it until later. */
4424       if ([NSApp modalWindow] == nil)
4425         {
4426           last_appdefined_event_data = [theEvent data1];
4427           [self stop: self];
4428         }
4429       else
4430         {
4431           send_appdefined = YES;
4432         }
4433     }
4436 #ifdef NS_IMPL_COCOA
4437   /* If no dialog and none of our frames have focus and it is a move, skip it.
4438      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4439      such as Wifi, sound, date or similar.
4440      This prevents "spooky" highlighting in the frame under the menu.  */
4441   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4442     {
4443       struct ns_display_info *di;
4444       BOOL has_focus = NO;
4445       for (di = x_display_list; ! has_focus && di; di = di->next)
4446         has_focus = di->x_focus_frame != 0;
4447       if (! has_focus)
4448         return;
4449     }
4450 #endif
4452   [super sendEvent: theEvent];
4456 - (void)showPreferencesWindow: (id)sender
4458   struct frame *emacsframe = SELECTED_FRAME ();
4459   NSEvent *theEvent = [NSApp currentEvent];
4461   if (!emacs_event)
4462     return;
4463   emacs_event->kind = NS_NONKEY_EVENT;
4464   emacs_event->code = KEY_NS_SHOW_PREFS;
4465   emacs_event->modifiers = 0;
4466   EV_TRAILER (theEvent);
4470 - (void)newFrame: (id)sender
4472   struct frame *emacsframe = SELECTED_FRAME ();
4473   NSEvent *theEvent = [NSApp currentEvent];
4475   if (!emacs_event)
4476     return;
4477   emacs_event->kind = NS_NONKEY_EVENT;
4478   emacs_event->code = KEY_NS_NEW_FRAME;
4479   emacs_event->modifiers = 0;
4480   EV_TRAILER (theEvent);
4484 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4485 - (BOOL) openFile: (NSString *)fileName
4487   struct frame *emacsframe = SELECTED_FRAME ();
4488   NSEvent *theEvent = [NSApp currentEvent];
4490   if (!emacs_event)
4491     return NO;
4493   emacs_event->kind = NS_NONKEY_EVENT;
4494   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4495   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4496   ns_input_line = Qnil; /* can be start or cons start,end */
4497   emacs_event->modifiers =0;
4498   EV_TRAILER (theEvent);
4500   return YES;
4504 /* **************************************************************************
4506       EmacsApp delegate implementation
4508    ************************************************************************** */
4510 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4511 /* --------------------------------------------------------------------------
4512      When application is loaded, terminate event loop in ns_term_init
4513    -------------------------------------------------------------------------- */
4515   NSTRACE (applicationDidFinishLaunching);
4516   [NSApp setServicesProvider: NSApp];
4517   ns_send_appdefined (-2);
4521 /* Termination sequences:
4522     C-x C-c:
4523     Cmd-Q:
4524     MenuBar | File | Exit:
4525     Select Quit from App menubar:
4526         -terminate
4527         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4528         ns_term_shutdown()
4530     Select Quit from Dock menu:
4531     Logout attempt:
4532         -appShouldTerminate
4533           Cancel -> Nothing else
4534           Accept ->
4536           -terminate
4537           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4538           ns_term_shutdown()
4542 - (void) terminate: (id)sender
4544   struct frame *emacsframe = SELECTED_FRAME ();
4546   if (!emacs_event)
4547     return;
4549   emacs_event->kind = NS_NONKEY_EVENT;
4550   emacs_event->code = KEY_NS_POWER_OFF;
4551   emacs_event->arg = Qt; /* mark as non-key event */
4552   EV_TRAILER ((id)nil);
4556 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4558   int ret;
4560   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4561     return NSTerminateNow;
4563     ret = NSRunAlertPanel(ns_app_name,
4564                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4565                           @"Save Buffers and Exit", @"Cancel", nil);
4567     if (ret == NSAlertDefaultReturn)
4568         return NSTerminateNow;
4569     else if (ret == NSAlertAlternateReturn)
4570         return NSTerminateCancel;
4571     return NSTerminateNow;  /* just in case */
4574 static int
4575 not_in_argv (NSString *arg)
4577   int k;
4578   const char *a = [arg UTF8String];
4579   for (k = 1; k < initial_argc; ++k)
4580     if (strcmp (a, initial_argv[k]) == 0) return 0;
4581   return 1;
4584 /*   Notification from the Workspace to open a file */
4585 - (BOOL)application: sender openFile: (NSString *)file
4587   if (ns_do_open_file || not_in_argv (file))
4588     [ns_pending_files addObject: file];
4589   return YES;
4593 /*   Open a file as a temporary file */
4594 - (BOOL)application: sender openTempFile: (NSString *)file
4596   if (ns_do_open_file || not_in_argv (file))
4597     [ns_pending_files addObject: file];
4598   return YES;
4602 /*   Notification from the Workspace to open a file noninteractively (?) */
4603 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4605   if (ns_do_open_file || not_in_argv (file))
4606     [ns_pending_files addObject: file];
4607   return YES;
4610 /*   Notification from the Workspace to open multiple files */
4611 - (void)application: sender openFiles: (NSArray *)fileList
4613   NSEnumerator *files = [fileList objectEnumerator];
4614   NSString *file;
4615   /* Don't open files from the command line unconditionally,
4616      Cocoa parses the command line wrong, --option value tries to open value
4617      if --option is the last option.  */
4618   while ((file = [files nextObject]) != nil)
4619     if (ns_do_open_file || not_in_argv (file))
4620       [ns_pending_files addObject: file];
4622   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4627 /* Handle dock menu requests.  */
4628 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4630   return dockMenu;
4634 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4635 - (void)applicationWillBecomeActive: (NSNotification *)notification
4637   //ns_app_active=YES;
4639 - (void)applicationDidBecomeActive: (NSNotification *)notification
4641   NSTRACE (applicationDidBecomeActive);
4643   //ns_app_active=YES;
4645   ns_update_auto_hide_menu_bar ();
4646   // No constraining takes place when the application is not active.
4647   ns_constrain_all_frames ();
4649 - (void)applicationDidResignActive: (NSNotification *)notification
4651   //ns_app_active=NO;
4652   ns_send_appdefined (-1);
4657 /* ==========================================================================
4659     EmacsApp aux handlers for managing event loop
4661    ========================================================================== */
4664 - (void)timeout_handler: (NSTimer *)timedEntry
4665 /* --------------------------------------------------------------------------
4666      The timeout specified to ns_select has passed.
4667    -------------------------------------------------------------------------- */
4669   /*NSTRACE (timeout_handler); */
4670   ns_send_appdefined (-2);
4673 #ifdef NS_IMPL_GNUSTEP
4674 - (void)sendFromMainThread:(id)unused
4676   ns_send_appdefined (nextappdefined);
4678 #endif
4680 - (void)fd_handler:(id)unused
4681 /* --------------------------------------------------------------------------
4682      Check data waiting on file descriptors and terminate if so
4683    -------------------------------------------------------------------------- */
4685   int result;
4686   int waiting = 1, nfds;
4687   char c;
4689   fd_set readfds, writefds, *wfds;
4690   struct timespec timeout, *tmo;
4691   NSAutoreleasePool *pool = nil;
4693   /* NSTRACE (fd_handler); */
4695   for (;;)
4696     {
4697       [pool release];
4698       pool = [[NSAutoreleasePool alloc] init];
4700       if (waiting)
4701         {
4702           fd_set fds;
4703           FD_ZERO (&fds);
4704           FD_SET (selfds[0], &fds);
4705           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4706           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4707             waiting = 0;
4708         }
4709       else
4710         {
4711           pthread_mutex_lock (&select_mutex);
4712           nfds = select_nfds;
4714           if (select_valid & SELECT_HAVE_READ)
4715             readfds = select_readfds;
4716           else
4717             FD_ZERO (&readfds);
4719           if (select_valid & SELECT_HAVE_WRITE)
4720             {
4721               writefds = select_writefds;
4722               wfds = &writefds;
4723             }
4724           else
4725             wfds = NULL;
4726           if (select_valid & SELECT_HAVE_TMO)
4727             {
4728               timeout = select_timeout;
4729               tmo = &timeout;
4730             }
4731           else
4732             tmo = NULL;
4734           pthread_mutex_unlock (&select_mutex);
4736           FD_SET (selfds[0], &readfds);
4737           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4739           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4741           if (result == 0)
4742             ns_send_appdefined (-2);
4743           else if (result > 0)
4744             {
4745               if (FD_ISSET (selfds[0], &readfds))
4746                 {
4747                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4748                     waiting = 1;
4749                 }
4750               else
4751                 {
4752                   pthread_mutex_lock (&select_mutex);
4753                   if (select_valid & SELECT_HAVE_READ)
4754                     select_readfds = readfds;
4755                   if (select_valid & SELECT_HAVE_WRITE)
4756                     select_writefds = writefds;
4757                   if (select_valid & SELECT_HAVE_TMO)
4758                     select_timeout = timeout;
4759                   pthread_mutex_unlock (&select_mutex);
4761                   ns_send_appdefined (result);
4762                 }
4763             }
4764           waiting = 1;
4765         }
4766     }
4771 /* ==========================================================================
4773     Service provision
4775    ========================================================================== */
4777 /* called from system: queue for next pass through event loop */
4778 - (void)requestService: (NSPasteboard *)pboard
4779               userData: (NSString *)userData
4780                  error: (NSString **)error
4782   [ns_pending_service_names addObject: userData];
4783   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4784       SSDATA (ns_string_from_pasteboard (pboard))]];
4788 /* called from ns_read_socket to clear queue */
4789 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4791   struct frame *emacsframe = SELECTED_FRAME ();
4792   NSEvent *theEvent = [NSApp currentEvent];
4794   if (!emacs_event)
4795     return NO;
4797   emacs_event->kind = NS_NONKEY_EVENT;
4798   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4799   ns_input_spi_name = build_string ([name UTF8String]);
4800   ns_input_spi_arg = build_string ([arg UTF8String]);
4801   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4802   EV_TRAILER (theEvent);
4804   return YES;
4808 @end  /* EmacsApp */
4812 /* ==========================================================================
4814     EmacsView implementation
4816    ========================================================================== */
4819 @implementation EmacsView
4821 /* needed to inform when window closed from LISP */
4822 - (void) setWindowClosing: (BOOL)closing
4824   windowClosing = closing;
4828 - (void)dealloc
4830   NSTRACE (EmacsView_dealloc);
4831   [toolbar release];
4832   if (fs_state == FULLSCREEN_BOTH)
4833     [nonfs_window release];
4834   [super dealloc];
4838 /* called on font panel selection */
4839 - (void)changeFont: (id)sender
4841   NSEvent *e =[[self window] currentEvent];
4842   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4843   id newFont;
4844   CGFloat size;
4846   NSTRACE (changeFont);
4847   if (!emacs_event)
4848     return;
4850   if ((newFont = [sender convertFont:
4851                            ((struct nsfont_info *)face->font)->nsfont]))
4852     {
4853       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4855       emacs_event->kind = NS_NONKEY_EVENT;
4856       emacs_event->modifiers = 0;
4857       emacs_event->code = KEY_NS_CHANGE_FONT;
4859       size = [newFont pointSize];
4860       ns_input_fontsize = make_number (lrint (size));
4861       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4862       EV_TRAILER (e);
4863     }
4867 - (BOOL)acceptsFirstResponder
4869   NSTRACE (acceptsFirstResponder);
4870   return YES;
4874 - (void)resetCursorRects
4876   NSRect visible = [self visibleRect];
4877   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4878   NSTRACE (resetCursorRects);
4880   if (currentCursor == nil)
4881     currentCursor = [NSCursor arrowCursor];
4883   if (!NSIsEmptyRect (visible))
4884     [self addCursorRect: visible cursor: currentCursor];
4885   [currentCursor setOnMouseEntered: YES];
4890 /*****************************************************************************/
4891 /* Keyboard handling. */
4892 #define NS_KEYLOG 0
4894 - (void)keyDown: (NSEvent *)theEvent
4896   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4897   int code;
4898   unsigned fnKeysym = 0;
4899   static NSMutableArray *nsEvArray;
4900 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4901   static BOOL firstTime = YES;
4902 #endif
4903   int left_is_none;
4904   unsigned int flags = [theEvent modifierFlags];
4906   NSTRACE (keyDown);
4908   /* Rhapsody and OS X give up and down events for the arrow keys */
4909   if (ns_fake_keydown == YES)
4910     ns_fake_keydown = NO;
4911   else if ([theEvent type] != NSKeyDown)
4912     return;
4914   if (!emacs_event)
4915     return;
4917  if (![[self window] isKeyWindow]
4918      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4919      /* we must avoid an infinite loop here. */
4920      && (EmacsView *)[[theEvent window] delegate] != self)
4921    {
4922      /* XXX: There is an occasional condition in which, when Emacs display
4923          updates a different frame from the current one, and temporarily
4924          selects it, then processes some interrupt-driven input
4925          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4926          for some reason that window has its first responder set to the NSView
4927          most recently updated (I guess), which is not the correct one. */
4928      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4929      return;
4930    }
4932   if (nsEvArray == nil)
4933     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4935   [NSCursor setHiddenUntilMouseMoves: YES];
4937   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4938     {
4939       clear_mouse_face (hlinfo);
4940       hlinfo->mouse_face_hidden = 1;
4941     }
4943   if (!processingCompose)
4944     {
4945       /* When using screen sharing, no left or right information is sent,
4946          so use Left key in those cases.  */
4947       int is_left_key, is_right_key;
4949       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4950         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4952       /* (Carbon way: [theEvent keyCode]) */
4954       /* is it a "function key"? */
4955       fnKeysym = (code < 0x00ff && (flags&NSNumericPadKeyMask))
4956         ? ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask)
4957         : ns_convert_key (code);
4959       if (fnKeysym)
4960         {
4961           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4962              because Emacs treats Delete and KP-Delete same (in simple.el). */
4963           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4964 #ifdef NS_IMPL_GNUSTEP
4965               /*  GNUstep uses incompatible keycodes, even for those that are
4966                   supposed to be hardware independent.  Just check for delete.
4967                   Keypad delete does not have keysym 0xFFFF.
4968                   See http://savannah.gnu.org/bugs/?25395
4969               */
4970               || (fnKeysym == 0xFFFF && code == 127)
4971 #endif
4972             )
4973             code = 0xFF08; /* backspace */
4974           else
4975             code = fnKeysym;
4976         }
4978       /* are there modifiers? */
4979       emacs_event->modifiers = 0;
4981       if (flags & NSHelpKeyMask)
4982           emacs_event->modifiers |= hyper_modifier;
4984       if (flags & NSShiftKeyMask)
4985         emacs_event->modifiers |= shift_modifier;
4987       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
4988       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
4989         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
4991       if (is_right_key)
4992         emacs_event->modifiers |= parse_solitary_modifier
4993           (EQ (ns_right_command_modifier, Qleft)
4994            ? ns_command_modifier
4995            : ns_right_command_modifier);
4997       if (is_left_key)
4998         {
4999           emacs_event->modifiers |= parse_solitary_modifier
5000             (ns_command_modifier);
5002           /* if super (default), take input manager's word so things like
5003              dvorak / qwerty layout work */
5004           if (EQ (ns_command_modifier, Qsuper)
5005               && !fnKeysym
5006               && [[theEvent characters] length] != 0)
5007             {
5008               /* XXX: the code we get will be unshifted, so if we have
5009                  a shift modifier, must convert ourselves */
5010               if (!(flags & NSShiftKeyMask))
5011                 code = [[theEvent characters] characterAtIndex: 0];
5012 #if 0
5013               /* this is ugly and also requires linking w/Carbon framework
5014                  (for LMGetKbdType) so for now leave this rare (?) case
5015                  undealt with.. in future look into CGEvent methods */
5016               else
5017                 {
5018                   long smv = GetScriptManagerVariable (smKeyScript);
5019                   Handle uchrHandle = GetResource
5020                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5021                   UInt32 dummy = 0;
5022                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5023                                  [[theEvent characters] characterAtIndex: 0],
5024                                  kUCKeyActionDisplay,
5025                                  (flags & ~NSCommandKeyMask) >> 8,
5026                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5027                                  &dummy, 1, &dummy, &code);
5028                   code &= 0xFF;
5029                 }
5030 #endif
5031             }
5032         }
5034       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5035       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5036         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5038       if (is_right_key)
5039           emacs_event->modifiers |= parse_solitary_modifier
5040               (EQ (ns_right_control_modifier, Qleft)
5041                ? ns_control_modifier
5042                : ns_right_control_modifier);
5044       if (is_left_key)
5045         emacs_event->modifiers |= parse_solitary_modifier
5046           (ns_control_modifier);
5048       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5049           emacs_event->modifiers |=
5050             parse_solitary_modifier (ns_function_modifier);
5052       left_is_none = NILP (ns_alternate_modifier)
5053         || EQ (ns_alternate_modifier, Qnone);
5055       is_right_key = (flags & NSRightAlternateKeyMask)
5056         == NSRightAlternateKeyMask;
5057       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5058         || (! is_right_key
5059             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5061       if (is_right_key)
5062         {
5063           if ((NILP (ns_right_alternate_modifier)
5064                || EQ (ns_right_alternate_modifier, Qnone)
5065                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5066               && !fnKeysym)
5067             {   /* accept pre-interp alt comb */
5068               if ([[theEvent characters] length] > 0)
5069                 code = [[theEvent characters] characterAtIndex: 0];
5070               /*HACK: clear lone shift modifier to stop next if from firing */
5071               if (emacs_event->modifiers == shift_modifier)
5072                 emacs_event->modifiers = 0;
5073             }
5074           else
5075             emacs_event->modifiers |= parse_solitary_modifier
5076               (EQ (ns_right_alternate_modifier, Qleft)
5077                ? ns_alternate_modifier
5078                : ns_right_alternate_modifier);
5079         }
5081       if (is_left_key) /* default = meta */
5082         {
5083           if (left_is_none && !fnKeysym)
5084             {   /* accept pre-interp alt comb */
5085               if ([[theEvent characters] length] > 0)
5086                 code = [[theEvent characters] characterAtIndex: 0];
5087               /*HACK: clear lone shift modifier to stop next if from firing */
5088               if (emacs_event->modifiers == shift_modifier)
5089                 emacs_event->modifiers = 0;
5090             }
5091           else
5092               emacs_event->modifiers |=
5093                 parse_solitary_modifier (ns_alternate_modifier);
5094         }
5096   if (NS_KEYLOG)
5097     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5098              code, fnKeysym, flags, emacs_event->modifiers);
5100       /* if it was a function key or had modifiers, pass it directly to emacs */
5101       if (fnKeysym || (emacs_event->modifiers
5102                        && (emacs_event->modifiers != shift_modifier)
5103                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5104 /*[[theEvent characters] length] */
5105         {
5106           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5107           if (code < 0x20)
5108             code |= (1<<28)|(3<<16);
5109           else if (code == 0x7f)
5110             code |= (1<<28)|(3<<16);
5111           else if (!fnKeysym)
5112             emacs_event->kind = code > 0xFF
5113               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5115           emacs_event->code = code;
5116           EV_TRAILER (theEvent);
5117           processingCompose = NO;
5118           return;
5119         }
5120     }
5123 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5124   /* if we get here we should send the key for input manager processing */
5125   /* Disable warning, there is nothing a user can do about it anyway, and
5126      it does not seem to matter.  */
5127 #if 0
5128   if (firstTime && [[NSInputManager currentInputManager]
5129                      wantsToDelayTextChangeNotifications] == NO)
5130     fprintf (stderr,
5131           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5132 #endif
5133   firstTime = NO;
5134 #endif
5135   if (NS_KEYLOG && !processingCompose)
5136     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5138   processingCompose = YES;
5139   [nsEvArray addObject: theEvent];
5140   [self interpretKeyEvents: nsEvArray];
5141   [nsEvArray removeObject: theEvent];
5145 #ifdef NS_IMPL_COCOA
5146 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5147    decided not to send key-down for.
5148    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5149    This only applies on Tiger and earlier.
5150    If it matches one of these, send it on to keyDown. */
5151 -(void)keyUp: (NSEvent *)theEvent
5153   int flags = [theEvent modifierFlags];
5154   int code = [theEvent keyCode];
5155   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5156       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5157     {
5158       if (NS_KEYLOG)
5159         fprintf (stderr, "keyUp: passed test");
5160       ns_fake_keydown = YES;
5161       [self keyDown: theEvent];
5162     }
5164 #endif
5167 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5170 /* <NSTextInput>: called when done composing;
5171    NOTE: also called when we delete over working text, followed immed.
5172          by doCommandBySelector: deleteBackward: */
5173 - (void)insertText: (id)aString
5175   int code;
5176   int len = [(NSString *)aString length];
5177   int i;
5179   if (NS_KEYLOG)
5180     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5181   processingCompose = NO;
5183   if (!emacs_event)
5184     return;
5186   /* first, clear any working text */
5187   if (workingText != nil)
5188     [self deleteWorkingText];
5190   /* now insert the string as keystrokes */
5191   for (i =0; i<len; i++)
5192     {
5193       code = [aString characterAtIndex: i];
5194       /* TODO: still need this? */
5195       if (code == 0x2DC)
5196         code = '~'; /* 0x7E */
5197       if (code != 32) /* Space */
5198         emacs_event->modifiers = 0;
5199       emacs_event->kind
5200         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5201       emacs_event->code = code;
5202       EV_TRAILER ((id)nil);
5203     }
5207 /* <NSTextInput>: inserts display of composing characters */
5208 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5210   NSString *str = [aString respondsToSelector: @selector (string)] ?
5211     [aString string] : aString;
5212   if (NS_KEYLOG)
5213     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
5214            selRange.length, selRange.location);
5216   if (workingText != nil)
5217     [self deleteWorkingText];
5218   if ([str length] == 0)
5219     return;
5221   if (!emacs_event)
5222     return;
5224   processingCompose = YES;
5225   workingText = [str copy];
5226   ns_working_text = build_string ([workingText UTF8String]);
5228   emacs_event->kind = NS_TEXT_EVENT;
5229   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5230   EV_TRAILER ((id)nil);
5234 /* delete display of composing characters [not in <NSTextInput>] */
5235 - (void)deleteWorkingText
5237   if (workingText == nil)
5238     return;
5239   if (NS_KEYLOG)
5240     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
5241   [workingText release];
5242   workingText = nil;
5243   processingCompose = NO;
5245   if (!emacs_event)
5246     return;
5248   emacs_event->kind = NS_TEXT_EVENT;
5249   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5250   EV_TRAILER ((id)nil);
5254 - (BOOL)hasMarkedText
5256   return workingText != nil;
5260 - (NSRange)markedRange
5262   NSRange rng = workingText != nil
5263     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5264   if (NS_KEYLOG)
5265     NSLog (@"markedRange request");
5266   return rng;
5270 - (void)unmarkText
5272   if (NS_KEYLOG)
5273     NSLog (@"unmark (accept) text");
5274   [self deleteWorkingText];
5275   processingCompose = NO;
5279 /* used to position char selection windows, etc. */
5280 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5282   NSRect rect;
5283   NSPoint pt;
5284   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5285   if (NS_KEYLOG)
5286     NSLog (@"firstRectForCharRange request");
5288   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5289   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5290   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5291   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5292                                        +FRAME_LINE_HEIGHT (emacsframe));
5294   pt = [self convertPoint: pt toView: nil];
5295   pt = [[self window] convertBaseToScreen: pt];
5296   rect.origin = pt;
5297   return rect;
5301 - (NSInteger)conversationIdentifier
5303   return (NSInteger)self;
5307 - (void)doCommandBySelector: (SEL)aSelector
5309   if (NS_KEYLOG)
5310     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5312   processingCompose = NO;
5313   if (aSelector == @selector (deleteBackward:))
5314     {
5315       /* happens when user backspaces over an ongoing composition:
5316          throw a 'delete' into the event queue */
5317       if (!emacs_event)
5318         return;
5319       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5320       emacs_event->code = 0xFF08;
5321       EV_TRAILER ((id)nil);
5322     }
5325 - (NSArray *)validAttributesForMarkedText
5327   static NSArray *arr = nil;
5328   if (arr == nil) arr = [NSArray new];
5329  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5330   return arr;
5333 - (NSRange)selectedRange
5335   if (NS_KEYLOG)
5336     NSLog (@"selectedRange request");
5337   return NSMakeRange (NSNotFound, 0);
5340 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5341     GNUSTEP_GUI_MINOR_VERSION > 22
5342 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5343 #else
5344 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5345 #endif
5347   if (NS_KEYLOG)
5348     NSLog (@"characterIndexForPoint request");
5349   return 0;
5352 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5354   static NSAttributedString *str = nil;
5355   if (str == nil) str = [NSAttributedString new];
5356   if (NS_KEYLOG)
5357     NSLog (@"attributedSubstringFromRange request");
5358   return str;
5361 /* End <NSTextInput> impl. */
5362 /*****************************************************************************/
5365 /* This is what happens when the user presses a mouse button.  */
5366 - (void)mouseDown: (NSEvent *)theEvent
5368   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5370   NSTRACE (mouseDown);
5372   [self deleteWorkingText];
5374   if (!emacs_event)
5375     return;
5377   last_mouse_frame = emacsframe;
5378   /* appears to be needed to prevent spurious movement events generated on
5379      button clicks */
5380   last_mouse_frame->mouse_moved = 0;
5382   if ([theEvent type] == NSScrollWheel)
5383     {
5384       CGFloat delta = [theEvent deltaY];
5385       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5386       if (delta == 0)
5387         return;
5388       emacs_event->kind = WHEEL_EVENT;
5389       emacs_event->code = 0;
5390       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5391         ((delta > 0) ? up_modifier : down_modifier);
5392     }
5393   else
5394     {
5395       emacs_event->kind = MOUSE_CLICK_EVENT;
5396       emacs_event->code = EV_BUTTON (theEvent);
5397       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5398                              | EV_UDMODIFIERS (theEvent);
5399     }
5400   XSETINT (emacs_event->x, lrint (p.x));
5401   XSETINT (emacs_event->y, lrint (p.y));
5402   EV_TRAILER (theEvent);
5406 - (void)rightMouseDown: (NSEvent *)theEvent
5408   NSTRACE (rightMouseDown);
5409   [self mouseDown: theEvent];
5413 - (void)otherMouseDown: (NSEvent *)theEvent
5415   NSTRACE (otherMouseDown);
5416   [self mouseDown: theEvent];
5420 - (void)mouseUp: (NSEvent *)theEvent
5422   NSTRACE (mouseUp);
5423   [self mouseDown: theEvent];
5427 - (void)rightMouseUp: (NSEvent *)theEvent
5429   NSTRACE (rightMouseUp);
5430   [self mouseDown: theEvent];
5434 - (void)otherMouseUp: (NSEvent *)theEvent
5436   NSTRACE (otherMouseUp);
5437   [self mouseDown: theEvent];
5441 - (void) scrollWheel: (NSEvent *)theEvent
5443   NSTRACE (scrollWheel);
5444   [self mouseDown: theEvent];
5448 /* Tell emacs the mouse has moved. */
5449 - (void)mouseMoved: (NSEvent *)e
5451   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5452   Lisp_Object frame;
5454 //  NSTRACE (mouseMoved);
5456   last_mouse_movement_time = EV_TIMESTAMP (e);
5457   last_mouse_motion_position
5458     = [self convertPoint: [e locationInWindow] fromView: nil];
5460   /* update any mouse face */
5461   if (hlinfo->mouse_face_hidden)
5462     {
5463       hlinfo->mouse_face_hidden = 0;
5464       clear_mouse_face (hlinfo);
5465     }
5467   /* tooltip handling */
5468   previous_help_echo_string = help_echo_string;
5469   help_echo_string = Qnil;
5471   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5472                             last_mouse_motion_position.y))
5473     help_echo_string = previous_help_echo_string;
5475   XSETFRAME (frame, emacsframe);
5476   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5477     {
5478       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5479          (note_mouse_highlight), which is called through the
5480          note_mouse_movement () call above */
5481       gen_help_event (help_echo_string, frame, help_echo_window,
5482                       help_echo_object, help_echo_pos);
5483     }
5484   else
5485     {
5486       help_echo_string = Qnil;
5487       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5488     }
5490   if (emacsframe->mouse_moved && send_appdefined)
5491     ns_send_appdefined (-1);
5495 - (void)mouseDragged: (NSEvent *)e
5497   NSTRACE (mouseDragged);
5498   [self mouseMoved: e];
5502 - (void)rightMouseDragged: (NSEvent *)e
5504   NSTRACE (rightMouseDragged);
5505   [self mouseMoved: e];
5509 - (void)otherMouseDragged: (NSEvent *)e
5511   NSTRACE (otherMouseDragged);
5512   [self mouseMoved: e];
5516 - (BOOL)windowShouldClose: (id)sender
5518   NSEvent *e =[[self window] currentEvent];
5520   NSTRACE (windowShouldClose);
5521   windowClosing = YES;
5522   if (!emacs_event)
5523     return NO;
5524   emacs_event->kind = DELETE_WINDOW_EVENT;
5525   emacs_event->modifiers = 0;
5526   emacs_event->code = 0;
5527   EV_TRAILER (e);
5528   /* Don't close this window, let this be done from lisp code.  */
5529   return NO;
5532 - (void) updateFrameSize: (BOOL) delay;
5534   NSWindow *window = [self window];
5535   NSRect wr = [window frame];
5536   int extra = 0;
5537   int gsextra = 0;
5538 #ifdef NS_IMPL_GNUSTEP
5539   gsextra = 3;
5540 #endif
5542   int oldc = cols, oldr = rows;
5543   int oldw = FRAME_PIXEL_WIDTH (emacsframe),
5544     oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5545   int neww, newh;
5547   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, wr.size.width + gsextra);
5549   if (cols < MINWIDTH)
5550     cols = MINWIDTH;
5552   if (! [self isFullscreen])
5553     {
5554       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5555         + FRAME_TOOLBAR_HEIGHT (emacsframe) - gsextra;
5556     }
5558   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, wr.size.height - extra);
5560   if (rows < MINHEIGHT)
5561     rows = MINHEIGHT;
5563   neww = (int)wr.size.width - emacsframe->border_width;
5564   newh = (int)wr.size.height - extra;
5566   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5567     {
5568       NSView *view = FRAME_NS_VIEW (emacsframe);
5569       NSWindow *win = [view window];
5570       NSSize sz = [win resizeIncrements];
5572       FRAME_PIXEL_WIDTH (emacsframe) = neww;
5573       FRAME_PIXEL_HEIGHT (emacsframe) = newh;
5574       change_frame_size (emacsframe, rows, cols, 0, delay, 0);
5575       SET_FRAME_GARBAGED (emacsframe);
5576       cancel_mouse_face (emacsframe);
5578       // Did resize increments change because of a font change?
5579       if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5580           sz.height != FRAME_LINE_HEIGHT (emacsframe))
5581         {
5582           sz.width = FRAME_COLUMN_WIDTH (emacsframe);
5583           sz.height = FRAME_LINE_HEIGHT (emacsframe);
5584           [win setResizeIncrements: sz];
5585         }
5587       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5588       [self windowDidMove:nil];   // Update top/left.
5589     }
5592 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5593 /* normalize frame to gridded text size */
5595   int extra = 0;
5596   int gsextra = 0;
5597 #ifdef NS_IMPL_GNUSTEP
5598   gsextra = 3;
5599 #endif
5601   NSTRACE (windowWillResize);
5602 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5604   if (fs_state == FULLSCREEN_MAXIMIZED
5605       && (maximized_width != (int)frameSize.width
5606           || maximized_height != (int)frameSize.height))
5607     [self setFSValue: FULLSCREEN_NONE];
5608   else if (fs_state == FULLSCREEN_WIDTH
5609            && maximized_width != (int)frameSize.width)
5610     [self setFSValue: FULLSCREEN_NONE];
5611   else if (fs_state == FULLSCREEN_HEIGHT
5612            && maximized_height != (int)frameSize.height)
5613     [self setFSValue: FULLSCREEN_NONE];
5614   if (fs_state == FULLSCREEN_NONE)
5615     maximized_width = maximized_height = -1;
5617   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5618                                          frameSize.width + gsextra);
5619   if (cols < MINWIDTH)
5620     cols = MINWIDTH;
5622   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5623                                            frameSize.height - extra);
5624   if (rows < MINHEIGHT)
5625     rows = MINHEIGHT;
5626 #ifdef NS_IMPL_COCOA
5627   {
5628     /* this sets window title to have size in it; the wm does this under GS */
5629     NSRect r = [[self window] frame];
5630     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5631       {
5632         if (old_title != 0)
5633           {
5634             xfree (old_title);
5635             old_title = 0;
5636           }
5637       }
5638     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5639       {
5640         char *size_title;
5641         NSWindow *window = [self window];
5642         if (old_title == 0)
5643           {
5644             char *t = strdup ([[[self window] title] UTF8String]);
5645             char *pos = strstr (t, "  â€”  ");
5646             if (pos)
5647               *pos = '\0';
5648             old_title = t;
5649           }
5650         size_title = xmalloc (strlen (old_title) + 40);
5651         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5652         [window setTitle: [NSString stringWithUTF8String: size_title]];
5653         [window display];
5654         xfree (size_title);
5655       }
5656   }
5657 #endif /* NS_IMPL_COCOA */
5658 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5660   return frameSize;
5664 - (void)windowDidResize: (NSNotification *)notification
5666   if (! [self fsIsNative])
5667     {
5668       NSWindow *theWindow = [notification object];
5669       /* We can get notification on the non-FS window when in
5670          fullscreen mode.  */
5671       if ([self window] != theWindow) return;
5672     }
5674 #ifdef NS_IMPL_GNUSTEP
5675   NSWindow *theWindow = [notification object];
5677    /* In GNUstep, at least currently, it's possible to get a didResize
5678       without getting a willResize.. therefore we need to act as if we got
5679       the willResize now */
5680   NSSize sz = [theWindow frame].size;
5681   sz = [self windowWillResize: theWindow toSize: sz];
5682 #endif /* NS_IMPL_GNUSTEP */
5684   NSTRACE (windowDidResize);
5685 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5687 if (cols > 0 && rows > 0)
5688     {
5689       [self updateFrameSize: YES];
5690     }
5692   ns_send_appdefined (-1);
5695 #ifdef NS_IMPL_COCOA
5696 - (void)viewDidEndLiveResize
5698   [super viewDidEndLiveResize];
5699   if (old_title != 0)
5700     {
5701       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
5702       xfree (old_title);
5703       old_title = 0;
5704     }
5705   maximizing_resize = NO;
5707 #endif /* NS_IMPL_COCOA */
5710 - (void)windowDidBecomeKey: (NSNotification *)notification
5711 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5713   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5714   struct frame *old_focus = dpyinfo->x_focus_frame;
5716   NSTRACE (windowDidBecomeKey);
5718   if (emacsframe != old_focus)
5719     dpyinfo->x_focus_frame = emacsframe;
5721   ns_frame_rehighlight (emacsframe);
5723   if (emacs_event)
5724     {
5725       emacs_event->kind = FOCUS_IN_EVENT;
5726       EV_TRAILER ((id)nil);
5727     }
5731 - (void)windowDidResignKey: (NSNotification *)notification
5732 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5734   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5735   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
5736   NSTRACE (windowDidResignKey);
5738   if (is_focus_frame)
5739     dpyinfo->x_focus_frame = 0;
5741   ns_frame_rehighlight (emacsframe);
5743   /* FIXME: for some reason needed on second and subsequent clicks away
5744             from sole-frame Emacs to get hollow box to show */
5745   if (!windowClosing && [[self window] isVisible] == YES)
5746     {
5747       x_update_cursor (emacsframe, 1);
5748       x_set_frame_alpha (emacsframe);
5749     }
5751   if (emacs_event && is_focus_frame)
5752     {
5753       [self deleteWorkingText];
5754       emacs_event->kind = FOCUS_OUT_EVENT;
5755       EV_TRAILER ((id)nil);
5756     }
5760 - (void)windowWillMiniaturize: sender
5762   NSTRACE (windowWillMiniaturize);
5766 - (BOOL)isFlipped
5768   return YES;
5772 - (BOOL)isOpaque
5774   return NO;
5778 - initFrameFromEmacs: (struct frame *)f
5780   NSRect r, wr;
5781   Lisp_Object tem;
5782   NSWindow *win;
5783   NSSize sz;
5784   NSColor *col;
5785   NSString *name;
5787   NSTRACE (initFrameFromEmacs);
5789   windowClosing = NO;
5790   processingCompose = NO;
5791   scrollbarsNeedingUpdate = 0;
5792   fs_state = FULLSCREEN_NONE;
5793   fs_before_fs = next_maximized = -1;
5794 #ifdef HAVE_NATIVE_FS
5795   fs_is_native = ns_use_native_fullscreen;
5796 #else
5797   fs_is_native = NO;
5798 #endif
5799   maximized_width = maximized_height = -1;
5800   nonfs_window = nil;
5802 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5804   ns_userRect = NSMakeRect (0, 0, 0, 0);
5805   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5806                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5807   [self initWithFrame: r];
5808   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5810   FRAME_NS_VIEW (f) = self;
5811   emacsframe = f;
5812 #ifdef NS_IMPL_COCOA
5813   old_title = 0;
5814   maximizing_resize = NO;
5815 #endif
5817   win = [[EmacsWindow alloc]
5818             initWithContentRect: r
5819                       styleMask: (NSResizableWindowMask |
5820 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5821                                   NSTitledWindowMask |
5822 #endif
5823                                   NSMiniaturizableWindowMask |
5824                                   NSClosableWindowMask)
5825                         backing: NSBackingStoreBuffered
5826                           defer: YES];
5828 #ifdef HAVE_NATIVE_FS
5829     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
5830 #endif
5832   wr = [win frame];
5833   bwidth = f->border_width = wr.size.width - r.size.width;
5834   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5836   [win setAcceptsMouseMovedEvents: YES];
5837   [win setDelegate: self];
5838   [win useOptimizedDrawing: YES];
5840   sz.width = FRAME_COLUMN_WIDTH (f);
5841   sz.height = FRAME_LINE_HEIGHT (f);
5842   [win setResizeIncrements: sz];
5844   [[win contentView] addSubview: self];
5846   if (ns_drag_types)
5847     [self registerForDraggedTypes: ns_drag_types];
5849   tem = f->name;
5850   name = [NSString stringWithUTF8String:
5851                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5852   [win setTitle: name];
5854   /* toolbar support */
5855   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5856                          [NSString stringWithFormat: @"Emacs Frame %d",
5857                                    ns_window_num]];
5858   [win setToolbar: toolbar];
5859   [toolbar setVisible: NO];
5860 #ifdef NS_IMPL_COCOA
5861   {
5862     NSButton *toggleButton;
5863   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5864   [toggleButton setTarget: self];
5865   [toggleButton setAction: @selector (toggleToolbar: )];
5866   }
5867 #endif
5868   FRAME_TOOLBAR_HEIGHT (f) = 0;
5870   tem = f->icon_name;
5871   if (!NILP (tem))
5872     [win setMiniwindowTitle:
5873            [NSString stringWithUTF8String: SSDATA (tem)]];
5875   {
5876     NSScreen *screen = [win screen];
5878     if (screen != 0)
5879       [win setFrameTopLeftPoint: NSMakePoint
5880            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5881             IN_BOUND (-SCREENMAX,
5882                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5883   }
5885   [win makeFirstResponder: self];
5887   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5888                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5889   [win setBackgroundColor: col];
5890   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
5891     [win setOpaque: NO];
5893   [self allocateGState];
5895   [NSApp registerServicesMenuSendTypes: ns_send_types
5896                            returnTypes: nil];
5898   ns_window_num++;
5899   return self;
5903 - (void)windowDidMove: sender
5905   NSWindow *win = [self window];
5906   NSRect r = [win frame];
5907   NSArray *screens = [NSScreen screens];
5908   NSScreen *screen = [screens objectAtIndex: 0];
5910   NSTRACE (windowDidMove);
5912   if (!emacsframe->output_data.ns)
5913     return;
5914   if (screen != nil)
5915     {
5916       emacsframe->left_pos = r.origin.x;
5917       emacsframe->top_pos =
5918         [screen frame].size.height - (r.origin.y + r.size.height);
5919     }
5923 /* Called AFTER method below, but before our windowWillResize call there leads
5924    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5925    location so set_window_size moves the frame. */
5926 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5928   emacsframe->output_data.ns->zooming = 1;
5929   return YES;
5933 /* Override to do something slightly nonstandard, but nice.  First click on
5934    zoom button will zoom vertically.  Second will zoom completely.  Third
5935    returns to original. */
5936 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5937                         defaultFrame:(NSRect)defaultFrame
5939   NSRect result = [sender frame];
5941   NSTRACE (windowWillUseStandardFrame);
5943   if (fs_before_fs != -1) /* Entering fullscreen */
5944       {
5945         result = defaultFrame;
5946       }
5947   else if (next_maximized == FULLSCREEN_HEIGHT
5948       || (next_maximized == -1
5949           && abs (defaultFrame.size.height - result.size.height)
5950           > FRAME_LINE_HEIGHT (emacsframe)))
5951     {
5952       /* first click */
5953       ns_userRect = result;
5954       maximized_height = result.size.height = defaultFrame.size.height;
5955       maximized_width = -1;
5956       result.origin.y = defaultFrame.origin.y;
5957       [self setFSValue: FULLSCREEN_HEIGHT];
5958 #ifdef NS_IMPL_COCOA
5959       maximizing_resize = YES;
5960 #endif
5961     }
5962   else if (next_maximized == FULLSCREEN_WIDTH)
5963     {
5964       ns_userRect = result;
5965       maximized_width = result.size.width = defaultFrame.size.width;
5966       maximized_height = -1;
5967       result.origin.x = defaultFrame.origin.x;
5968       [self setFSValue: FULLSCREEN_WIDTH];
5969     }
5970   else if (next_maximized == FULLSCREEN_MAXIMIZED
5971            || (next_maximized == -1
5972                && abs (defaultFrame.size.width - result.size.width)
5973                > FRAME_COLUMN_WIDTH (emacsframe)))
5974     {
5975       result = defaultFrame;  /* second click */
5976       maximized_width = result.size.width;
5977       maximized_height = result.size.height;
5978       [self setFSValue: FULLSCREEN_MAXIMIZED];
5979 #ifdef NS_IMPL_COCOA
5980       maximizing_resize = YES;
5981 #endif
5982     }
5983   else
5984     {
5985       /* restore */
5986       result = ns_userRect.size.height ? ns_userRect : result;
5987       ns_userRect = NSMakeRect (0, 0, 0, 0);
5988 #ifdef NS_IMPL_COCOA
5989       maximizing_resize = fs_state != FULLSCREEN_NONE;
5990 #endif
5991       [self setFSValue: FULLSCREEN_NONE];
5992       maximized_width = maximized_height = -1;
5993     }
5995   if (fs_before_fs == -1) next_maximized = -1;
5996   [self windowWillResize: sender toSize: result.size];
5997   return result;
6001 - (void)windowDidDeminiaturize: sender
6003   NSTRACE (windowDidDeminiaturize);
6004   if (!emacsframe->output_data.ns)
6005     return;
6007   SET_FRAME_ICONIFIED (emacsframe, 0);
6008   SET_FRAME_VISIBLE (emacsframe, 1);
6009   windows_or_buffers_changed++;
6011   if (emacs_event)
6012     {
6013       emacs_event->kind = DEICONIFY_EVENT;
6014       EV_TRAILER ((id)nil);
6015     }
6019 - (void)windowDidExpose: sender
6021   NSTRACE (windowDidExpose);
6022   if (!emacsframe->output_data.ns)
6023     return;
6025   SET_FRAME_VISIBLE (emacsframe, 1);
6026   SET_FRAME_GARBAGED (emacsframe);
6028   if (send_appdefined)
6029     ns_send_appdefined (-1);
6033 - (void)windowDidMiniaturize: sender
6035   NSTRACE (windowDidMiniaturize);
6036   if (!emacsframe->output_data.ns)
6037     return;
6039   SET_FRAME_ICONIFIED (emacsframe, 1);
6040   SET_FRAME_VISIBLE (emacsframe, 0);
6042   if (emacs_event)
6043     {
6044       emacs_event->kind = ICONIFY_EVENT;
6045       EV_TRAILER ((id)nil);
6046     }
6049 #ifdef HAVE_NATIVE_FS
6050 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6051       willUseFullScreenPresentationOptions:
6052   (NSApplicationPresentationOptions)proposedOptions
6054   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6056 #endif
6058 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6060   fs_before_fs = fs_state;
6063 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6065   [self setFSValue: FULLSCREEN_BOTH];
6066   if (! [self fsIsNative])
6067     {
6068       [self windowDidBecomeKey:notification];
6069       [nonfs_window orderOut:self];
6070     }
6071   else if (! FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6072     [toolbar setVisible:NO];
6075 - (void)windowWillExitFullScreen:(NSNotification *)notification
6077   if (next_maximized != -1)
6078     fs_before_fs = next_maximized;
6081 - (void)windowDidExitFullScreen:(NSNotification *)notification
6083   [self setFSValue: fs_before_fs];
6084   fs_before_fs = -1;
6085 #ifdef NS_IMPL_COCOA
6086   [self updateCollectionBehaviour];
6087 #endif
6088   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6089     {
6090       [toolbar setVisible:YES];
6091       update_frame_tool_bar (emacsframe);
6092       [self updateFrameSize:YES];
6093       [[self window] display];
6094     }
6095   else
6096     [toolbar setVisible:NO];
6098   if (next_maximized != -1)
6099     [[self window] performZoom:self];
6102 - (BOOL)fsIsNative
6104   return fs_is_native;
6107 - (BOOL)isFullscreen
6109   if (! fs_is_native) return nonfs_window != nil;
6110 #ifdef HAVE_NATIVE_FS
6111   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6112 #else
6113   return NO;
6114 #endif
6117 #ifdef HAVE_NATIVE_FS
6118 - (void)updateCollectionBehaviour
6120   if (! [self isFullscreen])
6121     {
6122       NSWindow *win = [self window];
6123       NSWindowCollectionBehavior b = [win collectionBehavior];
6124       if (ns_use_native_fullscreen)
6125         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6126       else
6127         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6129       [win setCollectionBehavior: b];
6130       fs_is_native = ns_use_native_fullscreen;
6131     }
6133 #endif
6135 - (void)toggleFullScreen: (id)sender
6137   NSWindow *w, *fw;
6138   BOOL onFirstScreen;
6139   struct frame *f;
6140   NSSize sz;
6141   NSRect r, wr;
6142   NSColor *col;
6144   if (fs_is_native)
6145     {
6146 #ifdef NS_IMPL_COCOA
6147       [[self window] toggleFullScreen:sender];
6148 #endif
6149       return;
6150     }
6152   w = [self window];
6153   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6154   f = emacsframe;
6155   wr = [w frame];
6156   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6157                                  (FRAME_DEFAULT_FACE (f)),
6158                                  f);
6160   sz.width = FRAME_COLUMN_WIDTH (f);
6161   sz.height = FRAME_LINE_HEIGHT (f);
6163   if (fs_state != FULLSCREEN_BOTH)
6164     {
6165       /* Hide dock and menubar if we are on the primary screen.  */
6166       if (onFirstScreen)
6167         {
6168 #if defined (NS_IMPL_COCOA) && \
6169   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6170           NSApplicationPresentationOptions options
6171             = NSApplicationPresentationAutoHideDock
6172             | NSApplicationPresentationAutoHideMenuBar;
6174           [NSApp setPresentationOptions: options];
6175 #else
6176           [NSMenu setMenuBarVisible:NO];
6177 #endif
6178         }
6180       fw = [[EmacsFSWindow alloc]
6181                        initWithContentRect:[w contentRectForFrameRect:wr]
6182                                  styleMask:NSBorderlessWindowMask
6183                                    backing:NSBackingStoreBuffered
6184                                      defer:YES
6185                                     screen:[w screen]];
6187       [fw setContentView:[w contentView]];
6188       [fw setTitle:[w title]];
6189       [fw setDelegate:self];
6190       [fw setAcceptsMouseMovedEvents: YES];
6191       [fw useOptimizedDrawing: YES];
6192       [fw setResizeIncrements: sz];
6193       [fw setBackgroundColor: col];
6194       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6195         [fw setOpaque: NO];
6197       f->border_width = 0;
6198       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6199       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6200       FRAME_TOOLBAR_HEIGHT (f) = 0;
6202       nonfs_window = w;
6204       [self windowWillEnterFullScreen:nil];
6205       [fw makeKeyAndOrderFront:NSApp];
6206       [fw makeFirstResponder:self];
6207       [w orderOut:self];
6208       r = [fw frameRectForContentRect:[[fw screen] frame]];
6209       [fw setFrame: r display:YES animate:YES];
6210       [self windowDidEnterFullScreen:nil];
6211       [fw display];
6212     }
6213   else
6214     {
6215       fw = w;
6216       w = nonfs_window;
6217       nonfs_window = nil;
6219       if (onFirstScreen)
6220         {
6221 #if defined (NS_IMPL_COCOA) && \
6222   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6223           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6224 #else
6225           [NSMenu setMenuBarVisible:YES];
6226 #endif
6227         }
6229       [w setContentView:[fw contentView]];
6230       [w setResizeIncrements: sz];
6231       [w setBackgroundColor: col];
6232       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6233         [w setOpaque: NO];
6235       f->border_width = bwidth;
6236       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6237       if (FRAME_EXTERNAL_TOOL_BAR (f))
6238         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6240       [self windowWillExitFullScreen:nil];
6241       [fw setFrame: [w frame] display:YES animate:YES];
6242       [fw close];
6243       [w makeKeyAndOrderFront:NSApp];
6244       [self windowDidExitFullScreen:nil];
6245       [self updateFrameSize:YES];
6246     }
6249 - (void)handleFS
6251   if (fs_state != emacsframe->want_fullscreen)
6252     {
6253       if (fs_state == FULLSCREEN_BOTH)
6254         {
6255           [self toggleFullScreen:self];
6256         }
6258       switch (emacsframe->want_fullscreen)
6259         {
6260         case FULLSCREEN_BOTH:
6261           [self toggleFullScreen:self];
6262           break;
6263         case FULLSCREEN_WIDTH:
6264           next_maximized = FULLSCREEN_WIDTH;
6265           if (fs_state != FULLSCREEN_BOTH)
6266             [[self window] performZoom:self];
6267           break;
6268         case FULLSCREEN_HEIGHT:
6269           next_maximized = FULLSCREEN_HEIGHT;
6270           if (fs_state != FULLSCREEN_BOTH)
6271             [[self window] performZoom:self];
6272           break;
6273         case FULLSCREEN_MAXIMIZED:
6274           next_maximized = FULLSCREEN_MAXIMIZED;
6275           if (fs_state != FULLSCREEN_BOTH)
6276             [[self window] performZoom:self];
6277           break;
6278         case FULLSCREEN_NONE:
6279           if (fs_state != FULLSCREEN_BOTH)
6280             {
6281               next_maximized = FULLSCREEN_NONE;
6282               [[self window] performZoom:self];
6283             }
6284           break;
6285         }
6287       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6288     }
6292 - (void) setFSValue: (int)value
6294   Lisp_Object lval = Qnil;
6295   switch (value)
6296     {
6297     case FULLSCREEN_BOTH:
6298       lval = Qfullboth;
6299       break;
6300     case FULLSCREEN_WIDTH:
6301       lval = Qfullwidth;
6302       break;
6303     case FULLSCREEN_HEIGHT:
6304       lval = Qfullheight;
6305       break;
6306     case FULLSCREEN_MAXIMIZED:
6307       lval = Qmaximized;
6308       break;
6309     }
6310   store_frame_param (emacsframe, Qfullscreen, lval);
6311   fs_state = value;
6314 - (void)mouseEntered: (NSEvent *)theEvent
6316   NSTRACE (mouseEntered);
6317   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6321 - (void)mouseExited: (NSEvent *)theEvent
6323   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6325   NSTRACE (mouseExited);
6327   if (!hlinfo)
6328     return;
6330   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6332   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6333     {
6334       clear_mouse_face (hlinfo);
6335       hlinfo->mouse_face_mouse_frame = 0;
6336     }
6340 - menuDown: sender
6342   NSTRACE (menuDown);
6343   if (context_menu_value == -1)
6344     context_menu_value = [sender tag];
6345   else
6346     {
6347       NSInteger tag = [sender tag];
6348       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6349                                     emacsframe->menu_bar_vector,
6350                                     (void *)tag);
6351     }
6353   ns_send_appdefined (-1);
6354   return self;
6358 - (EmacsToolbar *)toolbar
6360   return toolbar;
6364 /* this gets called on toolbar button click */
6365 - toolbarClicked: (id)item
6367   NSEvent *theEvent;
6368   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6370   NSTRACE (toolbarClicked);
6372   if (!emacs_event)
6373     return self;
6375   /* send first event (for some reason two needed) */
6376   theEvent = [[self window] currentEvent];
6377   emacs_event->kind = TOOL_BAR_EVENT;
6378   XSETFRAME (emacs_event->arg, emacsframe);
6379   EV_TRAILER (theEvent);
6381   emacs_event->kind = TOOL_BAR_EVENT;
6382 /*   XSETINT (emacs_event->code, 0); */
6383   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6384                            idx + TOOL_BAR_ITEM_KEY);
6385   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6386   EV_TRAILER (theEvent);
6387   return self;
6391 - toggleToolbar: (id)sender
6393   if (!emacs_event)
6394     return self;
6396   emacs_event->kind = NS_NONKEY_EVENT;
6397   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6398   EV_TRAILER ((id)nil);
6399   return self;
6403 - (void)drawRect: (NSRect)rect
6405   int x = NSMinX (rect), y = NSMinY (rect);
6406   int width = NSWidth (rect), height = NSHeight (rect);
6408   NSTRACE (drawRect);
6410   if (!emacsframe || !emacsframe->output_data.ns)
6411     return;
6413   ns_clear_frame_area (emacsframe, x, y, width, height);
6414   expose_frame (emacsframe, x, y, width, height);
6416   /*
6417     drawRect: may be called (at least in OS X 10.5) for invisible
6418     views as well for some reason.  Thus, do not infer visibility
6419     here.
6421     emacsframe->async_visible = 1;
6422     emacsframe->async_iconified = 0;
6423   */
6427 /* NSDraggingDestination protocol methods.  Actually this is not really a
6428    protocol, but a category of Object.  O well...  */
6430 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6432   NSTRACE (draggingEntered);
6433   return NSDragOperationGeneric;
6437 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6439   return YES;
6443 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6445   id pb;
6446   int x, y;
6447   NSString *type;
6448   NSEvent *theEvent = [[self window] currentEvent];
6449   NSPoint position;
6451   NSTRACE (performDragOperation);
6453   if (!emacs_event)
6454     return NO;
6456   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6457   x = lrint (position.x);  y = lrint (position.y);
6459   pb = [sender draggingPasteboard];
6460   type = [pb availableTypeFromArray: ns_drag_types];
6461   if (type == 0)
6462     {
6463       return NO;
6464     }
6465   else if ([type isEqualToString: NSFilenamesPboardType])
6466     {
6467       NSArray *files;
6468       NSEnumerator *fenum;
6469       NSString *file;
6471       if (!(files = [pb propertyListForType: type]))
6472         return NO;
6474       fenum = [files objectEnumerator];
6475       while ( (file = [fenum nextObject]) )
6476         {
6477           emacs_event->kind = NS_NONKEY_EVENT;
6478           emacs_event->code = KEY_NS_DRAG_FILE;
6479           XSETINT (emacs_event->x, x);
6480           XSETINT (emacs_event->y, y);
6481           ns_input_file = append2 (ns_input_file,
6482                                    build_string ([file UTF8String]));
6483           emacs_event->modifiers = EV_MODIFIERS (theEvent);
6484           EV_TRAILER (theEvent);
6485         }
6486       return YES;
6487     }
6488   else if ([type isEqualToString: NSURLPboardType])
6489     {
6490       NSString *file;
6491       NSURL *fileURL;
6493       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6494           [fileURL isFileURL] == NO)
6495         return NO;
6497       file = [fileURL path];
6498       emacs_event->kind = NS_NONKEY_EVENT;
6499       emacs_event->code = KEY_NS_DRAG_FILE;
6500       XSETINT (emacs_event->x, x);
6501       XSETINT (emacs_event->y, y);
6502       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6503       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6504       EV_TRAILER (theEvent);
6505       return YES;
6506     }
6507   else if ([type isEqualToString: NSStringPboardType]
6508            || [type isEqualToString: NSTabularTextPboardType])
6509     {
6510       NSString *data;
6512       if (! (data = [pb stringForType: type]))
6513         return NO;
6515       emacs_event->kind = NS_NONKEY_EVENT;
6516       emacs_event->code = KEY_NS_DRAG_TEXT;
6517       XSETINT (emacs_event->x, x);
6518       XSETINT (emacs_event->y, y);
6519       ns_input_text = build_string ([data UTF8String]);
6520       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6521       EV_TRAILER (theEvent);
6522       return YES;
6523     }
6524   else if ([type isEqualToString: NSColorPboardType])
6525     {
6526       NSColor *c = [NSColor colorFromPasteboard: pb];
6527       emacs_event->kind = NS_NONKEY_EVENT;
6528       emacs_event->code = KEY_NS_DRAG_COLOR;
6529       XSETINT (emacs_event->x, x);
6530       XSETINT (emacs_event->y, y);
6531       ns_input_color = ns_color_to_lisp (c);
6532       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6533       EV_TRAILER (theEvent);
6534       return YES;
6535     }
6536   else if ([type isEqualToString: NSFontPboardType])
6537     {
6538       /* impl based on GNUstep NSTextView.m */
6539       NSData *data = [pb dataForType: NSFontPboardType];
6540       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6541       NSFont *font = [dict objectForKey: NSFontAttributeName];
6542       char fontSize[10];
6544       if (font == nil)
6545         return NO;
6547       emacs_event->kind = NS_NONKEY_EVENT;
6548       emacs_event->code = KEY_NS_CHANGE_FONT;
6549       XSETINT (emacs_event->x, x);
6550       XSETINT (emacs_event->y, y);
6551       ns_input_font = build_string ([[font fontName] UTF8String]);
6552       snprintf (fontSize, 10, "%f", [font pointSize]);
6553       ns_input_fontsize = build_string (fontSize);
6554       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6555       EV_TRAILER (theEvent);
6556       return YES;
6557     }
6558   else
6559     {
6560       error ("Invalid data type in dragging pasteboard.");
6561       return NO;
6562     }
6566 - (id) validRequestorForSendType: (NSString *)typeSent
6567                       returnType: (NSString *)typeReturned
6569   NSTRACE (validRequestorForSendType);
6570   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6571       && typeReturned == nil)
6572     {
6573       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6574         return self;
6575     }
6577   return [super validRequestorForSendType: typeSent
6578                                returnType: typeReturned];
6582 /* The next two methods are part of NSServicesRequests informal protocol,
6583    supposedly called when a services menu item is chosen from this app.
6584    But this should not happen because we override the services menu with our
6585    own entries which call ns-perform-service.
6586    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6587    So let's at least stub them out until further investigation can be done. */
6589 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6591   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6592      be written into the buffer in place of the existing selection..
6593      ordinary service calls go through functions defined in ns-win.el */
6594   return NO;
6597 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6599   NSArray *typesDeclared;
6600   Lisp_Object val;
6602   /* We only support NSStringPboardType */
6603   if ([types containsObject:NSStringPboardType] == NO) {
6604     return NO;
6605   }
6607   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6608   if (CONSP (val) && SYMBOLP (XCAR (val)))
6609     {
6610       val = XCDR (val);
6611       if (CONSP (val) && NILP (XCDR (val)))
6612         val = XCAR (val);
6613     }
6614   if (! STRINGP (val))
6615     return NO;
6617   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6618   [pb declareTypes:typesDeclared owner:nil];
6619   ns_string_to_pasteboard (pb, val);
6620   return YES;
6624 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6625    (gives a miniaturized version of the window); currently we use the latter for
6626    frames whose active buffer doesn't correspond to any file
6627    (e.g., '*scratch*') */
6628 - setMiniwindowImage: (BOOL) setMini
6630   id image = [[self window] miniwindowImage];
6631   NSTRACE (setMiniwindowImage);
6633   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6634      about "AppleDockIconEnabled" notwithstanding, however the set message
6635      below has its effect nonetheless. */
6636   if (image != emacsframe->output_data.ns->miniimage)
6637     {
6638       if (image && [image isKindOfClass: [EmacsImage class]])
6639         [image release];
6640       [[self window] setMiniwindowImage:
6641                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6642     }
6644   return self;
6648 - (void) setRows: (int) r andColumns: (int) c
6650   rows = r;
6651   cols = c;
6654 @end  /* EmacsView */
6658 /* ==========================================================================
6660     EmacsWindow implementation
6662    ========================================================================== */
6664 @implementation EmacsWindow
6666 #ifdef NS_IMPL_COCOA
6667 - (id)accessibilityAttributeValue:(NSString *)attribute
6669   Lisp_Object str = Qnil;
6670   struct frame *f = SELECTED_FRAME ();
6671   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
6673   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6674     return NSAccessibilityTextFieldRole;
6676   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6677       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6678     {
6679       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6680     }
6681   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6682     {
6683       if (! NILP (BVAR (curbuf, mark_active)))
6684           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6686       if (NILP (str))
6687         {
6688           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6689           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6690           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6692           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6693             str = make_uninit_multibyte_string (range, byte_range);
6694           else
6695             str = make_uninit_string (range);
6696           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6697              Is this a problem?  */
6698           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6699         }
6700     }
6703   if (! NILP (str))
6704     {
6705       if (CONSP (str) && SYMBOLP (XCAR (str)))
6706         {
6707           str = XCDR (str);
6708           if (CONSP (str) && NILP (XCDR (str)))
6709             str = XCAR (str);
6710         }
6711       if (STRINGP (str))
6712         {
6713           const char *utfStr = SSDATA (str);
6714           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6715           return nsStr;
6716         }
6717     }
6719   return [super accessibilityAttributeValue:attribute];
6721 #endif /* NS_IMPL_COCOA */
6723 /* If we have multiple monitors, one above the other, we don't want to
6724    restrict the height to just one monitor.  So we override this.  */
6725 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6727   /* When making the frame visible for the first time or if there is just
6728      one screen, we want to constrain.  Other times not.  */
6729   NSUInteger nr_screens = [[NSScreen screens] count];
6730   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6731   NSTRACE (constrainFrameRect);
6733   if (nr_screens == 1)
6734     {
6735       NSRect r = [super constrainFrameRect:frameRect toScreen:screen];
6736       return r;
6737     }
6739   if (f->output_data.ns->dont_constrain
6740       || ns_menu_bar_should_be_hidden ())
6741     return frameRect;
6743   f->output_data.ns->dont_constrain = 1;
6744   return [super constrainFrameRect:frameRect toScreen:screen];
6747 @end /* EmacsWindow */
6750 @implementation EmacsFSWindow
6752 - (BOOL)canBecomeKeyWindow
6754   return YES;
6757 - (BOOL)canBecomeMainWindow
6759   return YES;
6762 @end
6764 /* ==========================================================================
6766     EmacsScroller implementation
6768    ========================================================================== */
6771 @implementation EmacsScroller
6773 /* for repeat button push */
6774 #define SCROLL_BAR_FIRST_DELAY 0.5
6775 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6777 + (CGFloat) scrollerWidth
6779   /* TODO: if we want to allow variable widths, this is the place to do it,
6780            however neither GNUstep nor Cocoa support it very well */
6781   return [NSScroller scrollerWidth];
6785 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6787   NSTRACE (EmacsScroller_initFrame);
6789   r.size.width = [EmacsScroller scrollerWidth];
6790   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6791   [self setContinuous: YES];
6792   [self setEnabled: YES];
6794   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6795      locked against the top and bottom edges, and right edge on OS X, where
6796      scrollers are on right. */
6797 #ifdef NS_IMPL_GNUSTEP
6798   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6799 #else
6800   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6801 #endif
6803   win = nwin;
6804   condemned = NO;
6805   pixel_height = NSHeight (r);
6806   if (pixel_height == 0) pixel_height = 1;
6807   min_portion = 20 / pixel_height;
6809   frame = XFRAME (XWINDOW (win)->frame);
6810   if (FRAME_LIVE_P (frame))
6811     {
6812       int i;
6813       EmacsView *view = FRAME_NS_VIEW (frame);
6814       NSView *sview = [[view window] contentView];
6815       NSArray *subs = [sview subviews];
6817       /* disable optimization stopping redraw of other scrollbars */
6818       view->scrollbarsNeedingUpdate = 0;
6819       for (i =[subs count]-1; i >= 0; i--)
6820         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6821           view->scrollbarsNeedingUpdate++;
6822       [sview addSubview: self];
6823     }
6825 /*  [self setFrame: r]; */
6827   return self;
6831 - (void)setFrame: (NSRect)newRect
6833   NSTRACE (EmacsScroller_setFrame);
6834 /*  block_input (); */
6835   pixel_height = NSHeight (newRect);
6836   if (pixel_height == 0) pixel_height = 1;
6837   min_portion = 20 / pixel_height;
6838   [super setFrame: newRect];
6839   [self display];
6840 /*  unblock_input (); */
6844 - (void)dealloc
6846   NSTRACE (EmacsScroller_dealloc);
6847   if (!NILP (win))
6848     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
6849   [super dealloc];
6853 - condemn
6855   NSTRACE (condemn);
6856   condemned =YES;
6857   return self;
6861 - reprieve
6863   NSTRACE (reprieve);
6864   condemned =NO;
6865   return self;
6869 - judge
6871   NSTRACE (judge);
6872   if (condemned)
6873     {
6874       EmacsView *view;
6875       block_input ();
6876       /* ensure other scrollbar updates after deletion */
6877       view = (EmacsView *)FRAME_NS_VIEW (frame);
6878       if (view != nil)
6879         view->scrollbarsNeedingUpdate++;
6880       [self removeFromSuperview];
6881       [self release];
6882       unblock_input ();
6883     }
6884   return self;
6888 - (void)resetCursorRects
6890   NSRect visible = [self visibleRect];
6891   NSTRACE (resetCursorRects);
6893   if (!NSIsEmptyRect (visible))
6894     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6895   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6899 - (int) checkSamePosition: (int) position portion: (int) portion
6900                     whole: (int) whole
6902   return em_position ==position && em_portion ==portion && em_whole ==whole
6903     && portion != whole; /* needed for resize empty buf */
6907 - setPosition: (int)position portion: (int)portion whole: (int)whole
6909   NSTRACE (setPosition);
6911   em_position = position;
6912   em_portion = portion;
6913   em_whole = whole;
6915   if (portion >= whole)
6916     {
6917 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6918       [self setKnobProportion: 1.0];
6919       [self setDoubleValue: 1.0];
6920 #else
6921       [self setFloatValue: 0.0 knobProportion: 1.0];
6922 #endif
6923     }
6924   else
6925     {
6926       float pos;
6927       CGFloat por;
6928       portion = max ((float)whole*min_portion/pixel_height, portion);
6929       pos = (float)position / (whole - portion);
6930       por = (CGFloat)portion/whole;
6931 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6932       [self setKnobProportion: por];
6933       [self setDoubleValue: pos];
6934 #else
6935       [self setFloatValue: pos knobProportion: por];
6936 #endif
6937     }
6939   /* Events may come here even if the event loop is not running.
6940      If we don't enter the event loop, the scroll bar will not update.
6941      So send SIGIO to ourselves.  */
6942   if (apploopnr == 0) raise (SIGIO);
6944   return self;
6947 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6948      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6949 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6950                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6952   *part = last_hit_part;
6953   *window = win;
6954   XSETINT (*y, pixel_height);
6955   if ([self floatValue] > 0.999F)
6956     XSETINT (*x, pixel_height);
6957   else
6958     XSETINT (*x, pixel_height * [self floatValue]);
6962 /* set up emacs_event */
6963 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6965   if (!emacs_event)
6966     return;
6968   emacs_event->part = last_hit_part;
6969   emacs_event->code = 0;
6970   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6971   emacs_event->frame_or_window = win;
6972   emacs_event->timestamp = EV_TIMESTAMP (e);
6973   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6974   emacs_event->arg = Qnil;
6975   XSETINT (emacs_event->x, loc * pixel_height);
6976   XSETINT (emacs_event->y, pixel_height-20);
6978   if (q_event_ptr)
6979     {
6980       n_emacs_events_pending++;
6981       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6982     }
6983   else
6984     hold_event (emacs_event);
6985   EVENT_INIT (*emacs_event);
6986   ns_send_appdefined (-1);
6990 /* called manually thru timer to implement repeated button action w/hold-down */
6991 - repeatScroll: (NSTimer *)scrollEntry
6993   NSEvent *e = [[self window] currentEvent];
6994   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6995   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6997   /* clear timer if need be */
6998   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6999     {
7000         [scroll_repeat_entry invalidate];
7001         [scroll_repeat_entry release];
7002         scroll_repeat_entry = nil;
7004         if (inKnob)
7005           return self;
7007         scroll_repeat_entry
7008           = [[NSTimer scheduledTimerWithTimeInterval:
7009                         SCROLL_BAR_CONTINUOUS_DELAY
7010                                             target: self
7011                                           selector: @selector (repeatScroll:)
7012                                           userInfo: 0
7013                                            repeats: YES]
7014               retain];
7015     }
7017   [self sendScrollEventAtLoc: 0 fromEvent: e];
7018   return self;
7022 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
7023    mouseDragged events without going into a modal loop. */
7024 - (void)mouseDown: (NSEvent *)e
7026   NSRect sr, kr;
7027   /* hitPart is only updated AFTER event is passed on */
7028   NSScrollerPart part = [self testPart: [e locationInWindow]];
7029   CGFloat inc = 0.0, loc, kloc, pos;
7030   int edge = 0;
7032   NSTRACE (EmacsScroller_mouseDown);
7034   switch (part)
7035     {
7036     case NSScrollerDecrementPage:
7037         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7038     case NSScrollerIncrementPage:
7039         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7040     case NSScrollerDecrementLine:
7041       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7042     case NSScrollerIncrementLine:
7043       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7044     case NSScrollerKnob:
7045       last_hit_part = scroll_bar_handle; break;
7046     case NSScrollerKnobSlot:  /* GNUstep-only */
7047       last_hit_part = scroll_bar_move_ratio; break;
7048     default:  /* NSScrollerNoPart? */
7049       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7050                (long) part);
7051       return;
7052     }
7054   if (inc != 0.0)
7055     {
7056       pos = 0;      /* ignored */
7058       /* set a timer to repeat, as we can't let superclass do this modally */
7059       scroll_repeat_entry
7060         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7061                                             target: self
7062                                           selector: @selector (repeatScroll:)
7063                                           userInfo: 0
7064                                            repeats: YES]
7065             retain];
7066     }
7067   else
7068     {
7069       /* handle, or on GNUstep possibly slot */
7070       NSEvent *fake_event;
7072       /* compute float loc in slot and mouse offset on knob */
7073       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7074                       toView: nil];
7075       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7076       if (loc <= 0.0)
7077         {
7078           loc = 0.0;
7079           edge = -1;
7080         }
7081       else if (loc >= NSHeight (sr))
7082         {
7083           loc = NSHeight (sr);
7084           edge = 1;
7085         }
7087       if (edge)
7088         kloc = 0.5 * edge;
7089       else
7090         {
7091           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7092                           toView: nil];
7093           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7094         }
7095       last_mouse_offset = kloc;
7097       /* if knob, tell emacs a location offset by knob pos
7098          (to indicate top of handle) */
7099       if (part == NSScrollerKnob)
7100           pos = (loc - last_mouse_offset) / NSHeight (sr);
7101       else
7102         /* else this is a slot click on GNUstep: go straight there */
7103         pos = loc / NSHeight (sr);
7105       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7106       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7107                                       location: [e locationInWindow]
7108                                  modifierFlags: [e modifierFlags]
7109                                      timestamp: [e timestamp]
7110                                   windowNumber: [e windowNumber]
7111                                        context: [e context]
7112                                    eventNumber: [e eventNumber]
7113                                     clickCount: [e clickCount]
7114                                       pressure: [e pressure]];
7115       [super mouseUp: fake_event];
7116     }
7118   if (part != NSScrollerKnob)
7119     [self sendScrollEventAtLoc: pos fromEvent: e];
7123 /* Called as we manually track scroller drags, rather than superclass. */
7124 - (void)mouseDragged: (NSEvent *)e
7126     NSRect sr;
7127     double loc, pos;
7129     NSTRACE (EmacsScroller_mouseDragged);
7131       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7132                       toView: nil];
7133       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7135       if (loc <= 0.0)
7136         {
7137           loc = 0.0;
7138         }
7139       else if (loc >= NSHeight (sr) + last_mouse_offset)
7140         {
7141           loc = NSHeight (sr) + last_mouse_offset;
7142         }
7144       pos = (loc - last_mouse_offset) / NSHeight (sr);
7145       [self sendScrollEventAtLoc: pos fromEvent: e];
7149 - (void)mouseUp: (NSEvent *)e
7151   if (scroll_repeat_entry)
7152     {
7153       [scroll_repeat_entry invalidate];
7154       [scroll_repeat_entry release];
7155       scroll_repeat_entry = nil;
7156     }
7157   last_hit_part = 0;
7161 /* treat scrollwheel events in the bar as though they were in the main window */
7162 - (void) scrollWheel: (NSEvent *)theEvent
7164   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7165   [view mouseDown: theEvent];
7168 @end  /* EmacsScroller */
7171 #ifdef NS_IMPL_GNUSTEP
7172 /* Dummy class to get rid of startup warnings.  */
7173 @implementation EmacsDocument
7175 @end
7176 #endif
7179 /* ==========================================================================
7181    Font-related functions; these used to be in nsfaces.m
7183    ========================================================================== */
7186 Lisp_Object
7187 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7189   struct font *font = XFONT_OBJECT (font_object);
7191   if (fontset < 0)
7192     fontset = fontset_from_font (font_object);
7193   FRAME_FONTSET (f) = fontset;
7195   if (FRAME_FONT (f) == font)
7196     /* This font is already set in frame F.  There's nothing more to
7197        do.  */
7198     return font_object;
7200   FRAME_FONT (f) = font;
7202   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7203   FRAME_COLUMN_WIDTH (f) = font->average_width;
7204   FRAME_LINE_HEIGHT (f) = font->height;
7206   compute_fringe_widths (f, 1);
7208   /* Compute the scroll bar width in character columns.  */
7209   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7210     {
7211       int wid = FRAME_COLUMN_WIDTH (f);
7212       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7213         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7214     }
7215   else
7216     {
7217       int wid = FRAME_COLUMN_WIDTH (f);
7218       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7219     }
7221   /* Now make the frame display the given font.  */
7222   if (FRAME_NS_WINDOW (f) != 0)
7223         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
7225   return font_object;
7229 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7230 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7231          in 1.43. */
7233 const char *
7234 ns_xlfd_to_fontname (const char *xlfd)
7235 /* --------------------------------------------------------------------------
7236     Convert an X font name (XLFD) to an NS font name.
7237     Only family is used.
7238     The string returned is temporarily allocated.
7239    -------------------------------------------------------------------------- */
7241   char *name = xmalloc (180);
7242   int i, len;
7243   const char *ret;
7245   if (!strncmp (xlfd, "--", 2))
7246     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7247   else
7248     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7250   /* stopgap for malformed XLFD input */
7251   if (strlen (name) == 0)
7252     strcpy (name, "Monaco");
7254   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7255      also uppercase after '-' or ' ' */
7256   name[0] = c_toupper (name[0]);
7257   for (len =strlen (name), i =0; i<len; i++)
7258     {
7259       if (name[i] == '$')
7260         {
7261           name[i] = '-';
7262           if (i+1<len)
7263             name[i+1] = c_toupper (name[i+1]);
7264         }
7265       else if (name[i] == '_')
7266         {
7267           name[i] = ' ';
7268           if (i+1<len)
7269             name[i+1] = c_toupper (name[i+1]);
7270         }
7271     }
7272 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7273   ret = [[NSString stringWithUTF8String: name] UTF8String];
7274   xfree (name);
7275   return ret;
7279 void
7280 syms_of_nsterm (void)
7282   NSTRACE (syms_of_nsterm);
7284   ns_antialias_threshold = 10.0;
7286   /* from 23+ we need to tell emacs what modifiers there are.. */
7287   DEFSYM (Qmodifier_value, "modifier-value");
7288   DEFSYM (Qalt, "alt");
7289   DEFSYM (Qhyper, "hyper");
7290   DEFSYM (Qmeta, "meta");
7291   DEFSYM (Qsuper, "super");
7292   DEFSYM (Qcontrol, "control");
7293   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7295   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7296   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7297   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7298   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7299   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7301   DEFVAR_LISP ("ns-input-file", ns_input_file,
7302               "The file specified in the last NS event.");
7303   ns_input_file =Qnil;
7305   DEFVAR_LISP ("ns-input-text", ns_input_text,
7306               "The data received in the last NS text drag event.");
7307   ns_input_text =Qnil;
7309   DEFVAR_LISP ("ns-working-text", ns_working_text,
7310               "String for visualizing working composition sequence.");
7311   ns_working_text =Qnil;
7313   DEFVAR_LISP ("ns-input-font", ns_input_font,
7314               "The font specified in the last NS event.");
7315   ns_input_font =Qnil;
7317   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7318               "The fontsize specified in the last NS event.");
7319   ns_input_fontsize =Qnil;
7321   DEFVAR_LISP ("ns-input-line", ns_input_line,
7322                "The line specified in the last NS event.");
7323   ns_input_line =Qnil;
7325   DEFVAR_LISP ("ns-input-color", ns_input_color,
7326                "The color specified in the last NS event.");
7327   ns_input_color =Qnil;
7329   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7330                "The service name specified in the last NS event.");
7331   ns_input_spi_name =Qnil;
7333   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7334                "The service argument specified in the last NS event.");
7335   ns_input_spi_arg =Qnil;
7337   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7338                "This variable describes the behavior of the alternate or option key.\n\
7339 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7340 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7341 at all, allowing it to be used at a lower level for accented character entry.");
7342   ns_alternate_modifier = Qmeta;
7344   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7345                "This variable describes the behavior of the right alternate or option key.\n\
7346 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7347 Set to left means be the same key as `ns-alternate-modifier'.\n\
7348 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7349 at all, allowing it to be used at a lower level for accented character entry.");
7350   ns_right_alternate_modifier = Qleft;
7352   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7353                "This variable describes the behavior of the command key.\n\
7354 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7355   ns_command_modifier = Qsuper;
7357   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7358                "This variable describes the behavior of the right command key.\n\
7359 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7360 Set to left means be the same key as `ns-command-modifier'.\n\
7361 Set to none means that the command / option key is not interpreted by Emacs\n\
7362 at all, allowing it to be used at a lower level for accented character entry.");
7363   ns_right_command_modifier = Qleft;
7365   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7366                "This variable describes the behavior of the control key.\n\
7367 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7368   ns_control_modifier = Qcontrol;
7370   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7371                "This variable describes the behavior of the right control key.\n\
7372 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7373 Set to left means be the same key as `ns-control-modifier'.\n\
7374 Set to none means that the control / option key is not interpreted by Emacs\n\
7375 at all, allowing it to be used at a lower level for accented character entry.");
7376   ns_right_control_modifier = Qleft;
7378   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7379                "This variable describes the behavior of the function key (on laptops).\n\
7380 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7381 Set to none means that the function key is not interpreted by Emacs at all,\n\
7382 allowing it to be used at a lower level for accented character entry.");
7383   ns_function_modifier = Qnone;
7385   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7386                "Non-nil (the default) means to render text antialiased.");
7387   ns_antialias_text = Qt;
7389   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7390                "Whether to confirm application quit using dialog.");
7391   ns_confirm_quit = Qnil;
7393   staticpro (&ns_display_name_list);
7394   ns_display_name_list = Qnil;
7396   staticpro (&last_mouse_motion_frame);
7397   last_mouse_motion_frame = Qnil;
7399   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7400                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7401 Only works on OSX 10.6 or later.  */);
7402   ns_auto_hide_menu_bar = Qnil;
7404   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7405      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7406 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7407 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7408 Default is t for OSX >= 10.7, nil otherwise. */);
7409 #ifdef HAVE_NATIVE_FS
7410   ns_use_native_fullscreen = YES;
7411 #else
7412   ns_use_native_fullscreen = NO;
7413 #endif
7414   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7416   /* TODO: move to common code */
7417   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7418                doc: /* Which toolkit scroll bars Emacs uses, if any.
7419 A value of nil means Emacs doesn't use toolkit scroll bars.
7420 With the X Window system, the value is a symbol describing the
7421 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7422 With MS Windows or Nextstep, the value is t.  */);
7423   Vx_toolkit_scroll_bars = Qt;
7425   DEFVAR_BOOL ("x-use-underline-position-properties",
7426                x_use_underline_position_properties,
7427      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7428 A value of nil means ignore them.  If you encounter fonts with bogus
7429 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7430 to 4.1, set this to nil. */);
7431   x_use_underline_position_properties = 0;
7433   DEFVAR_BOOL ("x-underline-at-descent-line",
7434                x_underline_at_descent_line,
7435      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7436 A value of nil means to draw the underline according to the value of the
7437 variable `x-use-underline-position-properties', which is usually at the
7438 baseline level.  The default value is nil.  */);
7439   x_underline_at_descent_line = 0;
7441   /* Tell emacs about this window system. */
7442   Fprovide (intern ("ns"), Qnil);