merge from trunk
[emacs.git] / src / nsterm.m
blob59627a3808733b050fb7a84e61cd5d1bf6a9fd36
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     EV_TRAILER2 (e);                                                    \
314   }
316 #define EV_TRAILER2(e)                                                  \
317   {                                                                     \
318       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
319       if (q_event_ptr)                                                  \
320         {                                                               \
321           n_emacs_events_pending++;                                     \
322           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
323         }                                                               \
324       else                                                              \
325         hold_event (emacs_event);                                       \
326       EVENT_INIT (*emacs_event);                                        \
327       ns_send_appdefined (-1);                                          \
328     }
330 /* TODO: get rid of need for these forward declarations */
331 static void ns_condemn_scroll_bars (struct frame *f);
332 static void ns_judge_scroll_bars (struct frame *f);
333 void x_set_frame_alpha (struct frame *f);
336 /* ==========================================================================
338     Utilities
340    ========================================================================== */
342 static void
343 hold_event (struct input_event *event)
345   if (hold_event_q.nr == hold_event_q.cap)
346     {
347       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
348       else hold_event_q.cap *= 2;
349       hold_event_q.q =
350         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
351     }
353   hold_event_q.q[hold_event_q.nr++] = *event;
354   /* Make sure ns_read_socket is called, i.e. we have input.  */
355   raise (SIGIO);
356   send_appdefined = YES;
359 static Lisp_Object
360 append2 (Lisp_Object list, Lisp_Object item)
361 /* --------------------------------------------------------------------------
362    Utility to append to a list
363    -------------------------------------------------------------------------- */
365   Lisp_Object array[2];
366   array[0] = list;
367   array[1] = list1 (item);
368   return Fnconc (2, &array[0]);
372 const char *
373 ns_etc_directory (void)
374 /* If running as a self-contained app bundle, return as a string the
375    filename of the etc directory, if present; else nil.  */
377   NSBundle *bundle = [NSBundle mainBundle];
378   NSString *resourceDir = [bundle resourcePath];
379   NSString *resourcePath;
380   NSFileManager *fileManager = [NSFileManager defaultManager];
381   BOOL isDir;
383   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
384   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
385     {
386       if (isDir) return [resourcePath UTF8String];
387     }
388   return NULL;
392 const char *
393 ns_exec_path (void)
394 /* If running as a self-contained app bundle, return as a path string
395    the filenames of the libexec and bin directories, ie libexec:bin.
396    Otherwise, return nil.
397    Normally, Emacs does not add its own bin/ directory to the PATH.
398    However, a self-contained NS build has a different layout, with
399    bin/ and libexec/ subdirectories in the directory that contains
400    Emacs.app itself.
401    We put libexec first, because init_callproc_1 uses the first
402    element to initialize exec-directory.  An alternative would be
403    for init_callproc to check for invocation-directory/libexec.
406   NSBundle *bundle = [NSBundle mainBundle];
407   NSString *resourceDir = [bundle resourcePath];
408   NSString *binDir = [bundle bundlePath];
409   NSString *resourcePath, *resourcePaths;
410   NSRange range;
411   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
412   NSFileManager *fileManager = [NSFileManager defaultManager];
413   NSArray *paths;
414   NSEnumerator *pathEnum;
415   BOOL isDir;
417   range = [resourceDir rangeOfString: @"Contents"];
418   if (range.location != NSNotFound)
419     {
420       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
421 #ifdef NS_IMPL_COCOA
422       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
423 #endif
424     }
426   paths = [binDir stringsByAppendingPaths:
427                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
428   pathEnum = [paths objectEnumerator];
429   resourcePaths = @"";
431   while ((resourcePath = [pathEnum nextObject]))
432     {
433       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
434         if (isDir)
435           {
436             if ([resourcePaths length] > 0)
437               resourcePaths
438                 = [resourcePaths stringByAppendingString: pathSeparator];
439             resourcePaths
440               = [resourcePaths stringByAppendingString: resourcePath];
441           }
442     }
443   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
445   return NULL;
449 const char *
450 ns_load_path (void)
451 /* If running as a self-contained app bundle, return as a path string
452    the filenames of the site-lisp, lisp and leim directories.
453    Ie, site-lisp:lisp:leim.  Otherwise, return nil.  */
455   NSBundle *bundle = [NSBundle mainBundle];
456   NSString *resourceDir = [bundle resourcePath];
457   NSString *resourcePath, *resourcePaths;
458   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
459   NSFileManager *fileManager = [NSFileManager defaultManager];
460   BOOL isDir;
461   NSArray *paths = [resourceDir stringsByAppendingPaths:
462                               [NSArray arrayWithObjects:
463                                          @"site-lisp", @"lisp", @"leim", nil]];
464   NSEnumerator *pathEnum = [paths objectEnumerator];
465   resourcePaths = @"";
467   /* Hack to skip site-lisp.  */
468   if (no_site_lisp) resourcePath = [pathEnum nextObject];
470   while ((resourcePath = [pathEnum nextObject]))
471     {
472       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
473         if (isDir)
474           {
475             if ([resourcePaths length] > 0)
476               resourcePaths
477                 = [resourcePaths stringByAppendingString: pathSeparator];
478             resourcePaths
479               = [resourcePaths stringByAppendingString: resourcePath];
480           }
481     }
482   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
484   return NULL;
487 static void
488 ns_timeout (int usecs)
489 /* --------------------------------------------------------------------------
490      Blocking timer utility used by ns_ring_bell
491    -------------------------------------------------------------------------- */
493   struct timespec wakeup = timespec_add (current_timespec (),
494                                          make_timespec (0, usecs * 1000));
496   /* Keep waiting until past the time wakeup.  */
497   while (1)
498     {
499       struct timespec timeout, now = current_timespec ();
500       if (timespec_cmp (wakeup, now) <= 0)
501         break;
502       timeout = timespec_sub (wakeup, now);
504       /* Try to wait that long--but we might wake up sooner.  */
505       pselect (0, NULL, NULL, NULL, &timeout, NULL);
506     }
510 void
511 ns_release_object (void *obj)
512 /* --------------------------------------------------------------------------
513     Release an object (callable from C)
514    -------------------------------------------------------------------------- */
516     [(id)obj release];
520 void
521 ns_retain_object (void *obj)
522 /* --------------------------------------------------------------------------
523     Retain an object (callable from C)
524    -------------------------------------------------------------------------- */
526     [(id)obj retain];
530 void *
531 ns_alloc_autorelease_pool (void)
532 /* --------------------------------------------------------------------------
533      Allocate a pool for temporary objects (callable from C)
534    -------------------------------------------------------------------------- */
536   return [[NSAutoreleasePool alloc] init];
540 void
541 ns_release_autorelease_pool (void *pool)
542 /* --------------------------------------------------------------------------
543      Free a pool and temporary objects it refers to (callable from C)
544    -------------------------------------------------------------------------- */
546   ns_release_object (pool);
551 /* ==========================================================================
553     Focus (clipping) and screen update
555    ========================================================================== */
558 // Window constraining
559 // -------------------
561 // To ensure that the windows are not placed under the menu bar, they
562 // are typically moved by the call-back constrainFrameRect. However,
563 // by overriding it, it's possible to inhibit this, leaving the window
564 // in it's original position.
566 // It's possible to hide the menu bar. However, technically, it's only
567 // possible to hide it when the application is active. To ensure that
568 // this work properly, the menu bar and window constraining are
569 // deferred until the application becomes active.
571 // Even though it's not possible to manually move a window above the
572 // top of the screen, it is allowed if it's done programmatically,
573 // when the menu is hidden. This allows the editable area to cover the
574 // full screen height.
576 // Test cases
577 // ----------
579 // Use the following extra files:
581 //    init.el:
582 //       ;; Hide menu and place frame slightly above the top of the screen.
583 //       (setq ns-auto-hide-menu-bar t)
584 //       (set-frame-position (selected-frame) 0 -20)
586 // Test 1:
588 //    emacs -Q -l init.el
590 //    Result: No menu bar, and the title bar should be above the screen.
592 // Test 2:
594 //    emacs -Q
596 //    Result: Menu bar visible, frame placed immediately below the menu.
599 static void
600 ns_constrain_all_frames (void)
602   Lisp_Object tail, frame;
604   FOR_EACH_FRAME (tail, frame)
605     {
606       struct frame *f = XFRAME (frame);
607       if (FRAME_NS_P (f))
608         {
609           NSView *view = FRAME_NS_VIEW (f);
610           /* This no-op will trigger the default window placing
611            * constraint system. */
612           f->output_data.ns->dont_constrain = 0;
613           [[view window] setFrameOrigin:[[view window] frame].origin];
614         }
615     }
619 /* True, if the menu bar should be hidden.  */
621 static BOOL
622 ns_menu_bar_should_be_hidden (void)
624   return !NILP (ns_auto_hide_menu_bar)
625     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
629 /* Show or hide the menu bar, based on user setting.  */
631 static void
632 ns_update_auto_hide_menu_bar (void)
634 #ifdef NS_IMPL_COCOA
635 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
636   block_input ();
638   NSTRACE (ns_update_auto_hide_menu_bar);
640   if (NSApp != nil
641       && [NSApp isActive]
642       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
643     {
644       // Note, "setPresentationOptions" triggers an error unless the
645       // application is active.
646       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
648       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
649         {
650           NSApplicationPresentationOptions options
651             = NSApplicationPresentationAutoHideDock;
653           if (menu_bar_should_be_hidden)
654             options |= NSApplicationPresentationAutoHideMenuBar;
656           [NSApp setPresentationOptions: options];
658           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
660           if (!ns_menu_bar_is_hidden)
661             {
662               ns_constrain_all_frames ();
663             }
664         }
665     }
667   unblock_input ();
668 #endif
669 #endif
673 static void
674 ns_update_begin (struct frame *f)
675 /* --------------------------------------------------------------------------
676    Prepare for a grouped sequence of drawing calls
677    external (RIF) call; whole frame, called before update_window_begin
678    -------------------------------------------------------------------------- */
680   NSView *view = FRAME_NS_VIEW (f);
681   NSTRACE (ns_update_begin);
683   ns_update_auto_hide_menu_bar ();
685   ns_updating_frame = f;
686   [view lockFocus];
688   /* drawRect may have been called for say the minibuffer, and then clip path
689      is for the minibuffer.  But the display engine may draw more because
690      we have set the frame as garbaged.  So reset clip path to the whole
691      view.  */
692 #ifdef NS_IMPL_COCOA
693   {
694     NSBezierPath *bp;
695     NSRect r = [view frame];
696     NSRect cr = [[view window] frame];
697     /* If a large frame size is set, r may be larger than the window frame
698        before constrained.  In that case don't change the clip path, as we
699        will clear in to the tool bar and title bar.  */
700     if (r.size.height
701         + FRAME_NS_TITLEBAR_HEIGHT (f)
702         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
703       {
704         bp = [[NSBezierPath bezierPathWithRect: r] retain];
705         [bp setClip];
706         [bp release];
707       }
708   }
709 #endif
711 #ifdef NS_IMPL_GNUSTEP
712   uRect = NSMakeRect (0, 0, 0, 0);
713 #endif
717 static void
718 ns_update_window_begin (struct window *w)
719 /* --------------------------------------------------------------------------
720    Prepare for a grouped sequence of drawing calls
721    external (RIF) call; for one window, called after update_begin
722    -------------------------------------------------------------------------- */
724   struct frame *f = XFRAME (WINDOW_FRAME (w));
725   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
727   NSTRACE (ns_update_window_begin);
728   w->output_cursor = w->cursor;
730   block_input ();
732   if (f == hlinfo->mouse_face_mouse_frame)
733     {
734       /* Don't do highlighting for mouse motion during the update.  */
735       hlinfo->mouse_face_defer = 1;
737         /* If the frame needs to be redrawn,
738            simply forget about any prior mouse highlighting.  */
739       if (FRAME_GARBAGED_P (f))
740         hlinfo->mouse_face_window = Qnil;
742       /* (further code for mouse faces ifdef'd out in other terms elided) */
743     }
745   unblock_input ();
749 static void
750 ns_update_window_end (struct window *w, bool cursor_on_p,
751                       bool mouse_face_overwritten_p)
752 /* --------------------------------------------------------------------------
753    Finished a grouped sequence of drawing calls
754    external (RIF) call; for one window called before update_end
755    -------------------------------------------------------------------------- */
757   /* note: this fn is nearly identical in all terms */
758   if (!w->pseudo_window_p)
759     {
760       block_input ();
762       if (cursor_on_p)
763         display_and_set_cursor (w, 1,
764                                 w->output_cursor.hpos, w->output_cursor.vpos,
765                                 w->output_cursor.x, w->output_cursor.y);
767       if (draw_window_fringes (w, 1))
768         x_draw_vertical_border (w);
770       unblock_input ();
771     }
773   /* If a row with mouse-face was overwritten, arrange for
774      frame_up_to_date to redisplay the mouse highlight.  */
775   if (mouse_face_overwritten_p)
776     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
778   NSTRACE (update_window_end);
782 static void
783 ns_update_end (struct frame *f)
784 /* --------------------------------------------------------------------------
785    Finished a grouped sequence of drawing calls
786    external (RIF) call; for whole frame, called after update_window_end
787    -------------------------------------------------------------------------- */
789   EmacsView *view = FRAME_NS_VIEW (f);
791 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
792   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
794   block_input ();
796   [view unlockFocus];
797   [[view window] flushWindow];
799   unblock_input ();
800   ns_updating_frame = NULL;
801   NSTRACE (ns_update_end);
804 static void
805 ns_focus (struct frame *f, NSRect *r, int n)
806 /* --------------------------------------------------------------------------
807    Internal: Focus on given frame.  During small local updates this is used to
808      draw, however during large updates, ns_update_begin and ns_update_end are
809      called to wrap the whole thing, in which case these calls are stubbed out.
810      Except, on GNUstep, we accumulate the rectangle being drawn into, because
811      the back end won't do this automatically, and will just end up flushing
812      the entire window.
813    -------------------------------------------------------------------------- */
815 //  NSTRACE (ns_focus);
816 /* static int c =0;
817    fprintf (stderr, "focus: %d", c++);
818    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
819    fprintf (stderr, "\n"); */
821   if (f != ns_updating_frame)
822     {
823       NSView *view = FRAME_NS_VIEW (f);
824       if (view != focus_view)
825         {
826           if (focus_view != NULL)
827             {
828               [focus_view unlockFocus];
829               [[focus_view window] flushWindow];
830 /*debug_lock--; */
831             }
833           if (view)
834             [view lockFocus];
835           focus_view = view;
836 /*if (view) debug_lock++; */
837         }
838     }
840   /* clipping */
841   if (r)
842     {
843       [[NSGraphicsContext currentContext] saveGraphicsState];
844       if (n == 2)
845         NSRectClipList (r, 2);
846       else
847         NSRectClip (*r);
848       gsaved = YES;
849     }
853 static void
854 ns_unfocus (struct frame *f)
855 /* --------------------------------------------------------------------------
856      Internal: Remove focus on given frame
857    -------------------------------------------------------------------------- */
859 //  NSTRACE (ns_unfocus);
861   if (gsaved)
862     {
863       [[NSGraphicsContext currentContext] restoreGraphicsState];
864       gsaved = NO;
865     }
867   if (f != ns_updating_frame)
868     {
869       if (focus_view != NULL)
870         {
871           [focus_view unlockFocus];
872           [[focus_view window] flushWindow];
873           focus_view = NULL;
874 /*debug_lock--; */
875         }
876     }
880 static void
881 ns_clip_to_row (struct window *w, struct glyph_row *row,
882                 enum glyph_row_area area, BOOL gc)
883 /* --------------------------------------------------------------------------
884      Internal (but parallels other terms): Focus drawing on given row
885    -------------------------------------------------------------------------- */
887   struct frame *f = XFRAME (WINDOW_FRAME (w));
888   NSRect clip_rect;
889   int window_x, window_y, window_width;
891   window_box (w, area, &window_x, &window_y, &window_width, 0);
893   clip_rect.origin.x = window_x;
894   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
895   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
896   clip_rect.size.width = window_width;
897   clip_rect.size.height = row->visible_height;
899   ns_focus (f, &clip_rect, 1);
903 static void
904 ns_ring_bell (struct frame *f)
905 /* --------------------------------------------------------------------------
906      "Beep" routine
907    -------------------------------------------------------------------------- */
909   NSTRACE (ns_ring_bell);
910   if (visible_bell)
911     {
912       NSAutoreleasePool *pool;
913       struct frame *frame = SELECTED_FRAME ();
914       NSView *view;
916       block_input ();
917       pool = [[NSAutoreleasePool alloc] init];
919       view = FRAME_NS_VIEW (frame);
920       if (view != nil)
921         {
922           NSRect r, surr;
923           NSPoint dim = NSMakePoint (128, 128);
925           r = [view bounds];
926           r.origin.x += (r.size.width - dim.x) / 2;
927           r.origin.y += (r.size.height - dim.y) / 2;
928           r.size.width = dim.x;
929           r.size.height = dim.y;
930           surr = NSInsetRect (r, -2, -2);
931           ns_focus (frame, &surr, 1);
932           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
933           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
934                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
935           NSRectFill (r);
936           [[view window] flushWindow];
937           ns_timeout (150000);
938           [[view window] restoreCachedImage];
939           [[view window] flushWindow];
940           ns_unfocus (frame);
941         }
942       [pool release];
943       unblock_input ();
944     }
945   else
946     {
947       NSBeep ();
948     }
951 /* ==========================================================================
953     Frame / window manager related functions
955    ========================================================================== */
958 static void
959 ns_raise_frame (struct frame *f)
960 /* --------------------------------------------------------------------------
961      Bring window to foreground and make it active
962    -------------------------------------------------------------------------- */
964   NSView *view;
965   check_window_system (f);
966   view = FRAME_NS_VIEW (f);
967   block_input ();
968   if (FRAME_VISIBLE_P (f))
969     [[view window] makeKeyAndOrderFront: NSApp];
970   unblock_input ();
974 static void
975 ns_lower_frame (struct frame *f)
976 /* --------------------------------------------------------------------------
977      Send window to back
978    -------------------------------------------------------------------------- */
980   NSView *view;
981   check_window_system (f);
982   view = FRAME_NS_VIEW (f);
983   block_input ();
984   [[view window] orderBack: NSApp];
985   unblock_input ();
989 static void
990 ns_frame_raise_lower (struct frame *f, int raise)
991 /* --------------------------------------------------------------------------
992      External (hook)
993    -------------------------------------------------------------------------- */
995   NSTRACE (ns_frame_raise_lower);
997   if (raise)
998     ns_raise_frame (f);
999   else
1000     ns_lower_frame (f);
1004 static void
1005 ns_frame_rehighlight (struct frame *frame)
1006 /* --------------------------------------------------------------------------
1007      External (hook): called on things like window switching within frame
1008    -------------------------------------------------------------------------- */
1010   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1011   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1013   NSTRACE (ns_frame_rehighlight);
1014   if (dpyinfo->x_focus_frame)
1015     {
1016       dpyinfo->x_highlight_frame
1017         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1018            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1019            : dpyinfo->x_focus_frame);
1020       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1021         {
1022           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1023           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1024         }
1025     }
1026   else
1027       dpyinfo->x_highlight_frame = 0;
1029   if (dpyinfo->x_highlight_frame &&
1030          dpyinfo->x_highlight_frame != old_highlight)
1031     {
1032       if (old_highlight)
1033         {
1034           x_update_cursor (old_highlight, 1);
1035           x_set_frame_alpha (old_highlight);
1036         }
1037       if (dpyinfo->x_highlight_frame)
1038         {
1039           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1040           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1041         }
1042     }
1046 void
1047 x_make_frame_visible (struct frame *f)
1048 /* --------------------------------------------------------------------------
1049      External: Show the window (X11 semantics)
1050    -------------------------------------------------------------------------- */
1052   NSTRACE (x_make_frame_visible);
1053   /* XXX: at some points in past this was not needed, as the only place that
1054      called this (frame.c:Fraise_frame ()) also called raise_lower;
1055      if this ends up the case again, comment this out again. */
1056   if (!FRAME_VISIBLE_P (f))
1057     {
1058       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1060       SET_FRAME_VISIBLE (f, 1);
1061       ns_raise_frame (f);
1063       /* Making a new frame from a fullscreen frame will make the new frame
1064          fullscreen also.  So skip handleFS as this will print an error.  */
1065       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1066           && [view isFullscreen])
1067         return;
1069       if (f->want_fullscreen != FULLSCREEN_NONE)
1070         {
1071           block_input ();
1072           [view handleFS];
1073           unblock_input ();
1074         }
1075     }
1079 void
1080 x_make_frame_invisible (struct frame *f)
1081 /* --------------------------------------------------------------------------
1082      External: Hide the window (X11 semantics)
1083    -------------------------------------------------------------------------- */
1085   NSView *view;
1086   NSTRACE (x_make_frame_invisible);
1087   check_window_system (f);
1088   view = FRAME_NS_VIEW (f);
1089   [[view window] orderOut: NSApp];
1090   SET_FRAME_VISIBLE (f, 0);
1091   SET_FRAME_ICONIFIED (f, 0);
1095 void
1096 x_iconify_frame (struct frame *f)
1097 /* --------------------------------------------------------------------------
1098      External: Iconify window
1099    -------------------------------------------------------------------------- */
1101   NSView *view;
1102   struct ns_display_info *dpyinfo;
1104   NSTRACE (x_iconify_frame);
1105   check_window_system (f);
1106   view = FRAME_NS_VIEW (f);
1107   dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1109   if (dpyinfo->x_highlight_frame == f)
1110     dpyinfo->x_highlight_frame = 0;
1112   if ([[view window] windowNumber] <= 0)
1113     {
1114       /* the window is still deferred.  Make it very small, bring it
1115          on screen and order it out. */
1116       NSRect s = { { 100, 100}, {0, 0} };
1117       NSRect t;
1118       t = [[view window] frame];
1119       [[view window] setFrame: s display: NO];
1120       [[view window] orderBack: NSApp];
1121       [[view window] orderOut: NSApp];
1122       [[view window] setFrame: t display: NO];
1123     }
1124   [[view window] miniaturize: NSApp];
1127 /* Free X resources of frame F.  */
1129 void
1130 x_free_frame_resources (struct frame *f)
1132   NSView *view;
1133   struct ns_display_info *dpyinfo;
1134   Mouse_HLInfo *hlinfo;
1136   NSTRACE (x_free_frame_resources);
1137   check_window_system (f);
1138   view = FRAME_NS_VIEW (f);
1139   dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1140   hlinfo = MOUSE_HL_INFO (f);
1142   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1144   block_input ();
1146   free_frame_menubar (f);
1148   if (FRAME_FACE_CACHE (f))
1149     free_frame_faces (f);
1151   if (f == dpyinfo->x_focus_frame)
1152     dpyinfo->x_focus_frame = 0;
1153   if (f == dpyinfo->x_highlight_frame)
1154     dpyinfo->x_highlight_frame = 0;
1155   if (f == hlinfo->mouse_face_mouse_frame)
1156     reset_mouse_highlight (hlinfo);
1158   if (f->output_data.ns->miniimage != nil)
1159     [f->output_data.ns->miniimage release];
1161   [[view window] close];
1162   [view release];
1164   xfree (f->output_data.ns);
1166   unblock_input ();
1169 void
1170 x_destroy_window (struct frame *f)
1171 /* --------------------------------------------------------------------------
1172      External: Delete the window
1173    -------------------------------------------------------------------------- */
1175   NSTRACE (x_destroy_window);
1176   check_window_system (f);
1177   x_free_frame_resources (f);
1178   ns_window_num--;
1182 void
1183 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1184 /* --------------------------------------------------------------------------
1185      External: Position the window
1186    -------------------------------------------------------------------------- */
1188   NSView *view = FRAME_NS_VIEW (f);
1189   NSArray *screens = [NSScreen screens];
1190   NSScreen *fscreen = [screens objectAtIndex: 0];
1191   NSScreen *screen = [[view window] screen];
1193   NSTRACE (x_set_offset);
1195   block_input ();
1197   f->left_pos = xoff;
1198   f->top_pos = yoff;
1200   if (view != nil && screen && fscreen)
1201     {
1202       f->left_pos = f->size_hint_flags & XNegative
1203         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1204         : f->left_pos;
1205       /* We use visibleFrame here to take menu bar into account.
1206          Ideally we should also adjust left/top with visibleFrame.origin.  */
1208       f->top_pos = f->size_hint_flags & YNegative
1209         ? ([screen visibleFrame].size.height + f->top_pos
1210            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1211            - FRAME_TOOLBAR_HEIGHT (f))
1212         : f->top_pos;
1213 #ifdef NS_IMPL_GNUSTEP
1214       if (f->left_pos < 100)
1215         f->left_pos = 100;  /* don't overlap menu */
1216 #endif
1217       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1218          menu bar.  */
1219       f->output_data.ns->dont_constrain = 0;
1220       [[view window] setFrameTopLeftPoint:
1221                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1222                                     SCREENMAXBOUND ([fscreen frame].size.height
1223                                                     - NS_TOP_POS (f)))];
1224       f->size_hint_flags &= ~(XNegative|YNegative);
1225     }
1227   unblock_input ();
1231 void
1232 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1233 /* --------------------------------------------------------------------------
1234      Adjust window pixel size based on given character grid size
1235      Impl is a bit more complex than other terms, need to do some
1236      internal clipping.
1237    -------------------------------------------------------------------------- */
1239   EmacsView *view = FRAME_NS_VIEW (f);
1240   NSWindow *window = [view window];
1241   NSRect wr = [window frame];
1242   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1243   int pixelwidth, pixelheight;
1245   NSTRACE (x_set_window_size);
1247   if (view == nil)
1248     return;
1250 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1252   block_input ();
1254   check_frame_size (f, &rows, &cols);
1256   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1257   compute_fringe_widths (f, 0);
1259   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1260   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1262   /* If we have a toolbar, take its height into account. */
1263   if (tb && ! [view isFullscreen])
1264     {
1265     /* NOTE: previously this would generate wrong result if toolbar not
1266              yet displayed and fixing toolbar_height=32 helped, but
1267              now (200903) seems no longer needed */
1268     FRAME_TOOLBAR_HEIGHT (f) =
1269       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1270         - FRAME_NS_TITLEBAR_HEIGHT (f);
1271 #ifdef NS_IMPL_GNUSTEP
1272       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1273 #endif
1274     }
1275   else
1276     FRAME_TOOLBAR_HEIGHT (f) = 0;
1278   wr.size.width = pixelwidth + f->border_width;
1279   wr.size.height = pixelheight;
1280   if (! [view isFullscreen])
1281     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1282       + FRAME_TOOLBAR_HEIGHT (f);
1284   /* Do not try to constrain to this screen.  We may have multiple
1285      screens, and want Emacs to span those.  Constraining to screen
1286      prevents that, and that is not nice to the user.  */
1287  if (f->output_data.ns->zooming)
1288    f->output_data.ns->zooming = 0;
1289  else
1290    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1292   [view setRows: rows andColumns: cols];
1293   [window setFrame: wr display: YES];
1295 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1297   /* This is a trick to compensate for Emacs' managing the scrollbar area
1298      as a fixed number of standard character columns.  Instead of leaving
1299      blank space for the extra, we chopped it off above.  Now for
1300      left-hand scrollbars, we shift all rendering to the left by the
1301      difference between the real width and Emacs' imagined one.  For
1302      right-hand bars, don't worry about it since the extra is never used.
1303      (Obviously doesn't work for vertically split windows tho..) */
1304   {
1305     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1306       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1307                      - NS_SCROLL_BAR_WIDTH (f), 0)
1308       : NSMakePoint (0, 0);
1309     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1310     [view setBoundsOrigin: origin];
1311   }
1313   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1314   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1315   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1316 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1318   mark_window_cursors_off (XWINDOW (f->root_window));
1319   cancel_mouse_face (f);
1321   unblock_input ();
1325 static void
1326 ns_fullscreen_hook (struct frame *f)
1328   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1330   if (!FRAME_VISIBLE_P (f))
1331     return;
1333    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1334     {
1335       /* Old style fs don't initiate correctly if created from
1336          init/default-frame alist, so use a timer (not nice...).
1337       */
1338       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1339                                      selector: @selector (handleFS)
1340                                      userInfo: nil repeats: NO];
1341       return;
1342     }
1344   block_input ();
1345   [view handleFS];
1346   unblock_input ();
1349 /* ==========================================================================
1351     Color management
1353    ========================================================================== */
1356 NSColor *
1357 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1359   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1360   if (idx < 1 || idx >= color_table->avail)
1361     return nil;
1362   return color_table->colors[idx];
1366 unsigned long
1367 ns_index_color (NSColor *color, struct frame *f)
1369   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1370   ptrdiff_t idx;
1371   ptrdiff_t i;
1373   if (!color_table->colors)
1374     {
1375       color_table->size = NS_COLOR_CAPACITY;
1376       color_table->avail = 1; /* skip idx=0 as marker */
1377       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1378       color_table->colors[0] = nil;
1379       color_table->empty_indices = [[NSMutableSet alloc] init];
1380     }
1382   /* do we already have this color ? */
1383   for (i = 1; i < color_table->avail; i++)
1384     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1385       return i;
1387   if ([color_table->empty_indices count] > 0)
1388     {
1389       NSNumber *index = [color_table->empty_indices anyObject];
1390       [color_table->empty_indices removeObject: index];
1391       idx = [index unsignedLongValue];
1392     }
1393   else
1394     {
1395       if (color_table->avail == color_table->size)
1396         color_table->colors =
1397           xpalloc (color_table->colors, &color_table->size, 1,
1398                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1399       idx = color_table->avail++;
1400     }
1402   color_table->colors[idx] = color;
1403   [color retain];
1404 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1405   return idx;
1409 void
1410 ns_free_indexed_color (unsigned long idx, struct frame *f)
1412   struct ns_color_table *color_table;
1413   NSColor *color;
1414   NSNumber *index;
1416   if (!f)
1417     return;
1419   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1421   if (idx <= 0 || idx >= color_table->size) {
1422     message1 ("ns_free_indexed_color: Color index out of range.\n");
1423     return;
1424   }
1426   index = [NSNumber numberWithUnsignedInt: idx];
1427   if ([color_table->empty_indices containsObject: index]) {
1428     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1429     return;
1430   }
1432   color = color_table->colors[idx];
1433   [color release];
1434   color_table->colors[idx] = nil;
1435   [color_table->empty_indices addObject: index];
1436 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1440 static int
1441 ns_get_color (const char *name, NSColor **col)
1442 /* --------------------------------------------------------------------------
1443      Parse a color name
1444    -------------------------------------------------------------------------- */
1445 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1446    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1447    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1449   NSColor *new = nil;
1450   static char hex[20];
1451   int scaling;
1452   float r = -1.0, g, b;
1453   NSString *nsname = [NSString stringWithUTF8String: name];
1455 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1456   block_input ();
1458   if ([nsname isEqualToString: @"ns_selection_color"])
1459     {
1460       nsname = ns_selection_color;
1461       name = [ns_selection_color UTF8String];
1462     }
1464   /* First, check for some sort of numeric specification. */
1465   hex[0] = '\0';
1467   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1468     {
1469       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1470       [scanner scanFloat: &r];
1471       [scanner scanFloat: &g];
1472       [scanner scanFloat: &b];
1473     }
1474   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1475     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1476   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1477     {
1478       int len = (strlen(name) - 1);
1479       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1480       int i;
1481       scaling = strlen(name+start) / 3;
1482       for (i = 0; i < 3; i++)
1483         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1484                  name + start + i * scaling);
1485       hex[3 * (scaling + 1) - 1] = '\0';
1486     }
1488   if (hex[0])
1489     {
1490       int rr, gg, bb;
1491       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1492       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1493         {
1494           r = rr / fscale;
1495           g = gg / fscale;
1496           b = bb / fscale;
1497         }
1498     }
1500   if (r >= 0.0F)
1501     {
1502       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1503       unblock_input ();
1504       return 0;
1505     }
1507   /* Otherwise, color is expected to be from a list */
1508   {
1509     NSEnumerator *lenum, *cenum;
1510     NSString *name;
1511     NSColorList *clist;
1513 #ifdef NS_IMPL_GNUSTEP
1514     /* XXX: who is wrong, the requestor or the implementation? */
1515     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1516         == NSOrderedSame)
1517       nsname = @"highlightColor";
1518 #endif
1520     lenum = [[NSColorList availableColorLists] objectEnumerator];
1521     while ( (clist = [lenum nextObject]) && new == nil)
1522       {
1523         cenum = [[clist allKeys] objectEnumerator];
1524         while ( (name = [cenum nextObject]) && new == nil )
1525           {
1526             if ([name compare: nsname
1527                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1528               new = [clist colorWithKey: name];
1529           }
1530       }
1531   }
1533   if (new)
1534     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1535   unblock_input ();
1536   return new ? 0 : 1;
1541 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1542 /* --------------------------------------------------------------------------
1543      Convert a Lisp string object to a NS color
1544    -------------------------------------------------------------------------- */
1546   NSTRACE (ns_lisp_to_color);
1547   if (STRINGP (color))
1548     return ns_get_color (SSDATA (color), col);
1549   else if (SYMBOLP (color))
1550     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1551   return 1;
1555 Lisp_Object
1556 ns_color_to_lisp (NSColor *col)
1557 /* --------------------------------------------------------------------------
1558      Convert a color to a lisp string with the RGB equivalent
1559    -------------------------------------------------------------------------- */
1561   EmacsCGFloat red, green, blue, alpha, gray;
1562   char buf[1024];
1563   const char *str;
1564   NSTRACE (ns_color_to_lisp);
1566   block_input ();
1567   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1569       if ((str =[[col colorNameComponent] UTF8String]))
1570         {
1571           unblock_input ();
1572           return build_string ((char *)str);
1573         }
1575     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1576         getRed: &red green: &green blue: &blue alpha: &alpha];
1577   if (red ==green && red ==blue)
1578     {
1579       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1580             getWhite: &gray alpha: &alpha];
1581       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1582                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1583       unblock_input ();
1584       return build_string (buf);
1585     }
1587   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1588             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1590   unblock_input ();
1591   return build_string (buf);
1595 void
1596 ns_query_color(void *col, XColor *color_def, int setPixel)
1597 /* --------------------------------------------------------------------------
1598          Get ARGB values out of NSColor col and put them into color_def.
1599          If setPixel, set the pixel to a concatenated version.
1600          and set color_def pixel to the resulting index.
1601    -------------------------------------------------------------------------- */
1603   EmacsCGFloat r, g, b, a;
1605   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1606   color_def->red   = r * 65535;
1607   color_def->green = g * 65535;
1608   color_def->blue  = b * 65535;
1610   if (setPixel == YES)
1611     color_def->pixel
1612       = ARGB_TO_ULONG((int)(a*255),
1613                       (int)(r*255), (int)(g*255), (int)(b*255));
1617 bool
1618 ns_defined_color (struct frame *f,
1619                   const char *name,
1620                   XColor *color_def,
1621                   bool alloc,
1622                   bool makeIndex)
1623 /* --------------------------------------------------------------------------
1624          Return true if named color found, and set color_def rgb accordingly.
1625          If makeIndex and alloc are nonzero put the color in the color_table,
1626          and set color_def pixel to the resulting index.
1627          If makeIndex is zero, set color_def pixel to ARGB.
1628          Return false if not found
1629    -------------------------------------------------------------------------- */
1631   NSColor *col;
1632   NSTRACE (ns_defined_color);
1634   block_input ();
1635   if (ns_get_color (name, &col) != 0) /* Color not found  */
1636     {
1637       unblock_input ();
1638       return 0;
1639     }
1640   if (makeIndex && alloc)
1641     color_def->pixel = ns_index_color (col, f);
1642   ns_query_color (col, color_def, !makeIndex);
1643   unblock_input ();
1644   return 1;
1648 void
1649 x_set_frame_alpha (struct frame *f)
1650 /* --------------------------------------------------------------------------
1651      change the entire-frame transparency
1652    -------------------------------------------------------------------------- */
1654   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1655   double alpha = 1.0;
1656   double alpha_min = 1.0;
1658   if (dpyinfo->x_highlight_frame == f)
1659     alpha = f->alpha[0];
1660   else
1661     alpha = f->alpha[1];
1663   if (FLOATP (Vframe_alpha_lower_limit))
1664     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1665   else if (INTEGERP (Vframe_alpha_lower_limit))
1666     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1668   if (alpha < 0.0)
1669     return;
1670   else if (1.0 < alpha)
1671     alpha = 1.0;
1672   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1673     alpha = alpha_min;
1675 #ifdef NS_IMPL_COCOA
1676   {
1677     EmacsView *view = FRAME_NS_VIEW (f);
1678   [[view window] setAlphaValue: alpha];
1679   }
1680 #endif
1684 /* ==========================================================================
1686     Mouse handling
1688    ========================================================================== */
1691 void
1692 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1693 /* --------------------------------------------------------------------------
1694      Programmatically reposition mouse pointer in pixel coordinates
1695    -------------------------------------------------------------------------- */
1697   NSTRACE (x_set_mouse_pixel_position);
1698   ns_raise_frame (f);
1699 #if 0
1700   /* FIXME: this does not work, and what about GNUstep? */
1701 #ifdef NS_IMPL_COCOA
1702   [FRAME_NS_VIEW (f) lockFocus];
1703   PSsetmouse ((float)pix_x, (float)pix_y);
1704   [FRAME_NS_VIEW (f) unlockFocus];
1705 #endif
1706 #endif
1710 void
1711 x_set_mouse_position (struct frame *f, int h, int v)
1712 /* --------------------------------------------------------------------------
1713      Programmatically reposition mouse pointer in character coordinates
1714    -------------------------------------------------------------------------- */
1716   int pix_x, pix_y;
1718   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1719   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1721   if (pix_x < 0) pix_x = 0;
1722   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1724   if (pix_y < 0) pix_y = 0;
1725   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1727   x_set_mouse_pixel_position (f, pix_x, pix_y);
1731 static int
1732 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1733 /*   ------------------------------------------------------------------------
1734      Called by EmacsView on mouseMovement events.  Passes on
1735      to emacs mainstream code if we moved off of a rect of interest
1736      known as last_mouse_glyph.
1737      ------------------------------------------------------------------------ */
1739 //  NSTRACE (note_mouse_movement);
1741   XSETFRAME (last_mouse_motion_frame, frame);
1743   /* Note, this doesn't get called for enter/leave, since we don't have a
1744      position.  Those are taken care of in the corresponding NSView methods. */
1746   /* has movement gone beyond last rect we were tracking? */
1747   if (x < last_mouse_glyph.origin.x ||
1748       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1749       y < last_mouse_glyph.origin.y ||
1750       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1751     {
1752       ns_update_begin(frame);
1753       frame->mouse_moved = 1;
1754       note_mouse_highlight (frame, x, y);
1755       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1756       ns_update_end(frame);
1757       return 1;
1758     }
1760   return 0;
1764 static void
1765 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1766                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1767                    Time *time)
1768 /* --------------------------------------------------------------------------
1769     External (hook): inform emacs about mouse position and hit parts.
1770     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1771     x & y should be position in the scrollbar (the whole bar, not the handle)
1772     and length of scrollbar respectively
1773    -------------------------------------------------------------------------- */
1775   id view;
1776   NSPoint position;
1777   Lisp_Object frame, tail;
1778   struct frame *f;
1779   struct ns_display_info *dpyinfo;
1781   NSTRACE (ns_mouse_position);
1783   if (*fp == NULL)
1784     {
1785       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1786       return;
1787     }
1789   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1791   block_input ();
1793   if (last_mouse_scroll_bar != nil && insist == 0)
1794     {
1795       /* TODO: we do not use this path at the moment because drag events will
1796            go directly to the EmacsScroller.  Leaving code in for now. */
1797       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1798                                               x: x y: y];
1799       if (time) *time = last_mouse_movement_time;
1800       last_mouse_scroll_bar = nil;
1801     }
1802   else
1803     {
1804       /* Clear the mouse-moved flag for every frame on this display.  */
1805       FOR_EACH_FRAME (tail, frame)
1806         if (FRAME_NS_P (XFRAME (frame))
1807             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1808           XFRAME (frame)->mouse_moved = 0;
1810       last_mouse_scroll_bar = nil;
1811       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1812         f = last_mouse_frame;
1813       else
1814         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1815                                     : SELECTED_FRAME ();
1817       if (f && FRAME_NS_P (f))
1818         {
1819           view = FRAME_NS_VIEW (*fp);
1821           position = [[view window] mouseLocationOutsideOfEventStream];
1822           position = [view convertPoint: position fromView: nil];
1823           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1824 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1826           if (bar_window) *bar_window = Qnil;
1827           if (part) *part = 0; /*scroll_bar_handle; */
1829           if (x) XSETINT (*x, lrint (position.x));
1830           if (y) XSETINT (*y, lrint (position.y));
1831           if (time) *time = last_mouse_movement_time;
1832           *fp = f;
1833         }
1834     }
1836   unblock_input ();
1840 static void
1841 ns_frame_up_to_date (struct frame *f)
1842 /* --------------------------------------------------------------------------
1843     External (hook): Fix up mouse highlighting right after a full update.
1844     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1845    -------------------------------------------------------------------------- */
1847   NSTRACE (ns_frame_up_to_date);
1849   if (FRAME_NS_P (f))
1850     {
1851       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1852       if (f == hlinfo->mouse_face_mouse_frame)
1853         {
1854           block_input ();
1855           ns_update_begin(f);
1856           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1857                                 hlinfo->mouse_face_mouse_x,
1858                                 hlinfo->mouse_face_mouse_y);
1859           ns_update_end(f);
1860           unblock_input ();
1861         }
1862     }
1866 static void
1867 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1868 /* --------------------------------------------------------------------------
1869     External (RIF): set frame mouse pointer type.
1870    -------------------------------------------------------------------------- */
1872   NSTRACE (ns_define_frame_cursor);
1873   if (FRAME_POINTER_TYPE (f) != cursor)
1874     {
1875       EmacsView *view = FRAME_NS_VIEW (f);
1876       FRAME_POINTER_TYPE (f) = cursor;
1877       [[view window] invalidateCursorRectsForView: view];
1878       /* Redisplay assumes this function also draws the changed frame
1879          cursor, but this function doesn't, so do it explicitly.  */
1880       x_update_cursor (f, 1);
1881     }
1886 /* ==========================================================================
1888     Keyboard handling
1890    ========================================================================== */
1893 static unsigned
1894 ns_convert_key (unsigned code)
1895 /* --------------------------------------------------------------------------
1896     Internal call used by NSView-keyDown.
1897    -------------------------------------------------------------------------- */
1899   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1900                                 / sizeof (convert_ns_to_X_keysym[0]));
1901   unsigned keysym;
1902   /* An array would be faster, but less easy to read. */
1903   for (keysym = 0; keysym < last_keysym; keysym += 2)
1904     if (code == convert_ns_to_X_keysym[keysym])
1905       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1906   return 0;
1907 /* if decide to use keyCode and Carbon table, use this line:
1908      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1912 char *
1913 x_get_keysym_name (int keysym)
1914 /* --------------------------------------------------------------------------
1915     Called by keyboard.c.  Not sure if the return val is important, except
1916     that it be unique.
1917    -------------------------------------------------------------------------- */
1919   static char value[16];
1920   NSTRACE (x_get_keysym_name);
1921   sprintf (value, "%d", keysym);
1922   return value;
1927 /* ==========================================================================
1929     Block drawing operations
1931    ========================================================================== */
1934 static void
1935 ns_redraw_scroll_bars (struct frame *f)
1937   int i;
1938   id view;
1939   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1940   NSTRACE (ns_redraw_scroll_bars);
1941   for (i =[subviews count]-1; i >= 0; i--)
1942     {
1943       view = [subviews objectAtIndex: i];
1944       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1945       [view display];
1946     }
1950 void
1951 ns_clear_frame (struct frame *f)
1952 /* --------------------------------------------------------------------------
1953       External (hook): Erase the entire frame
1954    -------------------------------------------------------------------------- */
1956   NSView *view = FRAME_NS_VIEW (f);
1957   NSRect r;
1959   NSTRACE (ns_clear_frame);
1961  /* comes on initial frame because we have
1962     after-make-frame-functions = select-frame */
1963  if (!FRAME_DEFAULT_FACE (f))
1964    return;
1966   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1968   r = [view bounds];
1970   block_input ();
1971   ns_focus (f, &r, 1);
1972   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
1973   NSRectFill (r);
1974   ns_unfocus (f);
1976   /* as of 2006/11 or so this is now needed */
1977   ns_redraw_scroll_bars (f);
1978   unblock_input ();
1982 static void
1983 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
1984 /* --------------------------------------------------------------------------
1985     External (RIF):  Clear section of frame
1986    -------------------------------------------------------------------------- */
1988   NSRect r = NSMakeRect (x, y, width, height);
1989   NSView *view = FRAME_NS_VIEW (f);
1990   struct face *face = FRAME_DEFAULT_FACE (f);
1992   if (!view || !face)
1993     return;
1995   NSTRACE (ns_clear_frame_area);
1997   r = NSIntersectionRect (r, [view frame]);
1998   ns_focus (f, &r, 1);
1999   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2001   NSRectFill (r);
2003   ns_unfocus (f);
2004   return;
2008 static void
2009 ns_scroll_run (struct window *w, struct run *run)
2010 /* --------------------------------------------------------------------------
2011     External (RIF):  Insert or delete n lines at line vpos
2012    -------------------------------------------------------------------------- */
2014   struct frame *f = XFRAME (w->frame);
2015   int x, y, width, height, from_y, to_y, bottom_y;
2017   NSTRACE (ns_scroll_run);
2019   /* begin copy from other terms */
2020   /* Get frame-relative bounding box of the text display area of W,
2021      without mode lines.  Include in this box the left and right
2022      fringe of W.  */
2023   window_box (w, ANY_AREA, &x, &y, &width, &height);
2025   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2026   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2027   bottom_y = y + height;
2029   if (to_y < from_y)
2030     {
2031       /* Scrolling up.  Make sure we don't copy part of the mode
2032          line at the bottom.  */
2033       if (from_y + run->height > bottom_y)
2034         height = bottom_y - from_y;
2035       else
2036         height = run->height;
2037     }
2038   else
2039     {
2040       /* Scrolling down.  Make sure we don't copy over the mode line.
2041          at the bottom.  */
2042       if (to_y + run->height > bottom_y)
2043         height = bottom_y - to_y;
2044       else
2045         height = run->height;
2046     }
2047   /* end copy from other terms */
2049   if (height == 0)
2050       return;
2052   block_input ();
2054   x_clear_cursor (w);
2056   {
2057     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2058     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2059     NSPoint dstOrigin = NSMakePoint (x, to_y);
2061     ns_focus (f, &dstRect, 1);
2062     NSCopyBits (0, srcRect , dstOrigin);
2063     ns_unfocus (f);
2064   }
2066   unblock_input ();
2070 static void
2071 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2072 /* --------------------------------------------------------------------------
2073     External (RIF): preparatory to fringe update after text was updated
2074    -------------------------------------------------------------------------- */
2076   struct frame *f;
2077   int width, height;
2079   NSTRACE (ns_after_update_window_line);
2081   /* begin copy from other terms */
2082   eassert (w);
2084   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2085     desired_row->redraw_fringe_bitmaps_p = 1;
2087   /* When a window has disappeared, make sure that no rest of
2088      full-width rows stays visible in the internal border.  */
2089   if (windows_or_buffers_changed
2090       && desired_row->full_width_p
2091       && (f = XFRAME (w->frame),
2092           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2093           width != 0)
2094       && (height = desired_row->visible_height,
2095           height > 0))
2096     {
2097       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2099       block_input ();
2100       ns_clear_frame_area (f, 0, y, width, height);
2101       ns_clear_frame_area (f,
2102                            FRAME_PIXEL_WIDTH (f) - width,
2103                            y, width, height);
2104       unblock_input ();
2105     }
2109 static void
2110 ns_shift_glyphs_for_insert (struct frame *f,
2111                            int x, int y, int width, int height,
2112                            int shift_by)
2113 /* --------------------------------------------------------------------------
2114     External (RIF): copy an area horizontally, don't worry about clearing src
2115    -------------------------------------------------------------------------- */
2117   NSRect srcRect = NSMakeRect (x, y, width, height);
2118   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2119   NSPoint dstOrigin = dstRect.origin;
2121   NSTRACE (ns_shift_glyphs_for_insert);
2123   ns_focus (f, &dstRect, 1);
2124   NSCopyBits (0, srcRect, dstOrigin);
2125   ns_unfocus (f);
2130 /* ==========================================================================
2132     Character encoding and metrics
2134    ========================================================================== */
2137 static void
2138 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2139 /* --------------------------------------------------------------------------
2140      External (RIF); compute left/right overhang of whole string and set in s
2141    -------------------------------------------------------------------------- */
2143   struct font *font = s->font;
2145   if (s->char2b)
2146     {
2147       struct font_metrics metrics;
2148       unsigned int codes[2];
2149       codes[0] = *(s->char2b);
2150       codes[1] = *(s->char2b + s->nchars - 1);
2152       font->driver->text_extents (font, codes, 2, &metrics);
2153       s->left_overhang = -metrics.lbearing;
2154       s->right_overhang
2155         = metrics.rbearing > metrics.width
2156         ? metrics.rbearing - metrics.width : 0;
2157     }
2158   else
2159     {
2160       s->left_overhang = 0;
2161       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2162         FONT_HEIGHT (font) * 0.2 : 0;
2163     }
2168 /* ==========================================================================
2170     Fringe and cursor drawing
2172    ========================================================================== */
2175 extern int max_used_fringe_bitmap;
2176 static void
2177 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2178                       struct draw_fringe_bitmap_params *p)
2179 /* --------------------------------------------------------------------------
2180     External (RIF); fringe-related
2181    -------------------------------------------------------------------------- */
2183   struct frame *f = XFRAME (WINDOW_FRAME (w));
2184   struct face *face = p->face;
2185   static EmacsImage **bimgs = NULL;
2186   static int nBimgs = 0;
2188   /* grow bimgs if needed */
2189   if (nBimgs < max_used_fringe_bitmap)
2190     {
2191       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2192       memset (bimgs + nBimgs, 0,
2193               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2194       nBimgs = max_used_fringe_bitmap;
2195     }
2197   /* Must clip because of partially visible lines.  */
2198   ns_clip_to_row (w, row, ANY_AREA, YES);
2200   if (!p->overlay_p)
2201     {
2202       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2204       /* If the fringe is adjacent to the left (right) scroll bar of a
2205          leftmost (rightmost, respectively) window, then extend its
2206          background to the gap between the fringe and the bar.  */
2207       if ((WINDOW_LEFTMOST_P (w)
2208            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2209           || (WINDOW_RIGHTMOST_P (w)
2210               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2211         {
2212           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2214           if (sb_width > 0)
2215             {
2216               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2217               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2218                                     * FRAME_COLUMN_WIDTH (f));
2220               if (bx < 0)
2221                 {
2222                   /* Bitmap fills the fringe.  */
2223                   if (bar_area_x + bar_area_width == p->x)
2224                     bx = bar_area_x + sb_width;
2225                   else if (p->x + p->wd == bar_area_x)
2226                     bx = bar_area_x;
2227                   if (bx >= 0)
2228                     {
2229                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2231                       nx = bar_area_width - sb_width;
2232                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2233                                                             row->y));
2234                       ny = row->visible_height;
2235                     }
2236                 }
2237               else
2238                 {
2239                   if (bar_area_x + bar_area_width == bx)
2240                     {
2241                       bx = bar_area_x + sb_width;
2242                       nx += bar_area_width - sb_width;
2243                     }
2244                   else if (bx + nx == bar_area_x)
2245                     nx += bar_area_width - sb_width;
2246                 }
2247             }
2248         }
2250       if (bx >= 0 && nx > 0)
2251         {
2252           NSRect r = NSMakeRect (bx, by, nx, ny);
2253           NSRectClip (r);
2254           [ns_lookup_indexed_color (face->background, f) set];
2255           NSRectFill (r);
2256         }
2257     }
2259   if (p->which)
2260     {
2261       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2262       EmacsImage *img = bimgs[p->which - 1];
2264       if (!img)
2265         {
2266           unsigned short *bits = p->bits + p->dh;
2267           int len = p->h;
2268           int i;
2269           unsigned char *cbits = xmalloc (len);
2271           for (i = 0; i < len; i++)
2272             cbits[i] = ~(bits[i] & 0xff);
2273           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2274                                            flip: NO];
2275           bimgs[p->which - 1] = img;
2276           xfree (cbits);
2277         }
2279       NSRectClip (r);
2280       /* Since we composite the bitmap instead of just blitting it, we need
2281          to erase the whole background. */
2282       [ns_lookup_indexed_color(face->background, f) set];
2283       NSRectFill (r);
2284       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2285 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2286       [img drawInRect: r
2287               fromRect: NSZeroRect
2288              operation: NSCompositeSourceOver
2289               fraction: 1.0
2290            respectFlipped: YES
2291                 hints: nil];
2292 #else
2293       {
2294         NSPoint pt = r.origin;
2295         pt.y += p->h;
2296         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2297       }
2298 #endif
2299     }
2300   ns_unfocus (f);
2304 static void
2305 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2306                        int x, int y, enum text_cursor_kinds cursor_type,
2307                        int cursor_width, bool on_p, bool active_p)
2308 /* --------------------------------------------------------------------------
2309      External call (RIF): draw cursor.
2310      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2311    -------------------------------------------------------------------------- */
2313   NSRect r, s;
2314   int fx, fy, h, cursor_height;
2315   struct frame *f = WINDOW_XFRAME (w);
2316   struct glyph *phys_cursor_glyph;
2317   struct glyph *cursor_glyph;
2318   struct face *face;
2319   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2321   /* If cursor is out of bounds, don't draw garbage.  This can happen
2322      in mini-buffer windows when switching between echo area glyphs
2323      and mini-buffer.  */
2325   NSTRACE (dumpcursor);
2327   if (!on_p)
2328     return;
2330   w->phys_cursor_type = cursor_type;
2331   w->phys_cursor_on_p = on_p;
2333   if (cursor_type == NO_CURSOR)
2334     {
2335       w->phys_cursor_width = 0;
2336       return;
2337     }
2339   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2340     {
2341       if (glyph_row->exact_window_width_line_p
2342           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2343         {
2344           glyph_row->cursor_in_fringe_p = 1;
2345           draw_fringe_bitmap (w, glyph_row, 0);
2346         }
2347       return;
2348     }
2350   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2351      (other terminals do it the other way round).  We must set
2352      w->phys_cursor_width to the cursor width.  For bar cursors, that
2353      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2354   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2356   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2357      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2358   if (cursor_type == BAR_CURSOR)
2359     {
2360       if (cursor_width < 1)
2361         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2362       w->phys_cursor_width = cursor_width;
2363     }
2364   /* If we have an HBAR, "cursor_width" MAY specify height. */
2365   else if (cursor_type == HBAR_CURSOR)
2366     {
2367       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2368       fy += h - cursor_height;
2369       h = cursor_height;
2370     }
2372   r.origin.x = fx, r.origin.y = fy;
2373   r.size.height = h;
2374   r.size.width = w->phys_cursor_width;
2376   /* TODO: only needed in rare cases with last-resort font in HELLO..
2377      should we do this more efficiently? */
2378   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2381   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2382   if (face && NS_FACE_BACKGROUND (face)
2383       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2384     {
2385       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2386       hollow_color = FRAME_CURSOR_COLOR (f);
2387     }
2388   else
2389     [FRAME_CURSOR_COLOR (f) set];
2391 #ifdef NS_IMPL_COCOA
2392   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2393            atomic.  Cleaner ways of doing this should be investigated.
2394            One way would be to set a global variable DRAWING_CURSOR
2395            when making the call to draw_phys..(), don't focus in that
2396            case, then move the ns_unfocus() here after that call. */
2397   NSDisableScreenUpdates ();
2398 #endif
2400   switch (cursor_type)
2401     {
2402     case NO_CURSOR:
2403       break;
2404     case FILLED_BOX_CURSOR:
2405       NSRectFill (r);
2406       break;
2407     case HOLLOW_BOX_CURSOR:
2408       NSRectFill (r);
2409       [hollow_color set];
2410       NSRectFill (NSInsetRect (r, 1, 1));
2411       [FRAME_CURSOR_COLOR (f) set];
2412       break;
2413     case HBAR_CURSOR:
2414       NSRectFill (r);
2415       break;
2416     case BAR_CURSOR:
2417       s = r;
2418       /* If the character under cursor is R2L, draw the bar cursor
2419          on the right of its glyph, rather than on the left.  */
2420       cursor_glyph = get_phys_cursor_glyph (w);
2421       if ((cursor_glyph->resolved_level & 1) != 0)
2422         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2424       NSRectFill (s);
2425       break;
2426     }
2427   ns_unfocus (f);
2429   /* draw the character under the cursor */
2430   if (cursor_type != NO_CURSOR)
2431     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2433 #ifdef NS_IMPL_COCOA
2434   NSEnableScreenUpdates ();
2435 #endif
2440 static void
2441 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2442 /* --------------------------------------------------------------------------
2443      External (RIF): Draw a vertical line.
2444    -------------------------------------------------------------------------- */
2446   struct frame *f = XFRAME (WINDOW_FRAME (w));
2447   struct face *face;
2448   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2450   NSTRACE (ns_draw_vertical_window_border);
2452   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2453   if (face)
2454       [ns_lookup_indexed_color(face->foreground, f) set];
2456   ns_focus (f, &r, 1);
2457   NSRectFill(r);
2458   ns_unfocus (f);
2462 void
2463 show_hourglass (struct atimer *timer)
2465   if (hourglass_shown_p)
2466     return;
2468   block_input ();
2470   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2472   hourglass_shown_p = 1;
2473   unblock_input ();
2477 void
2478 hide_hourglass (void)
2480   if (!hourglass_shown_p)
2481     return;
2483   block_input ();
2485   /* TODO: remove NSProgressIndicator from all frames */
2487   hourglass_shown_p = 0;
2488   unblock_input ();
2493 /* ==========================================================================
2495     Glyph drawing operations
2497    ========================================================================== */
2499 static int
2500 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2501 /* --------------------------------------------------------------------------
2502     Wrapper utility to account for internal border width on full-width lines,
2503     and allow top full-width rows to hit the frame top.  nr should be pointer
2504     to two successive NSRects.  Number of rects actually used is returned.
2505    -------------------------------------------------------------------------- */
2507   int n = get_glyph_string_clip_rects (s, nr, 2);
2508   return n;
2511 /* --------------------------------------------------------------------
2512    Draw a wavy line under glyph string s. The wave fills wave_height
2513    pixels from y.
2515                     x          wave_length = 2
2516                                  --
2517                 y    *   *   *   *   *
2518                      |* * * * * * * * *
2519     wave_height = 3  | *   *   *   *
2520   --------------------------------------------------------------------- */
2522 static void
2523 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2525   int wave_height = 3, wave_length = 2;
2526   int y, dx, dy, odd, xmax;
2527   NSPoint a, b;
2528   NSRect waveClip;
2530   dx = wave_length;
2531   dy = wave_height - 1;
2532   y =  s->ybase - wave_height + 3;
2533   xmax = x + width;
2535   /* Find and set clipping rectangle */
2536   waveClip = NSMakeRect (x, y, width, wave_height);
2537   [[NSGraphicsContext currentContext] saveGraphicsState];
2538   NSRectClip (waveClip);
2540   /* Draw the waves */
2541   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2542   b.x = a.x + dx;
2543   odd = (int)(a.x/dx) % 2;
2544   a.y = b.y = y + 0.5;
2546   if (odd)
2547     a.y += dy;
2548   else
2549     b.y += dy;
2551   while (a.x <= xmax)
2552     {
2553       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2554       a.x = b.x, a.y = b.y;
2555       b.x += dx, b.y = y + 0.5 + odd*dy;
2556       odd = !odd;
2557     }
2559   /* Restore previous clipping rectangle(s) */
2560   [[NSGraphicsContext currentContext] restoreGraphicsState];
2565 void
2566 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2567                          NSColor *defaultCol, CGFloat width, CGFloat x)
2568 /* --------------------------------------------------------------------------
2569    Draw underline, overline, and strike-through on glyph string s.
2570    -------------------------------------------------------------------------- */
2572   if (s->for_overlaps)
2573     return;
2575   /* Do underline. */
2576   if (face->underline_p)
2577     {
2578       if (s->face->underline_type == FACE_UNDER_WAVE)
2579         {
2580           if (face->underline_defaulted_p)
2581             [defaultCol set];
2582           else
2583             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2585           ns_draw_underwave (s, width, x);
2586         }
2587       else if (s->face->underline_type == FACE_UNDER_LINE)
2588         {
2590           NSRect r;
2591           unsigned long thickness, position;
2593           /* If the prev was underlined, match its appearance. */
2594           if (s->prev && s->prev->face->underline_p
2595               && s->prev->face->underline_type == FACE_UNDER_LINE
2596               && s->prev->underline_thickness > 0)
2597             {
2598               thickness = s->prev->underline_thickness;
2599               position = s->prev->underline_position;
2600             }
2601           else
2602             {
2603               struct font *font;
2604               unsigned long descent;
2606               font=s->font;
2607               descent = s->y + s->height - s->ybase;
2609               /* Use underline thickness of font, defaulting to 1. */
2610               thickness = (font && font->underline_thickness > 0)
2611                 ? font->underline_thickness : 1;
2613               /* Determine the offset of underlining from the baseline. */
2614               if (x_underline_at_descent_line)
2615                 position = descent - thickness;
2616               else if (x_use_underline_position_properties
2617                        && font && font->underline_position >= 0)
2618                 position = font->underline_position;
2619               else if (font)
2620                 position = lround (font->descent / 2);
2621               else
2622                 position = underline_minimum_offset;
2624               position = max (position, underline_minimum_offset);
2626               /* Ensure underlining is not cropped. */
2627               if (descent <= position)
2628                 {
2629                   position = descent - 1;
2630                   thickness = 1;
2631                 }
2632               else if (descent < position + thickness)
2633                 thickness = 1;
2634             }
2636           s->underline_thickness = thickness;
2637           s->underline_position = position;
2639           r = NSMakeRect (x, s->ybase + position, width, thickness);
2641           if (face->underline_defaulted_p)
2642             [defaultCol set];
2643           else
2644             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2645           NSRectFill (r);
2646         }
2647     }
2648   /* Do overline. We follow other terms in using a thickness of 1
2649      and ignoring overline_margin. */
2650   if (face->overline_p)
2651     {
2652       NSRect r;
2653       r = NSMakeRect (x, s->y, width, 1);
2655       if (face->overline_color_defaulted_p)
2656         [defaultCol set];
2657       else
2658         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2659       NSRectFill (r);
2660     }
2662   /* Do strike-through.  We follow other terms for thickness and
2663      vertical position.*/
2664   if (face->strike_through_p)
2665     {
2666       NSRect r;
2667       unsigned long dy;
2669       dy = lrint ((s->height - 1) / 2);
2670       r = NSMakeRect (x, s->y + dy, width, 1);
2672       if (face->strike_through_color_defaulted_p)
2673         [defaultCol set];
2674       else
2675         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2676       NSRectFill (r);
2677     }
2680 static void
2681 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2682              char left_p, char right_p)
2683 /* --------------------------------------------------------------------------
2684     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2685     Note we can't just use an NSDrawRect command, because of the possibility
2686     of some sides not being drawn, and because the rect will be filled.
2687    -------------------------------------------------------------------------- */
2689   NSRect s = r;
2690   [col set];
2692   /* top, bottom */
2693   s.size.height = thickness;
2694   NSRectFill (s);
2695   s.origin.y += r.size.height - thickness;
2696   NSRectFill (s);
2698   s.size.height = r.size.height;
2699   s.origin.y = r.origin.y;
2701   /* left, right (optional) */
2702   s.size.width = thickness;
2703   if (left_p)
2704     NSRectFill (s);
2705   if (right_p)
2706     {
2707       s.origin.x += r.size.width - thickness;
2708       NSRectFill (s);
2709     }
2713 static void
2714 ns_draw_relief (NSRect r, int thickness, char raised_p,
2715                char top_p, char bottom_p, char left_p, char right_p,
2716                struct glyph_string *s)
2717 /* --------------------------------------------------------------------------
2718     Draw a relief rect inside r, optionally leaving some sides open.
2719     Note we can't just use an NSDrawBezel command, because of the possibility
2720     of some sides not being drawn, and because the rect will be filled.
2721    -------------------------------------------------------------------------- */
2723   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2724   NSColor *newBaseCol = nil;
2725   NSRect sr = r;
2727   NSTRACE (ns_draw_relief);
2729   /* set up colors */
2731   if (s->face->use_box_color_for_shadows_p)
2732     {
2733       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2734     }
2735 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2736            && s->img->pixmap
2737            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2738        {
2739          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2740        } */
2741   else
2742     {
2743       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2744     }
2746   if (newBaseCol == nil)
2747     newBaseCol = [NSColor grayColor];
2749   if (newBaseCol != baseCol)  /* TODO: better check */
2750     {
2751       [baseCol release];
2752       baseCol = [newBaseCol retain];
2753       [lightCol release];
2754       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2755       [darkCol release];
2756       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2757     }
2759   [(raised_p ? lightCol : darkCol) set];
2761   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2763   /* top */
2764   sr.size.height = thickness;
2765   if (top_p) NSRectFill (sr);
2767   /* left */
2768   sr.size.height = r.size.height;
2769   sr.size.width = thickness;
2770   if (left_p) NSRectFill (sr);
2772   [(raised_p ? darkCol : lightCol) set];
2774   /* bottom */
2775   sr.size.width = r.size.width;
2776   sr.size.height = thickness;
2777   sr.origin.y += r.size.height - thickness;
2778   if (bottom_p) NSRectFill (sr);
2780   /* right */
2781   sr.size.height = r.size.height;
2782   sr.origin.y = r.origin.y;
2783   sr.size.width = thickness;
2784   sr.origin.x += r.size.width - thickness;
2785   if (right_p) NSRectFill (sr);
2789 static void
2790 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2791 /* --------------------------------------------------------------------------
2792       Function modeled after x_draw_glyph_string_box ().
2793       Sets up parameters for drawing.
2794    -------------------------------------------------------------------------- */
2796   int right_x, last_x;
2797   char left_p, right_p;
2798   struct glyph *last_glyph;
2799   NSRect r;
2800   int thickness;
2801   struct face *face;
2803   if (s->hl == DRAW_MOUSE_FACE)
2804     {
2805       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2806       if (!face)
2807         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2808     }
2809   else
2810     face = s->face;
2812   thickness = face->box_line_width;
2814   NSTRACE (ns_dumpglyphs_box_or_relief);
2816   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2817             ? WINDOW_RIGHT_EDGE_X (s->w)
2818             : window_box_right (s->w, s->area));
2819   last_glyph = (s->cmp || s->img
2820                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2822   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2823               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2825   left_p = (s->first_glyph->left_box_line_p
2826             || (s->hl == DRAW_MOUSE_FACE
2827                 && (s->prev == NULL || s->prev->hl != s->hl)));
2828   right_p = (last_glyph->right_box_line_p
2829              || (s->hl == DRAW_MOUSE_FACE
2830                  && (s->next == NULL || s->next->hl != s->hl)));
2832   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2834   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2835   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2836     {
2837       ns_draw_box (r, abs (thickness),
2838                    ns_lookup_indexed_color (face->box_color, s->f),
2839                   left_p, right_p);
2840     }
2841   else
2842     {
2843       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2844                      1, 1, left_p, right_p, s);
2845     }
2849 static void
2850 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2851 /* --------------------------------------------------------------------------
2852       Modeled after x_draw_glyph_string_background, which draws BG in
2853       certain cases.  Others are left to the text rendering routine.
2854    -------------------------------------------------------------------------- */
2856   NSTRACE (ns_maybe_dumpglyphs_background);
2858   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2859     {
2860       int box_line_width = max (s->face->box_line_width, 0);
2861       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2862           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2863         {
2864           struct face *face;
2865           if (s->hl == DRAW_MOUSE_FACE)
2866             {
2867               face = FACE_FROM_ID (s->f,
2868                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2869               if (!face)
2870                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2871             }
2872           else
2873             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2874           if (!face->stipple)
2875             [(NS_FACE_BACKGROUND (face) != 0
2876               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2877               : FRAME_BACKGROUND_COLOR (s->f)) set];
2878           else
2879             {
2880               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2881               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2882             }
2884           if (s->hl != DRAW_CURSOR)
2885             {
2886               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2887                                     s->background_width,
2888                                     s->height-2*box_line_width);
2889               NSRectFill (r);
2890             }
2892           s->background_filled_p = 1;
2893         }
2894     }
2898 static void
2899 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2900 /* --------------------------------------------------------------------------
2901       Renders an image and associated borders.
2902    -------------------------------------------------------------------------- */
2904   EmacsImage *img = s->img->pixmap;
2905   int box_line_vwidth = max (s->face->box_line_width, 0);
2906   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2907   int bg_x, bg_y, bg_height;
2908   int th;
2909   char raised_p;
2910   NSRect br;
2911   struct face *face;
2912   NSColor *tdCol;
2914   NSTRACE (ns_dumpglyphs_image);
2916   if (s->face->box != FACE_NO_BOX
2917       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2918     x += abs (s->face->box_line_width);
2920   bg_x = x;
2921   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2922   bg_height = s->height;
2923   /* other terms have this, but was causing problems w/tabbar mode */
2924   /* - 2 * box_line_vwidth; */
2926   if (s->slice.x == 0) x += s->img->hmargin;
2927   if (s->slice.y == 0) y += s->img->vmargin;
2929   /* Draw BG: if we need larger area than image itself cleared, do that,
2930      otherwise, since we composite the image under NS (instead of mucking
2931      with its background color), we must clear just the image area. */
2932   if (s->hl == DRAW_MOUSE_FACE)
2933     {
2934       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2935       if (!face)
2936        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2937     }
2938   else
2939     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2941   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2943   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2944       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2945     {
2946       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2947       s->background_filled_p = 1;
2948     }
2949   else
2950     {
2951       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2952     }
2954   NSRectFill (br);
2956   /* Draw the image.. do we need to draw placeholder if img ==nil? */
2957   if (img != nil)
2958     {
2959 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2960       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
2961       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
2962                               s->slice.width, s->slice.height);
2963       [img drawInRect: dr
2964              fromRect: ir
2965              operation: NSCompositeSourceOver
2966               fraction: 1.0
2967            respectFlipped: YES
2968                 hints: nil];
2969 #else
2970       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
2971                   operation: NSCompositeSourceOver];
2972 #endif
2973     }
2975   if (s->hl == DRAW_CURSOR)
2976     {
2977     [FRAME_CURSOR_COLOR (s->f) set];
2978     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
2979       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
2980     else
2981       /* Currently on NS img->mask is always 0. Since
2982          get_window_cursor_type specifies a hollow box cursor when on
2983          a non-masked image we never reach this clause. But we put it
2984          in in anticipation of better support for image masks on
2985          NS. */
2986       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
2987     }
2988   else
2989     {
2990       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
2991     }
2993   /* Draw underline, overline, strike-through. */
2994   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
2996   /* Draw relief, if requested */
2997   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
2998     {
2999       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3000         {
3001           th = tool_bar_button_relief >= 0 ?
3002             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3003           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3004         }
3005       else
3006         {
3007           th = abs (s->img->relief);
3008           raised_p = (s->img->relief > 0);
3009         }
3011       r.origin.x = x - th;
3012       r.origin.y = y - th;
3013       r.size.width = s->slice.width + 2*th-1;
3014       r.size.height = s->slice.height + 2*th-1;
3015       ns_draw_relief (r, th, raised_p,
3016                       s->slice.y == 0,
3017                       s->slice.y + s->slice.height == s->img->height,
3018                       s->slice.x == 0,
3019                       s->slice.x + s->slice.width == s->img->width, s);
3020     }
3022   /* If there is no mask, the background won't be seen,
3023      so draw a rectangle on the image for the cursor.
3024      Do this for all images, getting transparency right is not reliable.  */
3025   if (s->hl == DRAW_CURSOR)
3026     {
3027       int thickness = abs (s->img->relief);
3028       if (thickness == 0) thickness = 1;
3029       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3030     }
3034 static void
3035 ns_dumpglyphs_stretch (struct glyph_string *s)
3037   NSRect r[2];
3038   int n, i;
3039   struct face *face;
3040   NSColor *fgCol, *bgCol;
3042   if (!s->background_filled_p)
3043     {
3044       n = ns_get_glyph_string_clip_rect (s, r);
3045       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3047       ns_focus (s->f, r, n);
3049       if (s->hl == DRAW_MOUSE_FACE)
3050        {
3051          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3052          if (!face)
3053            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3054        }
3055       else
3056        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3058       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3059       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3061       for (i = 0; i < n; ++i)
3062         {
3063           if (!s->row->full_width_p)
3064             {
3065               int overrun, leftoverrun;
3067               /* truncate to avoid overwriting fringe and/or scrollbar */
3068               overrun = max (0, (s->x + s->background_width)
3069                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3070                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3071               r[i].size.width -= overrun;
3073               /* truncate to avoid overwriting to left of the window box */
3074               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3075                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3077               if (leftoverrun > 0)
3078                 {
3079                   r[i].origin.x += leftoverrun;
3080                   r[i].size.width -= leftoverrun;
3081                 }
3083               /* XXX: Try to work between problem where a stretch glyph on
3084                  a partially-visible bottom row will clear part of the
3085                  modeline, and another where list-buffers headers and similar
3086                  rows erroneously have visible_height set to 0.  Not sure
3087                  where this is coming from as other terms seem not to show. */
3088               r[i].size.height = min (s->height, s->row->visible_height);
3089             }
3091           [bgCol set];
3093           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3094              overwriting cursor (usually when cursor on a tab) */
3095           if (s->hl == DRAW_CURSOR)
3096             {
3097               CGFloat x, width;
3099               x = r[i].origin.x;
3100               width = s->w->phys_cursor_width;
3101               r[i].size.width -= width;
3102               r[i].origin.x += width;
3104               NSRectFill (r[i]);
3106               /* Draw overlining, etc. on the cursor. */
3107               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3108                 ns_draw_text_decoration (s, face, bgCol, width, x);
3109               else
3110                 ns_draw_text_decoration (s, face, fgCol, width, x);
3111             }
3112           else
3113             {
3114               NSRectFill (r[i]);
3115             }
3117           /* Draw overlining, etc. on the stretch glyph (or the part
3118              of the stretch glyph after the cursor). */
3119           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3120                                    r[i].origin.x);
3121         }
3122       ns_unfocus (s->f);
3123       s->background_filled_p = 1;
3124     }
3128 static void
3129 ns_draw_glyph_string (struct glyph_string *s)
3130 /* --------------------------------------------------------------------------
3131       External (RIF): Main draw-text call.
3132    -------------------------------------------------------------------------- */
3134   /* TODO (optimize): focus for box and contents draw */
3135   NSRect r[2];
3136   int n;
3137   char box_drawn_p = 0;
3139   NSTRACE (ns_draw_glyph_string);
3141   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3142     {
3143       int width;
3144       struct glyph_string *next;
3146       for (width = 0, next = s->next;
3147            next && width < s->right_overhang;
3148            width += next->width, next = next->next)
3149         if (next->first_glyph->type != IMAGE_GLYPH)
3150           {
3151             if (next->first_glyph->type != STRETCH_GLYPH)
3152               {
3153                 n = ns_get_glyph_string_clip_rect (s->next, r);
3154                 ns_focus (s->f, r, n);
3155                 ns_maybe_dumpglyphs_background (s->next, 1);
3156                 ns_unfocus (s->f);
3157               }
3158             else
3159               {
3160                 ns_dumpglyphs_stretch (s->next);
3161               }
3162             next->num_clips = 0;
3163           }
3164     }
3166   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3167         && (s->first_glyph->type == CHAR_GLYPH
3168             || s->first_glyph->type == COMPOSITE_GLYPH))
3169     {
3170       n = ns_get_glyph_string_clip_rect (s, r);
3171       ns_focus (s->f, r, n);
3172       ns_maybe_dumpglyphs_background (s, 1);
3173       ns_dumpglyphs_box_or_relief (s);
3174       ns_unfocus (s->f);
3175       box_drawn_p = 1;
3176     }
3178   switch (s->first_glyph->type)
3179     {
3181     case IMAGE_GLYPH:
3182       n = ns_get_glyph_string_clip_rect (s, r);
3183       ns_focus (s->f, r, n);
3184       ns_dumpglyphs_image (s, r[0]);
3185       ns_unfocus (s->f);
3186       break;
3188     case STRETCH_GLYPH:
3189       ns_dumpglyphs_stretch (s);
3190       break;
3192     case CHAR_GLYPH:
3193     case COMPOSITE_GLYPH:
3194       n = ns_get_glyph_string_clip_rect (s, r);
3195       ns_focus (s->f, r, n);
3197       if (s->for_overlaps || (s->cmp_from > 0
3198                               && ! s->first_glyph->u.cmp.automatic))
3199         s->background_filled_p = 1;
3200       else
3201         ns_maybe_dumpglyphs_background
3202           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3204       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3205                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3206                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3207                       NS_DUMPGLYPH_NORMAL));
3208       ns_tmp_font = (struct nsfont_info *)s->face->font;
3209       if (ns_tmp_font == NULL)
3210           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3212       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3213         {
3214           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3215           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3216           NS_FACE_FOREGROUND (s->face) = tmp;
3217         }
3219       ns_tmp_font->font.driver->draw
3220         (s, 0, s->nchars, s->x, s->y,
3221          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3222          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3224       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3225         {
3226           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3227           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3228           NS_FACE_FOREGROUND (s->face) = tmp;
3229         }
3231       ns_unfocus (s->f);
3232       break;
3234     case GLYPHLESS_GLYPH:
3235       n = ns_get_glyph_string_clip_rect (s, r);
3236       ns_focus (s->f, r, n);
3238       if (s->for_overlaps || (s->cmp_from > 0
3239                               && ! s->first_glyph->u.cmp.automatic))
3240         s->background_filled_p = 1;
3241       else
3242         ns_maybe_dumpglyphs_background
3243           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3244       /* ... */
3245       /* Not yet implemented.  */
3246       /* ... */
3247       ns_unfocus (s->f);
3248       break;
3250     default:
3251       emacs_abort ();
3252     }
3254   /* Draw box if not done already. */
3255   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3256     {
3257       n = ns_get_glyph_string_clip_rect (s, r);
3258       ns_focus (s->f, r, n);
3259       ns_dumpglyphs_box_or_relief (s);
3260       ns_unfocus (s->f);
3261     }
3263   s->num_clips = 0;
3268 /* ==========================================================================
3270     Event loop
3272    ========================================================================== */
3275 static void
3276 ns_send_appdefined (int value)
3277 /* --------------------------------------------------------------------------
3278     Internal: post an appdefined event which EmacsApp-sendEvent will
3279               recognize and take as a command to halt the event loop.
3280    -------------------------------------------------------------------------- */
3282   /*NSTRACE (ns_send_appdefined); */
3284 #ifdef NS_IMPL_GNUSTEP
3285   // GNUStep needs postEvent to happen on the main thread.
3286   if (! [[NSThread currentThread] isMainThread])
3287     {
3288       EmacsApp *app = (EmacsApp *)NSApp;
3289       app->nextappdefined = value;
3290       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3291                             withObject:nil
3292                          waitUntilDone:YES];
3293       return;
3294     }
3295 #endif
3297   /* Only post this event if we haven't already posted one.  This will end
3298        the [NXApp run] main loop after having processed all events queued at
3299        this moment.  */
3300   if (send_appdefined)
3301     {
3302       NSEvent *nxev;
3304       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3305       send_appdefined = NO;
3307       /* Don't need wakeup timer any more */
3308       if (timed_entry)
3309         {
3310           [timed_entry invalidate];
3311           [timed_entry release];
3312           timed_entry = nil;
3313         }
3315       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3316                                 location: NSMakePoint (0, 0)
3317                            modifierFlags: 0
3318                                timestamp: 0
3319                             windowNumber: [[NSApp mainWindow] windowNumber]
3320                                  context: [NSApp context]
3321                                  subtype: 0
3322                                    data1: value
3323                                    data2: 0];
3325       /* Post an application defined event on the event queue.  When this is
3326          received the [NXApp run] will return, thus having processed all
3327          events which are currently queued.  */
3328       [NSApp postEvent: nxev atStart: NO];
3329     }
3332 #ifdef HAVE_NATIVE_FS
3333 static void
3334 check_native_fs ()
3336   Lisp_Object frame, tail;
3338   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3339     return;
3341   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3343   /* Clear the mouse-moved flag for every frame on this display.  */
3344   FOR_EACH_FRAME (tail, frame)
3345     {
3346       struct frame *f = XFRAME (frame);
3347       if (FRAME_NS_P (f))
3348         {
3349           EmacsView *view = FRAME_NS_VIEW (f);
3350           [view updateCollectionBehaviour];
3351         }
3352     }
3354 #endif
3356 /* GNUStep and OSX <= 10.4 does not have cancelTracking.  */
3357 #if defined (NS_IMPL_COCOA) && \
3358   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
3359 /* Check if menu open should be cancelled or continued as normal.  */
3360 void
3361 ns_check_menu_open (NSMenu *menu)
3363   /* Click in menu bar? */
3364   NSArray *a = [[NSApp mainMenu] itemArray];
3365   int i;
3366   BOOL found = NO;
3368   if (menu == nil) // Menu tracking ended.
3369     {
3370       if (menu_will_open_state == MENU_OPENING)
3371         menu_will_open_state = MENU_NONE;
3372       return;
3373     }
3375   for (i = 0; ! found && i < [a count]; i++)
3376     found = menu == [[a objectAtIndex:i] submenu];
3377   if (found)
3378     {
3379       if (menu_will_open_state == MENU_NONE && emacs_event)
3380         {
3381           NSEvent *theEvent = [NSApp currentEvent];
3382           struct frame *emacsframe = SELECTED_FRAME ();
3384           [menu cancelTracking];
3385           menu_will_open_state = MENU_PENDING;
3386           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3387           EV_TRAILER (theEvent);
3389           CGEventRef ourEvent = CGEventCreate (NULL);
3390           menu_mouse_point = CGEventGetLocation (ourEvent);
3391           CFRelease (ourEvent);
3392         }
3393       else if (menu_will_open_state == MENU_OPENING)
3394         {
3395           menu_will_open_state = MENU_NONE;
3396         }
3397     }
3400 /* Redo saved menu click if state is MENU_PENDING.  */
3401 void
3402 ns_check_pending_open_menu ()
3404   if (menu_will_open_state == MENU_PENDING)
3405     {
3406       CGEventSourceRef source
3407         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3409       CGEventRef event = CGEventCreateMouseEvent (source,
3410                                                   kCGEventLeftMouseDown,
3411                                                   menu_mouse_point,
3412                                                   kCGMouseButtonLeft);
3413       CGEventSetType (event, kCGEventLeftMouseDown);
3414       CGEventPost (kCGHIDEventTap, event);
3415       CFRelease (event);
3416       CFRelease (source);
3418       menu_will_open_state = MENU_OPENING;
3419     }
3421 #endif /* NS_IMPL_COCOA) && >= MAC_OS_X_VERSION_10_5 */
3423 static int
3424 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3425 /* --------------------------------------------------------------------------
3426      External (hook): Post an event to ourself and keep reading events until
3427      we read it back again.  In effect process all events which were waiting.
3428      From 21+ we have to manage the event buffer ourselves.
3429    -------------------------------------------------------------------------- */
3431   struct input_event ev;
3432   int nevents;
3434 /* NSTRACE (ns_read_socket); */
3436 #ifdef HAVE_NATIVE_FS
3437   check_native_fs ();
3438 #endif
3440   if ([NSApp modalWindow] != nil)
3441     return -1;
3443   if (hold_event_q.nr > 0)
3444     {
3445       int i;
3446       for (i = 0; i < hold_event_q.nr; ++i)
3447         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3448       hold_event_q.nr = 0;
3449       return i;
3450     }
3452   block_input ();
3453   n_emacs_events_pending = 0;
3454   EVENT_INIT (ev);
3455   emacs_event = &ev;
3456   q_event_ptr = hold_quit;
3458   /* we manage autorelease pools by allocate/reallocate each time around
3459      the loop; strict nesting is occasionally violated but seems not to
3460      matter.. earlier methods using full nesting caused major memory leaks */
3461   [outerpool release];
3462   outerpool = [[NSAutoreleasePool alloc] init];
3464   /* If have pending open-file requests, attend to the next one of those. */
3465   if (ns_pending_files && [ns_pending_files count] != 0
3466       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3467     {
3468       [ns_pending_files removeObjectAtIndex: 0];
3469     }
3470   /* Deal with pending service requests. */
3471   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3472     && [(EmacsApp *)
3473          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3474                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3475     {
3476       [ns_pending_service_names removeObjectAtIndex: 0];
3477       [ns_pending_service_args removeObjectAtIndex: 0];
3478     }
3479   else
3480     {
3481       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3482          to ourself, otherwise [NXApp run] will never exit.  */
3483       send_appdefined = YES;
3484       ns_send_appdefined (-1);
3486       if (++apploopnr != 1)
3487         {
3488           emacs_abort ();
3489         }
3490       [NSApp run];
3491       --apploopnr;
3492     }
3494   nevents = n_emacs_events_pending;
3495   n_emacs_events_pending = 0;
3496   emacs_event = q_event_ptr = NULL;
3497   unblock_input ();
3499   return nevents;
3504 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3505            fd_set *exceptfds, struct timespec const *timeout,
3506            sigset_t const *sigmask)
3507 /* --------------------------------------------------------------------------
3508      Replacement for select, checking for events
3509    -------------------------------------------------------------------------- */
3511   int result;
3512   int t, k, nr = 0;
3513   struct input_event event;
3514   char c;
3516 /*  NSTRACE (ns_select); */
3518 #ifdef HAVE_NATIVE_FS
3519   check_native_fs ();
3520 #endif
3522   if (hold_event_q.nr > 0)
3523     {
3524       /* We already have events pending. */
3525       raise (SIGIO);
3526       errno = EINTR;
3527       return -1;
3528     }
3530   for (k = 0; k < nfds+1; k++)
3531     {
3532       if (readfds && FD_ISSET(k, readfds)) ++nr;
3533       if (writefds && FD_ISSET(k, writefds)) ++nr;
3534     }
3536   if (NSApp == nil
3537       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3538     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3540   [outerpool release];
3541   outerpool = [[NSAutoreleasePool alloc] init];
3544   send_appdefined = YES;
3545   if (nr > 0)
3546     {
3547       pthread_mutex_lock (&select_mutex);
3548       select_nfds = nfds;
3549       select_valid = 0;
3550       if (readfds)
3551         {
3552           select_readfds = *readfds;
3553           select_valid += SELECT_HAVE_READ;
3554         }
3555       if (writefds)
3556         {
3557           select_writefds = *writefds;
3558           select_valid += SELECT_HAVE_WRITE;
3559         }
3561       if (timeout)
3562         {
3563           select_timeout = *timeout;
3564           select_valid += SELECT_HAVE_TMO;
3565         }
3567       pthread_mutex_unlock (&select_mutex);
3569       /* Inform fd_handler that select should be called */
3570       c = 'g';
3571       emacs_write_sig (selfds[1], &c, 1);
3572     }
3573   else if (nr == 0 && timeout)
3574     {
3575       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3576       double time = timespectod (*timeout);
3577       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3578                                                       target: NSApp
3579                                                     selector:
3580                                   @selector (timeout_handler:)
3581                                                     userInfo: 0
3582                                                      repeats: NO]
3583                       retain];
3584     }
3585   else /* No timeout and no file descriptors, can this happen?  */
3586     {
3587       /* Send appdefined so we exit from the loop */
3588       ns_send_appdefined (-1);
3589     }
3591   EVENT_INIT (event);
3592   block_input ();
3593   emacs_event = &event;
3594   if (++apploopnr != 1)
3595     {
3596       emacs_abort ();
3597     }
3598   [NSApp run];
3599   --apploopnr;
3600   emacs_event = NULL;
3601   if (nr > 0 && readfds)
3602     {
3603       c = 's';
3604       emacs_write_sig (selfds[1], &c, 1);
3605     }
3606   unblock_input ();
3608   t = last_appdefined_event_data;
3610   if (t != NO_APPDEFINED_DATA)
3611     {
3612       last_appdefined_event_data = NO_APPDEFINED_DATA;
3614       if (t == -2)
3615         {
3616           /* The NX_APPDEFINED event we received was a timeout. */
3617           result = 0;
3618         }
3619       else if (t == -1)
3620         {
3621           /* The NX_APPDEFINED event we received was the result of
3622              at least one real input event arriving.  */
3623           errno = EINTR;
3624           result = -1;
3625         }
3626       else
3627         {
3628           /* Received back from select () in fd_handler; copy the results */
3629           pthread_mutex_lock (&select_mutex);
3630           if (readfds) *readfds = select_readfds;
3631           if (writefds) *writefds = select_writefds;
3632           pthread_mutex_unlock (&select_mutex);
3633           result = t;
3634         }
3635     }
3636   else
3637     {
3638       errno = EINTR;
3639       result = -1;
3640     }
3642   return result;
3647 /* ==========================================================================
3649     Scrollbar handling
3651    ========================================================================== */
3654 static void
3655 ns_set_vertical_scroll_bar (struct window *window,
3656                            int portion, int whole, int position)
3657 /* --------------------------------------------------------------------------
3658       External (hook): Update or add scrollbar
3659    -------------------------------------------------------------------------- */
3661   Lisp_Object win;
3662   NSRect r, v;
3663   struct frame *f = XFRAME (WINDOW_FRAME (window));
3664   EmacsView *view = FRAME_NS_VIEW (f);
3665   int window_y, window_height;
3666   int top, left, height, width, sb_width, sb_left;
3667   EmacsScroller *bar;
3668   BOOL fringe_extended_p;
3670   /* optimization; display engine sends WAY too many of these.. */
3671   if (!NILP (window->vertical_scroll_bar))
3672     {
3673       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3674       if ([bar checkSamePosition: position portion: portion whole: whole])
3675         {
3676           if (view->scrollbarsNeedingUpdate == 0)
3677             {
3678               if (!windows_or_buffers_changed)
3679                   return;
3680             }
3681           else
3682             view->scrollbarsNeedingUpdate--;
3683         }
3684     }
3686   NSTRACE (ns_set_vertical_scroll_bar);
3688   /* Get dimensions.  */
3689   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3690   top = window_y;
3691   height = window_height;
3692   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3693   left = WINDOW_SCROLL_BAR_AREA_X (window);
3695   /* allow for displaying a skinnier scrollbar than char area allotted */
3696   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3697     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3698   sb_left = left;
3700   r = NSMakeRect (sb_left, top, sb_width, height);
3701   /* the parent view is flipped, so we need to flip y value */
3702   v = [view frame];
3703   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3705   fringe_extended_p = WINDOW_FRINGE_EXTENDED_P (window);
3707   XSETWINDOW (win, window);
3708   block_input ();
3710   /* we want at least 5 lines to display a scrollbar */
3711   if (WINDOW_TOTAL_LINES (window) < 5)
3712     {
3713       if (!NILP (window->vertical_scroll_bar))
3714         {
3715           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3716           [bar removeFromSuperview];
3717           wset_vertical_scroll_bar (window, Qnil);
3718         }
3719       ns_clear_frame_area (f, sb_left, top, width, height);
3720       unblock_input ();
3721       return;
3722     }
3724   if (NILP (window->vertical_scroll_bar))
3725     {
3726       if (width > 0 && height > 0)
3727         {
3728           if (fringe_extended_p)
3729             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3730           else
3731             ns_clear_frame_area (f, left, top, width, height);
3732         }
3734       bar = [[EmacsScroller alloc] initFrame: r window: win];
3735       wset_vertical_scroll_bar (window, make_save_ptr (bar));
3736     }
3737   else
3738     {
3739       NSRect oldRect;
3740       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3741       oldRect = [bar frame];
3742       r.size.width = oldRect.size.width;
3743       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3744         {
3745           if (oldRect.origin.x != r.origin.x)
3746               ns_clear_frame_area (f, sb_left, top, width, height);
3747           [bar setFrame: r];
3748         }
3749     }
3751   [bar setPosition: position portion: portion whole: whole];
3752   unblock_input ();
3756 static void
3757 ns_condemn_scroll_bars (struct frame *f)
3758 /* --------------------------------------------------------------------------
3759      External (hook): arrange for all frame's scrollbars to be removed
3760      at next call to judge_scroll_bars, except for those redeemed.
3761    -------------------------------------------------------------------------- */
3763   int i;
3764   id view;
3765   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3767   NSTRACE (ns_condemn_scroll_bars);
3769   for (i =[subviews count]-1; i >= 0; i--)
3770     {
3771       view = [subviews objectAtIndex: i];
3772       if ([view isKindOfClass: [EmacsScroller class]])
3773         [view condemn];
3774     }
3778 static void
3779 ns_redeem_scroll_bar (struct window *window)
3780 /* --------------------------------------------------------------------------
3781      External (hook): arrange to spare this window's scrollbar
3782      at next call to judge_scroll_bars.
3783    -------------------------------------------------------------------------- */
3785   id bar;
3786   NSTRACE (ns_redeem_scroll_bar);
3787   if (!NILP (window->vertical_scroll_bar))
3788     {
3789       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3790       [bar reprieve];
3791     }
3795 static void
3796 ns_judge_scroll_bars (struct frame *f)
3797 /* --------------------------------------------------------------------------
3798      External (hook): destroy all scrollbars on frame that weren't
3799      redeemed after call to condemn_scroll_bars.
3800    -------------------------------------------------------------------------- */
3802   int i;
3803   id view;
3804   EmacsView *eview = FRAME_NS_VIEW (f);
3805   NSArray *subviews = [[eview superview] subviews];
3806   BOOL removed = NO;
3808   NSTRACE (ns_judge_scroll_bars);
3809   for (i = [subviews count]-1; i >= 0; --i)
3810     {
3811       view = [subviews objectAtIndex: i];
3812       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3813       [view judge];
3814       removed = YES;
3815     }
3817   if (removed)
3818     [eview updateFrameSize: NO];
3821 /* ==========================================================================
3823     Initialization
3825    ========================================================================== */
3828 x_display_pixel_height (struct ns_display_info *dpyinfo)
3830   NSArray *screens = [NSScreen screens];
3831   NSEnumerator *enumerator = [screens objectEnumerator];
3832   NSScreen *screen;
3833   NSRect frame;
3835   frame = NSZeroRect;
3836   while ((screen = [enumerator nextObject]) != nil)
3837     frame = NSUnionRect (frame, [screen frame]);
3839   return NSHeight (frame);
3843 x_display_pixel_width (struct ns_display_info *dpyinfo)
3845   NSArray *screens = [NSScreen screens];
3846   NSEnumerator *enumerator = [screens objectEnumerator];
3847   NSScreen *screen;
3848   NSRect frame;
3850   frame = NSZeroRect;
3851   while ((screen = [enumerator nextObject]) != nil)
3852     frame = NSUnionRect (frame, [screen frame]);
3854   return NSWidth (frame);
3858 static Lisp_Object ns_string_to_lispmod (const char *s)
3859 /* --------------------------------------------------------------------------
3860      Convert modifier name to lisp symbol
3861    -------------------------------------------------------------------------- */
3863   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3864     return Qmeta;
3865   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3866     return Qsuper;
3867   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3868     return Qcontrol;
3869   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3870     return Qalt;
3871   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3872     return Qhyper;
3873   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3874     return Qnone;
3875   else
3876     return Qnil;
3880 static void
3881 ns_default (const char *parameter, Lisp_Object *result,
3882            Lisp_Object yesval, Lisp_Object noval,
3883            BOOL is_float, BOOL is_modstring)
3884 /* --------------------------------------------------------------------------
3885       Check a parameter value in user's preferences
3886    -------------------------------------------------------------------------- */
3888   const char *value = ns_get_defaults_value (parameter);
3890   if (value)
3891     {
3892       double f;
3893       char *pos;
3894       if (c_strcasecmp (value, "YES") == 0)
3895         *result = yesval;
3896       else if (c_strcasecmp (value, "NO") == 0)
3897         *result = noval;
3898       else if (is_float && (f = strtod (value, &pos), pos != value))
3899         *result = make_float (f);
3900       else if (is_modstring && value)
3901         *result = ns_string_to_lispmod (value);
3902       else fprintf (stderr,
3903                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3904     }
3908 static void
3909 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3910 /* --------------------------------------------------------------------------
3911       Initialize global info and storage for display.
3912    -------------------------------------------------------------------------- */
3914     NSScreen *screen = [NSScreen mainScreen];
3915     NSWindowDepth depth = [screen depth];
3917     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3918     dpyinfo->resy = 72.27;
3919     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3920                                                   NSColorSpaceFromDepth (depth)]
3921                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3922                                                  NSColorSpaceFromDepth (depth)];
3923     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3924     dpyinfo->image_cache = make_image_cache ();
3925     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
3926     dpyinfo->color_table->colors = NULL;
3927     dpyinfo->root_window = 42; /* a placeholder.. */
3928     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3929     dpyinfo->n_fonts = 0;
3930     dpyinfo->smallest_font_height = 1;
3931     dpyinfo->smallest_char_width = 1;
3933     reset_mouse_highlight (&dpyinfo->mouse_highlight);
3937 /* This and next define (many of the) public functions in this file. */
3938 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3939          with using despite presence in the "system dependent" redisplay
3940          interface.  In addition, many of the ns_ methods have code that is
3941          shared with all terms, indicating need for further refactoring. */
3942 extern frame_parm_handler ns_frame_parm_handlers[];
3943 static struct redisplay_interface ns_redisplay_interface =
3945   ns_frame_parm_handlers,
3946   x_produce_glyphs,
3947   x_write_glyphs,
3948   x_insert_glyphs,
3949   x_clear_end_of_line,
3950   ns_scroll_run,
3951   ns_after_update_window_line,
3952   ns_update_window_begin,
3953   ns_update_window_end,
3954   0, /* flush_display */
3955   x_clear_window_mouse_face,
3956   x_get_glyph_overhangs,
3957   x_fix_overlapping_area,
3958   ns_draw_fringe_bitmap,
3959   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3960   0, /* destroy_fringe_bitmap */
3961   ns_compute_glyph_string_overhangs,
3962   ns_draw_glyph_string, /* interface to nsfont.m */
3963   ns_define_frame_cursor,
3964   ns_clear_frame_area,
3965   ns_draw_window_cursor,
3966   ns_draw_vertical_window_border,
3967   ns_shift_glyphs_for_insert
3971 static void
3972 ns_delete_display (struct ns_display_info *dpyinfo)
3974   /* TODO... */
3978 /* This function is called when the last frame on a display is deleted. */
3979 static void
3980 ns_delete_terminal (struct terminal *terminal)
3982   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3984   /* Protect against recursive calls.  delete_frame in
3985      delete_terminal calls us back when it deletes our last frame.  */
3986   if (!terminal->name)
3987     return;
3989   block_input ();
3991   x_destroy_all_bitmaps (dpyinfo);
3992   ns_delete_display (dpyinfo);
3993   unblock_input ();
3997 static struct terminal *
3998 ns_create_terminal (struct ns_display_info *dpyinfo)
3999 /* --------------------------------------------------------------------------
4000       Set up use of NS before we make the first connection.
4001    -------------------------------------------------------------------------- */
4003   struct terminal *terminal;
4005   NSTRACE (ns_create_terminal);
4007   terminal = create_terminal ();
4009   terminal->type = output_ns;
4010   terminal->display_info.ns = dpyinfo;
4011   dpyinfo->terminal = terminal;
4013   terminal->rif = &ns_redisplay_interface;
4015   terminal->clear_frame_hook = ns_clear_frame;
4016   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4017   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
4018   terminal->ring_bell_hook = ns_ring_bell;
4019   terminal->reset_terminal_modes_hook = NULL;
4020   terminal->set_terminal_modes_hook = NULL;
4021   terminal->update_begin_hook = ns_update_begin;
4022   terminal->update_end_hook = ns_update_end;
4023   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4024   terminal->read_socket_hook = ns_read_socket;
4025   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4026   terminal->mouse_position_hook = ns_mouse_position;
4027   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4028   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4030   terminal->fullscreen_hook = ns_fullscreen_hook;
4032   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4033   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4034   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4035   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4037   terminal->delete_frame_hook = x_destroy_window;
4038   terminal->delete_terminal_hook = ns_delete_terminal;
4040   terminal->scroll_region_ok = 1;
4041   terminal->char_ins_del_ok = 1;
4042   terminal->line_ins_del_ok = 1;
4043   terminal->fast_clear_end_of_line = 1;
4044   terminal->memory_below_frame = 0;
4046   return terminal;
4050 struct ns_display_info *
4051 ns_term_init (Lisp_Object display_name)
4052 /* --------------------------------------------------------------------------
4053      Start the Application and get things rolling.
4054    -------------------------------------------------------------------------- */
4056   struct terminal *terminal;
4057   struct ns_display_info *dpyinfo;
4058   static int ns_initialized = 0;
4059   Lisp_Object tmp;
4061   if (ns_initialized) return x_display_list;
4062   ns_initialized = 1;
4064   NSTRACE (ns_term_init);
4066   [outerpool release];
4067   outerpool = [[NSAutoreleasePool alloc] init];
4069   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4070   /*GSDebugAllocationActive (YES); */
4071   block_input ();
4073   baud_rate = 38400;
4074   Fset_input_interrupt_mode (Qnil);
4076   if (selfds[0] == -1)
4077     {
4078       if (emacs_pipe (selfds) != 0)
4079         {
4080           fprintf (stderr, "Failed to create pipe: %s\n",
4081                    emacs_strerror (errno));
4082           emacs_abort ();
4083         }
4085       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4086       FD_ZERO (&select_readfds);
4087       FD_ZERO (&select_writefds);
4088       pthread_mutex_init (&select_mutex, NULL);
4089     }
4091   ns_pending_files = [[NSMutableArray alloc] init];
4092   ns_pending_service_names = [[NSMutableArray alloc] init];
4093   ns_pending_service_args = [[NSMutableArray alloc] init];
4095 /* Start app and create the main menu, window, view.
4096      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4097      The view will then ask the NSApp to stop and return to Emacs. */
4098   [EmacsApp sharedApplication];
4099   if (NSApp == nil)
4100     return NULL;
4101   [NSApp setDelegate: NSApp];
4103   /* Start the select thread.  */
4104   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4105                            toTarget:NSApp
4106                          withObject:nil];
4108   /* debugging: log all notifications */
4109   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4110                                          selector: @selector (logNotification:)
4111                                              name: nil object: nil]; */
4113   dpyinfo = xzalloc (sizeof *dpyinfo);
4115   ns_initialize_display_info (dpyinfo);
4116   terminal = ns_create_terminal (dpyinfo);
4118   terminal->kboard = xmalloc (sizeof *terminal->kboard);
4119   init_kboard (terminal->kboard);
4120   kset_window_system (terminal->kboard, Qns);
4121   terminal->kboard->next_kboard = all_kboards;
4122   all_kboards = terminal->kboard;
4123   /* Don't let the initial kboard remain current longer than necessary.
4124      That would cause problems if a file loaded on startup tries to
4125      prompt in the mini-buffer.  */
4126   if (current_kboard == initial_kboard)
4127     current_kboard = terminal->kboard;
4128   terminal->kboard->reference_count++;
4130   dpyinfo->next = x_display_list;
4131   x_display_list = dpyinfo;
4133   /* Put it on ns_display_name_list */
4134   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4135                                 ns_display_name_list);
4136   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4138   terminal->name = xstrdup (SSDATA (display_name));
4140   unblock_input ();
4142   if (!inhibit_x_resources)
4143     {
4144       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4145                  Qt, Qnil, NO, NO);
4146       tmp = Qnil;
4147       /* this is a standard variable */
4148       ns_default ("AppleAntiAliasingThreshold", &tmp,
4149                  make_float (10.0), make_float (6.0), YES, NO);
4150       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4151     }
4153   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4154                          stringForKey: @"AppleHighlightColor"];
4155   if (ns_selection_color == nil)
4156     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4158   {
4159     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4161     if ( cl == nil )
4162       {
4163         Lisp_Object color_file, color_map, color;
4164         unsigned long c;
4165         char *name;
4167         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4168                          Fsymbol_value (intern ("data-directory")));
4170         color_map = Fx_load_color_file (color_file);
4171         if (NILP (color_map))
4172           fatal ("Could not read %s.\n", SDATA (color_file));
4174         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4175         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4176           {
4177             color = XCAR (color_map);
4178             name = SSDATA (XCAR (color));
4179             c = XINT (XCDR (color));
4180             [cl setColor:
4181                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4182                                             green: GREEN_FROM_ULONG (c) / 255.0
4183                                              blue: BLUE_FROM_ULONG (c) / 255.0
4184                                             alpha: 1.0]
4185                   forKey: [NSString stringWithUTF8String: name]];
4186           }
4187         [cl writeToFile: nil];
4188       }
4189   }
4191   {
4192 #ifdef NS_IMPL_GNUSTEP
4193     Vwindow_system_version = build_string (gnustep_base_version);
4194 #else
4195     /*PSnextrelease (128, c); */
4196     char c[DBL_BUFSIZE_BOUND];
4197     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4198     Vwindow_system_version = make_unibyte_string (c, len);
4199 #endif
4200   }
4202   delete_keyboard_wait_descriptor (0);
4204   ns_app_name = [[NSProcessInfo processInfo] processName];
4206 /* Set up OS X app menu */
4207 #ifdef NS_IMPL_COCOA
4208   {
4209     NSMenu *appMenu;
4210     NSMenuItem *item;
4211     /* set up the application menu */
4212     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4213     [svcsMenu setAutoenablesItems: NO];
4214     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4215     [appMenu setAutoenablesItems: NO];
4216     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4217     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4219     [appMenu insertItemWithTitle: @"About Emacs"
4220                           action: @selector (orderFrontStandardAboutPanel:)
4221                    keyEquivalent: @""
4222                          atIndex: 0];
4223     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4224     [appMenu insertItemWithTitle: @"Preferences..."
4225                           action: @selector (showPreferencesWindow:)
4226                    keyEquivalent: @","
4227                          atIndex: 2];
4228     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4229     item = [appMenu insertItemWithTitle: @"Services"
4230                                  action: @selector (menuDown:)
4231                           keyEquivalent: @""
4232                                 atIndex: 4];
4233     [appMenu setSubmenu: svcsMenu forItem: item];
4234     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4235     [appMenu insertItemWithTitle: @"Hide Emacs"
4236                           action: @selector (hide:)
4237                    keyEquivalent: @"h"
4238                          atIndex: 6];
4239     item =  [appMenu insertItemWithTitle: @"Hide Others"
4240                           action: @selector (hideOtherApplications:)
4241                    keyEquivalent: @"h"
4242                          atIndex: 7];
4243     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4244     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4245     [appMenu insertItemWithTitle: @"Quit Emacs"
4246                           action: @selector (terminate:)
4247                    keyEquivalent: @"q"
4248                          atIndex: 9];
4250     item = [mainMenu insertItemWithTitle: ns_app_name
4251                                   action: @selector (menuDown:)
4252                            keyEquivalent: @""
4253                                  atIndex: 0];
4254     [mainMenu setSubmenu: appMenu forItem: item];
4255     [dockMenu insertItemWithTitle: @"New Frame"
4256                            action: @selector (newFrame:)
4257                     keyEquivalent: @""
4258                           atIndex: 0];
4260     [NSApp setMainMenu: mainMenu];
4261     [NSApp setAppleMenu: appMenu];
4262     [NSApp setServicesMenu: svcsMenu];
4263     /* Needed at least on Cocoa, to get dock menu to show windows */
4264     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4266     [[NSNotificationCenter defaultCenter]
4267       addObserver: mainMenu
4268          selector: @selector (trackingNotification:)
4269              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4270     [[NSNotificationCenter defaultCenter]
4271       addObserver: mainMenu
4272          selector: @selector (trackingNotification:)
4273              name: NSMenuDidEndTrackingNotification object: mainMenu];
4274   }
4275 #endif /* MAC OS X menu setup */
4277   /* Register our external input/output types, used for determining
4278      applicable services and also drag/drop eligibility. */
4279   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4280   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4281                       retain];
4282   ns_drag_types = [[NSArray arrayWithObjects:
4283                             NSStringPboardType,
4284                             NSTabularTextPboardType,
4285                             NSFilenamesPboardType,
4286                             NSURLPboardType,
4287                             NSColorPboardType,
4288                             NSFontPboardType, nil] retain];
4290   /* If fullscreen is in init/default-frame-alist, focus isn't set
4291      right for fullscreen windows, so set this.  */
4292   [NSApp activateIgnoringOtherApps:YES];
4294   [NSApp run];
4295   ns_do_open_file = YES;
4297 #ifdef NS_IMPL_GNUSTEP
4298   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4299      We must re-catch it so subprocess works.  */
4300   catch_child_signal ();
4301 #endif
4302   return dpyinfo;
4306 void
4307 ns_term_shutdown (int sig)
4309   [[NSUserDefaults standardUserDefaults] synchronize];
4311   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4312   if (STRINGP (Vauto_save_list_file_name))
4313     unlink (SSDATA (Vauto_save_list_file_name));
4315   if (sig == 0 || sig == SIGTERM)
4316     {
4317       [NSApp terminate: NSApp];
4318     }
4319   else // force a stack trace to happen
4320     {
4321       emacs_abort ();
4322     }
4326 /* ==========================================================================
4328     EmacsApp implementation
4330    ========================================================================== */
4333 @implementation EmacsApp
4335 - (void)logNotification: (NSNotification *)notification
4337   const char *name = [[notification name] UTF8String];
4338   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4339       && !strstr (name, "WindowNumber"))
4340     NSLog (@"notification: '%@'", [notification name]);
4344 - (void)sendEvent: (NSEvent *)theEvent
4345 /* --------------------------------------------------------------------------
4346      Called when NSApp is running for each event received.  Used to stop
4347      the loop when we choose, since there's no way to just run one iteration.
4348    -------------------------------------------------------------------------- */
4350   int type = [theEvent type];
4351   NSWindow *window = [theEvent window];
4353 /*  NSTRACE (sendEvent); */
4354 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4356 #ifdef NS_IMPL_GNUSTEP
4357   // Keyboard events aren't propagated to file dialogs for some reason.
4358   if ([NSApp modalWindow] != nil &&
4359       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4360     {
4361       [[NSApp modalWindow] sendEvent: theEvent];
4362       return;
4363     }
4364 #endif
4366   if (type == NSApplicationDefined)
4367     {
4368       switch ([theEvent data2])
4369         {
4370 #ifdef NS_IMPL_COCOA
4371         case NSAPP_DATA2_RUNASSCRIPT:
4372           ns_run_ascript ();
4373           [self stop: self];
4374           return;
4375 #endif
4376         case NSAPP_DATA2_RUNFILEDIALOG:
4377           ns_run_file_dialog ();
4378           [self stop: self];
4379           return;
4380         }
4381     }
4383   if (type == NSCursorUpdate && window == nil)
4384     {
4385       fprintf (stderr, "Dropping external cursor update event.\n");
4386       return;
4387     }
4389   if (type == NSApplicationDefined)
4390     {
4391       /* Events posted by ns_send_appdefined interrupt the run loop here.
4392          But, if a modal window is up, an appdefined can still come through,
4393          (e.g., from a makeKeyWindow event) but stopping self also stops the
4394          modal loop. Just defer it until later. */
4395       if ([NSApp modalWindow] == nil)
4396         {
4397           last_appdefined_event_data = [theEvent data1];
4398           [self stop: self];
4399         }
4400       else
4401         {
4402           send_appdefined = YES;
4403         }
4404     }
4407 #ifdef NS_IMPL_COCOA
4408   /* If no dialog and none of our frames have focus and it is a move, skip it.
4409      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4410      such as Wifi, sound, date or similar.
4411      This prevents "spooky" highlighting in the frame under the menu.  */
4412   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4413     {
4414       struct ns_display_info *di;
4415       BOOL has_focus = NO;
4416       for (di = x_display_list; ! has_focus && di; di = di->next)
4417         has_focus = di->x_focus_frame != 0;
4418       if (! has_focus)
4419         return;
4420     }
4421 #endif
4423   [super sendEvent: theEvent];
4427 - (void)showPreferencesWindow: (id)sender
4429   struct frame *emacsframe = SELECTED_FRAME ();
4430   NSEvent *theEvent = [NSApp currentEvent];
4432   if (!emacs_event)
4433     return;
4434   emacs_event->kind = NS_NONKEY_EVENT;
4435   emacs_event->code = KEY_NS_SHOW_PREFS;
4436   emacs_event->modifiers = 0;
4437   EV_TRAILER (theEvent);
4441 - (void)newFrame: (id)sender
4443   struct frame *emacsframe = SELECTED_FRAME ();
4444   NSEvent *theEvent = [NSApp currentEvent];
4446   if (!emacs_event)
4447     return;
4448   emacs_event->kind = NS_NONKEY_EVENT;
4449   emacs_event->code = KEY_NS_NEW_FRAME;
4450   emacs_event->modifiers = 0;
4451   EV_TRAILER (theEvent);
4455 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4456 - (BOOL) openFile: (NSString *)fileName
4458   struct frame *emacsframe = SELECTED_FRAME ();
4459   NSEvent *theEvent = [NSApp currentEvent];
4461   if (!emacs_event)
4462     return NO;
4464   emacs_event->kind = NS_NONKEY_EVENT;
4465   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4466   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4467   ns_input_line = Qnil; /* can be start or cons start,end */
4468   emacs_event->modifiers =0;
4469   EV_TRAILER (theEvent);
4471   return YES;
4475 /* **************************************************************************
4477       EmacsApp delegate implementation
4479    ************************************************************************** */
4481 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4482 /* --------------------------------------------------------------------------
4483      When application is loaded, terminate event loop in ns_term_init
4484    -------------------------------------------------------------------------- */
4486   NSTRACE (applicationDidFinishLaunching);
4487   [NSApp setServicesProvider: NSApp];
4488   ns_send_appdefined (-2);
4492 /* Termination sequences:
4493     C-x C-c:
4494     Cmd-Q:
4495     MenuBar | File | Exit:
4496     Select Quit from App menubar:
4497         -terminate
4498         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4499         ns_term_shutdown()
4501     Select Quit from Dock menu:
4502     Logout attempt:
4503         -appShouldTerminate
4504           Cancel -> Nothing else
4505           Accept ->
4507           -terminate
4508           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4509           ns_term_shutdown()
4513 - (void) terminate: (id)sender
4515   struct frame *emacsframe = SELECTED_FRAME ();
4517   if (!emacs_event)
4518     return;
4520   emacs_event->kind = NS_NONKEY_EVENT;
4521   emacs_event->code = KEY_NS_POWER_OFF;
4522   emacs_event->arg = Qt; /* mark as non-key event */
4523   EV_TRAILER ((id)nil);
4527 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4529   int ret;
4531   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4532     return NSTerminateNow;
4534     ret = NSRunAlertPanel(ns_app_name,
4535                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4536                           @"Save Buffers and Exit", @"Cancel", nil);
4538     if (ret == NSAlertDefaultReturn)
4539         return NSTerminateNow;
4540     else if (ret == NSAlertAlternateReturn)
4541         return NSTerminateCancel;
4542     return NSTerminateNow;  /* just in case */
4545 static int
4546 not_in_argv (NSString *arg)
4548   int k;
4549   const char *a = [arg UTF8String];
4550   for (k = 1; k < initial_argc; ++k)
4551     if (strcmp (a, initial_argv[k]) == 0) return 0;
4552   return 1;
4555 /*   Notification from the Workspace to open a file */
4556 - (BOOL)application: sender openFile: (NSString *)file
4558   if (ns_do_open_file || not_in_argv (file))
4559     [ns_pending_files addObject: file];
4560   return YES;
4564 /*   Open a file as a temporary file */
4565 - (BOOL)application: sender openTempFile: (NSString *)file
4567   if (ns_do_open_file || not_in_argv (file))
4568     [ns_pending_files addObject: file];
4569   return YES;
4573 /*   Notification from the Workspace to open a file noninteractively (?) */
4574 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4576   if (ns_do_open_file || not_in_argv (file))
4577     [ns_pending_files addObject: file];
4578   return YES;
4581 /*   Notification from the Workspace to open multiple files */
4582 - (void)application: sender openFiles: (NSArray *)fileList
4584   NSEnumerator *files = [fileList objectEnumerator];
4585   NSString *file;
4586   /* Don't open files from the command line unconditionally,
4587      Cocoa parses the command line wrong, --option value tries to open value
4588      if --option is the last option.  */
4589   while ((file = [files nextObject]) != nil)
4590     if (ns_do_open_file || not_in_argv (file))
4591       [ns_pending_files addObject: file];
4593   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4598 /* Handle dock menu requests.  */
4599 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4601   return dockMenu;
4605 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4606 - (void)applicationWillBecomeActive: (NSNotification *)notification
4608   //ns_app_active=YES;
4610 - (void)applicationDidBecomeActive: (NSNotification *)notification
4612   NSTRACE (applicationDidBecomeActive);
4614   //ns_app_active=YES;
4616   ns_update_auto_hide_menu_bar ();
4617   // No constraining takes place when the application is not active.
4618   ns_constrain_all_frames ();
4620 - (void)applicationDidResignActive: (NSNotification *)notification
4622   //ns_app_active=NO;
4623   ns_send_appdefined (-1);
4628 /* ==========================================================================
4630     EmacsApp aux handlers for managing event loop
4632    ========================================================================== */
4635 - (void)timeout_handler: (NSTimer *)timedEntry
4636 /* --------------------------------------------------------------------------
4637      The timeout specified to ns_select has passed.
4638    -------------------------------------------------------------------------- */
4640   /*NSTRACE (timeout_handler); */
4641   ns_send_appdefined (-2);
4644 #ifdef NS_IMPL_GNUSTEP
4645 - (void)sendFromMainThread:(id)unused
4647   ns_send_appdefined (nextappdefined);
4649 #endif
4651 - (void)fd_handler:(id)unused
4652 /* --------------------------------------------------------------------------
4653      Check data waiting on file descriptors and terminate if so
4654    -------------------------------------------------------------------------- */
4656   int result;
4657   int waiting = 1, nfds;
4658   char c;
4660   fd_set readfds, writefds, *wfds;
4661   struct timespec timeout, *tmo;
4662   NSAutoreleasePool *pool = nil;
4664   /* NSTRACE (fd_handler); */
4666   for (;;)
4667     {
4668       [pool release];
4669       pool = [[NSAutoreleasePool alloc] init];
4671       if (waiting)
4672         {
4673           fd_set fds;
4674           FD_ZERO (&fds);
4675           FD_SET (selfds[0], &fds);
4676           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4677           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4678             waiting = 0;
4679         }
4680       else
4681         {
4682           pthread_mutex_lock (&select_mutex);
4683           nfds = select_nfds;
4685           if (select_valid & SELECT_HAVE_READ)
4686             readfds = select_readfds;
4687           else
4688             FD_ZERO (&readfds);
4690           if (select_valid & SELECT_HAVE_WRITE)
4691             {
4692               writefds = select_writefds;
4693               wfds = &writefds;
4694             }
4695           else
4696             wfds = NULL;
4697           if (select_valid & SELECT_HAVE_TMO)
4698             {
4699               timeout = select_timeout;
4700               tmo = &timeout;
4701             }
4702           else
4703             tmo = NULL;
4705           pthread_mutex_unlock (&select_mutex);
4707           FD_SET (selfds[0], &readfds);
4708           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4710           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4712           if (result == 0)
4713             ns_send_appdefined (-2);
4714           else if (result > 0)
4715             {
4716               if (FD_ISSET (selfds[0], &readfds))
4717                 {
4718                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4719                     waiting = 1;
4720                 }
4721               else
4722                 {
4723                   pthread_mutex_lock (&select_mutex);
4724                   if (select_valid & SELECT_HAVE_READ)
4725                     select_readfds = readfds;
4726                   if (select_valid & SELECT_HAVE_WRITE)
4727                     select_writefds = writefds;
4728                   if (select_valid & SELECT_HAVE_TMO)
4729                     select_timeout = timeout;
4730                   pthread_mutex_unlock (&select_mutex);
4732                   ns_send_appdefined (result);
4733                 }
4734             }
4735           waiting = 1;
4736         }
4737     }
4742 /* ==========================================================================
4744     Service provision
4746    ========================================================================== */
4748 /* called from system: queue for next pass through event loop */
4749 - (void)requestService: (NSPasteboard *)pboard
4750               userData: (NSString *)userData
4751                  error: (NSString **)error
4753   [ns_pending_service_names addObject: userData];
4754   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4755       SSDATA (ns_string_from_pasteboard (pboard))]];
4759 /* called from ns_read_socket to clear queue */
4760 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4762   struct frame *emacsframe = SELECTED_FRAME ();
4763   NSEvent *theEvent = [NSApp currentEvent];
4765   if (!emacs_event)
4766     return NO;
4768   emacs_event->kind = NS_NONKEY_EVENT;
4769   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4770   ns_input_spi_name = build_string ([name UTF8String]);
4771   ns_input_spi_arg = build_string ([arg UTF8String]);
4772   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4773   EV_TRAILER (theEvent);
4775   return YES;
4779 @end  /* EmacsApp */
4783 /* ==========================================================================
4785     EmacsView implementation
4787    ========================================================================== */
4790 @implementation EmacsView
4792 /* needed to inform when window closed from LISP */
4793 - (void) setWindowClosing: (BOOL)closing
4795   windowClosing = closing;
4799 - (void)dealloc
4801   NSTRACE (EmacsView_dealloc);
4802   [toolbar release];
4803   if (fs_state == FULLSCREEN_BOTH)
4804     [nonfs_window release];
4805   [super dealloc];
4809 /* called on font panel selection */
4810 - (void)changeFont: (id)sender
4812   NSEvent *e =[[self window] currentEvent];
4813   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4814   id newFont;
4815   CGFloat size;
4817   NSTRACE (changeFont);
4818   if (!emacs_event)
4819     return;
4821   if ((newFont = [sender convertFont:
4822                            ((struct nsfont_info *)face->font)->nsfont]))
4823     {
4824       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4826       emacs_event->kind = NS_NONKEY_EVENT;
4827       emacs_event->modifiers = 0;
4828       emacs_event->code = KEY_NS_CHANGE_FONT;
4830       size = [newFont pointSize];
4831       ns_input_fontsize = make_number (lrint (size));
4832       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4833       EV_TRAILER (e);
4834     }
4838 - (BOOL)acceptsFirstResponder
4840   NSTRACE (acceptsFirstResponder);
4841   return YES;
4845 - (void)resetCursorRects
4847   NSRect visible = [self visibleRect];
4848   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4849   NSTRACE (resetCursorRects);
4851   if (currentCursor == nil)
4852     currentCursor = [NSCursor arrowCursor];
4854   if (!NSIsEmptyRect (visible))
4855     [self addCursorRect: visible cursor: currentCursor];
4856   [currentCursor setOnMouseEntered: YES];
4861 /*****************************************************************************/
4862 /* Keyboard handling. */
4863 #define NS_KEYLOG 0
4865 - (void)keyDown: (NSEvent *)theEvent
4867   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4868   int code;
4869   unsigned fnKeysym = 0;
4870   static NSMutableArray *nsEvArray;
4871 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4872   static BOOL firstTime = YES;
4873 #endif
4874   int left_is_none;
4875   unsigned int flags = [theEvent modifierFlags];
4877   NSTRACE (keyDown);
4879   /* Rhapsody and OS X give up and down events for the arrow keys */
4880   if (ns_fake_keydown == YES)
4881     ns_fake_keydown = NO;
4882   else if ([theEvent type] != NSKeyDown)
4883     return;
4885   if (!emacs_event)
4886     return;
4888  if (![[self window] isKeyWindow]
4889      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4890      /* we must avoid an infinite loop here. */
4891      && (EmacsView *)[[theEvent window] delegate] != self)
4892    {
4893      /* XXX: There is an occasional condition in which, when Emacs display
4894          updates a different frame from the current one, and temporarily
4895          selects it, then processes some interrupt-driven input
4896          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4897          for some reason that window has its first responder set to the NSView
4898          most recently updated (I guess), which is not the correct one. */
4899      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4900      return;
4901    }
4903   if (nsEvArray == nil)
4904     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4906   [NSCursor setHiddenUntilMouseMoves: YES];
4908   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4909     {
4910       clear_mouse_face (hlinfo);
4911       hlinfo->mouse_face_hidden = 1;
4912     }
4914   if (!processingCompose)
4915     {
4916       /* When using screen sharing, no left or right information is sent,
4917          so use Left key in those cases.  */
4918       int is_left_key, is_right_key;
4920       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4921         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4923       /* (Carbon way: [theEvent keyCode]) */
4925       /* is it a "function key"? */
4926       fnKeysym = (code < 0x00ff && (flags&NSNumericPadKeyMask))
4927         ? ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask)
4928         : ns_convert_key (code);
4930       if (fnKeysym)
4931         {
4932           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4933              because Emacs treats Delete and KP-Delete same (in simple.el). */
4934           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4935 #ifdef NS_IMPL_GNUSTEP
4936               /*  GNUstep uses incompatible keycodes, even for those that are
4937                   supposed to be hardware independent.  Just check for delete.
4938                   Keypad delete does not have keysym 0xFFFF.
4939                   See http://savannah.gnu.org/bugs/?25395
4940               */
4941               || (fnKeysym == 0xFFFF && code == 127)
4942 #endif
4943             )
4944             code = 0xFF08; /* backspace */
4945           else
4946             code = fnKeysym;
4947         }
4949       /* are there modifiers? */
4950       emacs_event->modifiers = 0;
4952       if (flags & NSHelpKeyMask)
4953           emacs_event->modifiers |= hyper_modifier;
4955       if (flags & NSShiftKeyMask)
4956         emacs_event->modifiers |= shift_modifier;
4958       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
4959       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
4960         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
4962       if (is_right_key)
4963         emacs_event->modifiers |= parse_solitary_modifier
4964           (EQ (ns_right_command_modifier, Qleft)
4965            ? ns_command_modifier
4966            : ns_right_command_modifier);
4968       if (is_left_key)
4969         {
4970           emacs_event->modifiers |= parse_solitary_modifier
4971             (ns_command_modifier);
4973           /* if super (default), take input manager's word so things like
4974              dvorak / qwerty layout work */
4975           if (EQ (ns_command_modifier, Qsuper)
4976               && !fnKeysym
4977               && [[theEvent characters] length] != 0)
4978             {
4979               /* XXX: the code we get will be unshifted, so if we have
4980                  a shift modifier, must convert ourselves */
4981               if (!(flags & NSShiftKeyMask))
4982                 code = [[theEvent characters] characterAtIndex: 0];
4983 #if 0
4984               /* this is ugly and also requires linking w/Carbon framework
4985                  (for LMGetKbdType) so for now leave this rare (?) case
4986                  undealt with.. in future look into CGEvent methods */
4987               else
4988                 {
4989                   long smv = GetScriptManagerVariable (smKeyScript);
4990                   Handle uchrHandle = GetResource
4991                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4992                   UInt32 dummy = 0;
4993                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4994                                  [[theEvent characters] characterAtIndex: 0],
4995                                  kUCKeyActionDisplay,
4996                                  (flags & ~NSCommandKeyMask) >> 8,
4997                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4998                                  &dummy, 1, &dummy, &code);
4999                   code &= 0xFF;
5000                 }
5001 #endif
5002             }
5003         }
5005       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5006       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5007         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5009       if (is_right_key)
5010           emacs_event->modifiers |= parse_solitary_modifier
5011               (EQ (ns_right_control_modifier, Qleft)
5012                ? ns_control_modifier
5013                : ns_right_control_modifier);
5015       if (is_left_key)
5016         emacs_event->modifiers |= parse_solitary_modifier
5017           (ns_control_modifier);
5019       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5020           emacs_event->modifiers |=
5021             parse_solitary_modifier (ns_function_modifier);
5023       left_is_none = NILP (ns_alternate_modifier)
5024         || EQ (ns_alternate_modifier, Qnone);
5026       is_right_key = (flags & NSRightAlternateKeyMask)
5027         == NSRightAlternateKeyMask;
5028       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5029         || (! is_right_key
5030             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5032       if (is_right_key)
5033         {
5034           if ((NILP (ns_right_alternate_modifier)
5035                || EQ (ns_right_alternate_modifier, Qnone)
5036                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5037               && !fnKeysym)
5038             {   /* accept pre-interp alt comb */
5039               if ([[theEvent characters] length] > 0)
5040                 code = [[theEvent characters] characterAtIndex: 0];
5041               /*HACK: clear lone shift modifier to stop next if from firing */
5042               if (emacs_event->modifiers == shift_modifier)
5043                 emacs_event->modifiers = 0;
5044             }
5045           else
5046             emacs_event->modifiers |= parse_solitary_modifier
5047               (EQ (ns_right_alternate_modifier, Qleft)
5048                ? ns_alternate_modifier
5049                : ns_right_alternate_modifier);
5050         }
5052       if (is_left_key) /* default = meta */
5053         {
5054           if (left_is_none && !fnKeysym)
5055             {   /* accept pre-interp alt comb */
5056               if ([[theEvent characters] length] > 0)
5057                 code = [[theEvent characters] characterAtIndex: 0];
5058               /*HACK: clear lone shift modifier to stop next if from firing */
5059               if (emacs_event->modifiers == shift_modifier)
5060                 emacs_event->modifiers = 0;
5061             }
5062           else
5063               emacs_event->modifiers |=
5064                 parse_solitary_modifier (ns_alternate_modifier);
5065         }
5067   if (NS_KEYLOG)
5068     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5069              code, fnKeysym, flags, emacs_event->modifiers);
5071       /* if it was a function key or had modifiers, pass it directly to emacs */
5072       if (fnKeysym || (emacs_event->modifiers
5073                        && (emacs_event->modifiers != shift_modifier)
5074                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5075 /*[[theEvent characters] length] */
5076         {
5077           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5078           if (code < 0x20)
5079             code |= (1<<28)|(3<<16);
5080           else if (code == 0x7f)
5081             code |= (1<<28)|(3<<16);
5082           else if (!fnKeysym)
5083             emacs_event->kind = code > 0xFF
5084               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5086           emacs_event->code = code;
5087           EV_TRAILER (theEvent);
5088           processingCompose = NO;
5089           return;
5090         }
5091     }
5094 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5095   /* if we get here we should send the key for input manager processing */
5096   /* Disable warning, there is nothing a user can do about it anyway, and
5097      it does not seem to matter.  */
5098 #if 0
5099   if (firstTime && [[NSInputManager currentInputManager]
5100                      wantsToDelayTextChangeNotifications] == NO)
5101     fprintf (stderr,
5102           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5103 #endif
5104   firstTime = NO;
5105 #endif
5106   if (NS_KEYLOG && !processingCompose)
5107     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5109   processingCompose = YES;
5110   [nsEvArray addObject: theEvent];
5111   [self interpretKeyEvents: nsEvArray];
5112   [nsEvArray removeObject: theEvent];
5116 #ifdef NS_IMPL_COCOA
5117 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5118    decided not to send key-down for.
5119    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5120    This only applies on Tiger and earlier.
5121    If it matches one of these, send it on to keyDown. */
5122 -(void)keyUp: (NSEvent *)theEvent
5124   int flags = [theEvent modifierFlags];
5125   int code = [theEvent keyCode];
5126   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5127       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5128     {
5129       if (NS_KEYLOG)
5130         fprintf (stderr, "keyUp: passed test");
5131       ns_fake_keydown = YES;
5132       [self keyDown: theEvent];
5133     }
5135 #endif
5138 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5141 /* <NSTextInput>: called when done composing;
5142    NOTE: also called when we delete over working text, followed immed.
5143          by doCommandBySelector: deleteBackward: */
5144 - (void)insertText: (id)aString
5146   int code;
5147   int len = [(NSString *)aString length];
5148   int i;
5150   if (NS_KEYLOG)
5151     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5152   processingCompose = NO;
5154   if (!emacs_event)
5155     return;
5157   /* first, clear any working text */
5158   if (workingText != nil)
5159     [self deleteWorkingText];
5161   /* now insert the string as keystrokes */
5162   for (i =0; i<len; i++)
5163     {
5164       code = [aString characterAtIndex: i];
5165       /* TODO: still need this? */
5166       if (code == 0x2DC)
5167         code = '~'; /* 0x7E */
5168       if (code != 32) /* Space */
5169         emacs_event->modifiers = 0;
5170       emacs_event->kind
5171         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5172       emacs_event->code = code;
5173       EV_TRAILER ((id)nil);
5174     }
5178 /* <NSTextInput>: inserts display of composing characters */
5179 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5181   NSString *str = [aString respondsToSelector: @selector (string)] ?
5182     [aString string] : aString;
5183   if (NS_KEYLOG)
5184     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
5185            selRange.length, selRange.location);
5187   if (workingText != nil)
5188     [self deleteWorkingText];
5189   if ([str length] == 0)
5190     return;
5192   if (!emacs_event)
5193     return;
5195   processingCompose = YES;
5196   workingText = [str copy];
5197   ns_working_text = build_string ([workingText UTF8String]);
5199   emacs_event->kind = NS_TEXT_EVENT;
5200   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5201   EV_TRAILER ((id)nil);
5205 /* delete display of composing characters [not in <NSTextInput>] */
5206 - (void)deleteWorkingText
5208   if (workingText == nil)
5209     return;
5210   if (NS_KEYLOG)
5211     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
5212   [workingText release];
5213   workingText = nil;
5214   processingCompose = NO;
5216   if (!emacs_event)
5217     return;
5219   emacs_event->kind = NS_TEXT_EVENT;
5220   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5221   EV_TRAILER ((id)nil);
5225 - (BOOL)hasMarkedText
5227   return workingText != nil;
5231 - (NSRange)markedRange
5233   NSRange rng = workingText != nil
5234     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5235   if (NS_KEYLOG)
5236     NSLog (@"markedRange request");
5237   return rng;
5241 - (void)unmarkText
5243   if (NS_KEYLOG)
5244     NSLog (@"unmark (accept) text");
5245   [self deleteWorkingText];
5246   processingCompose = NO;
5250 /* used to position char selection windows, etc. */
5251 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5253   NSRect rect;
5254   NSPoint pt;
5255   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5256   if (NS_KEYLOG)
5257     NSLog (@"firstRectForCharRange request");
5259   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5260   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5261   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5262   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5263                                        +FRAME_LINE_HEIGHT (emacsframe));
5265   pt = [self convertPoint: pt toView: nil];
5266   pt = [[self window] convertBaseToScreen: pt];
5267   rect.origin = pt;
5268   return rect;
5272 - (NSInteger)conversationIdentifier
5274   return (NSInteger)self;
5278 - (void)doCommandBySelector: (SEL)aSelector
5280   if (NS_KEYLOG)
5281     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5283   processingCompose = NO;
5284   if (aSelector == @selector (deleteBackward:))
5285     {
5286       /* happens when user backspaces over an ongoing composition:
5287          throw a 'delete' into the event queue */
5288       if (!emacs_event)
5289         return;
5290       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5291       emacs_event->code = 0xFF08;
5292       EV_TRAILER ((id)nil);
5293     }
5296 - (NSArray *)validAttributesForMarkedText
5298   static NSArray *arr = nil;
5299   if (arr == nil) arr = [NSArray new];
5300  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5301   return arr;
5304 - (NSRange)selectedRange
5306   if (NS_KEYLOG)
5307     NSLog (@"selectedRange request");
5308   return NSMakeRange (NSNotFound, 0);
5311 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5312     GNUSTEP_GUI_MINOR_VERSION > 22
5313 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5314 #else
5315 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5316 #endif
5318   if (NS_KEYLOG)
5319     NSLog (@"characterIndexForPoint request");
5320   return 0;
5323 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5325   static NSAttributedString *str = nil;
5326   if (str == nil) str = [NSAttributedString new];
5327   if (NS_KEYLOG)
5328     NSLog (@"attributedSubstringFromRange request");
5329   return str;
5332 /* End <NSTextInput> impl. */
5333 /*****************************************************************************/
5336 /* This is what happens when the user presses a mouse button.  */
5337 - (void)mouseDown: (NSEvent *)theEvent
5339   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5341   NSTRACE (mouseDown);
5343   [self deleteWorkingText];
5345   if (!emacs_event)
5346     return;
5348   last_mouse_frame = emacsframe;
5349   /* appears to be needed to prevent spurious movement events generated on
5350      button clicks */
5351   last_mouse_frame->mouse_moved = 0;
5353   if ([theEvent type] == NSScrollWheel)
5354     {
5355       CGFloat delta = [theEvent deltaY];
5356       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5357       if (delta == 0)
5358         return;
5359       emacs_event->kind = WHEEL_EVENT;
5360       emacs_event->code = 0;
5361       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5362         ((delta > 0) ? up_modifier : down_modifier);
5363     }
5364   else
5365     {
5366       emacs_event->kind = MOUSE_CLICK_EVENT;
5367       emacs_event->code = EV_BUTTON (theEvent);
5368       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5369                              | EV_UDMODIFIERS (theEvent);
5370     }
5371   XSETINT (emacs_event->x, lrint (p.x));
5372   XSETINT (emacs_event->y, lrint (p.y));
5373   EV_TRAILER (theEvent);
5377 - (void)rightMouseDown: (NSEvent *)theEvent
5379   NSTRACE (rightMouseDown);
5380   [self mouseDown: theEvent];
5384 - (void)otherMouseDown: (NSEvent *)theEvent
5386   NSTRACE (otherMouseDown);
5387   [self mouseDown: theEvent];
5391 - (void)mouseUp: (NSEvent *)theEvent
5393   NSTRACE (mouseUp);
5394   [self mouseDown: theEvent];
5398 - (void)rightMouseUp: (NSEvent *)theEvent
5400   NSTRACE (rightMouseUp);
5401   [self mouseDown: theEvent];
5405 - (void)otherMouseUp: (NSEvent *)theEvent
5407   NSTRACE (otherMouseUp);
5408   [self mouseDown: theEvent];
5412 - (void) scrollWheel: (NSEvent *)theEvent
5414   NSTRACE (scrollWheel);
5415   [self mouseDown: theEvent];
5419 /* Tell emacs the mouse has moved. */
5420 - (void)mouseMoved: (NSEvent *)e
5422   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5423   Lisp_Object frame;
5425 //  NSTRACE (mouseMoved);
5427   last_mouse_movement_time = EV_TIMESTAMP (e);
5428   last_mouse_motion_position
5429     = [self convertPoint: [e locationInWindow] fromView: nil];
5431   /* update any mouse face */
5432   if (hlinfo->mouse_face_hidden)
5433     {
5434       hlinfo->mouse_face_hidden = 0;
5435       clear_mouse_face (hlinfo);
5436     }
5438   /* tooltip handling */
5439   previous_help_echo_string = help_echo_string;
5440   help_echo_string = Qnil;
5442   if (!NILP (Vmouse_autoselect_window))
5443     {
5444       NSTRACE (mouse_autoselect_window);
5445       static Lisp_Object last_mouse_window;
5446       Lisp_Object window = window_from_coordinates
5447         (emacsframe, last_mouse_motion_position.x,
5448          last_mouse_motion_position.y, 0, 0);
5450       if (WINDOWP (window)
5451           && !EQ (window, last_mouse_window)
5452           && !EQ (window, selected_window)
5453           && (focus_follows_mouse
5454               || (EQ (XWINDOW (window)->frame,
5455                       XWINDOW (selected_window)->frame))))
5456         {
5457           NSTRACE (in_window);
5458           emacs_event->kind = SELECT_WINDOW_EVENT;
5459           emacs_event->frame_or_window = window;
5460           EV_TRAILER2 (e);
5461         }
5462       /* Remember the last window where we saw the mouse.  */
5463       last_mouse_window = window;
5464     }
5466   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5467                             last_mouse_motion_position.y))
5468     help_echo_string = previous_help_echo_string;
5470   XSETFRAME (frame, emacsframe);
5471   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5472     {
5473       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5474          (note_mouse_highlight), which is called through the
5475          note_mouse_movement () call above */
5476       gen_help_event (help_echo_string, frame, help_echo_window,
5477                       help_echo_object, help_echo_pos);
5478     }
5479   else
5480     {
5481       help_echo_string = Qnil;
5482       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5483     }
5485   if (emacsframe->mouse_moved && send_appdefined)
5486     ns_send_appdefined (-1);
5490 - (void)mouseDragged: (NSEvent *)e
5492   NSTRACE (mouseDragged);
5493   [self mouseMoved: e];
5497 - (void)rightMouseDragged: (NSEvent *)e
5499   NSTRACE (rightMouseDragged);
5500   [self mouseMoved: e];
5504 - (void)otherMouseDragged: (NSEvent *)e
5506   NSTRACE (otherMouseDragged);
5507   [self mouseMoved: e];
5511 - (BOOL)windowShouldClose: (id)sender
5513   NSEvent *e =[[self window] currentEvent];
5515   NSTRACE (windowShouldClose);
5516   windowClosing = YES;
5517   if (!emacs_event)
5518     return NO;
5519   emacs_event->kind = DELETE_WINDOW_EVENT;
5520   emacs_event->modifiers = 0;
5521   emacs_event->code = 0;
5522   EV_TRAILER (e);
5523   /* Don't close this window, let this be done from lisp code.  */
5524   return NO;
5527 - (void) updateFrameSize: (BOOL) delay;
5529   NSWindow *window = [self window];
5530   NSRect wr = [window frame];
5531   int extra = 0;
5532   int gsextra = 0;
5533 #ifdef NS_IMPL_GNUSTEP
5534   gsextra = 3;
5535 #endif
5537   int oldc = cols, oldr = rows;
5538   int oldw = FRAME_PIXEL_WIDTH (emacsframe),
5539     oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5540   int neww, newh;
5542   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, wr.size.width + gsextra);
5544   if (cols < MINWIDTH)
5545     cols = MINWIDTH;
5547   if (! [self isFullscreen])
5548     {
5549       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5550         + FRAME_TOOLBAR_HEIGHT (emacsframe) - gsextra;
5551     }
5553   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, wr.size.height - extra);
5555   if (rows < MINHEIGHT)
5556     rows = MINHEIGHT;
5558   neww = (int)wr.size.width - emacsframe->border_width;
5559   newh = (int)wr.size.height - extra;
5561   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5562     {
5563       NSView *view = FRAME_NS_VIEW (emacsframe);
5564       NSWindow *win = [view window];
5565       NSSize sz = [win resizeIncrements];
5567       FRAME_PIXEL_WIDTH (emacsframe) = neww;
5568       FRAME_PIXEL_HEIGHT (emacsframe) = newh;
5569       change_frame_size (emacsframe, rows, cols, 0, delay, 0);
5570       SET_FRAME_GARBAGED (emacsframe);
5571       cancel_mouse_face (emacsframe);
5573       // Did resize increments change because of a font change?
5574       if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5575           sz.height != FRAME_LINE_HEIGHT (emacsframe))
5576         {
5577           sz.width = FRAME_COLUMN_WIDTH (emacsframe);
5578           sz.height = FRAME_LINE_HEIGHT (emacsframe);
5579           [win setResizeIncrements: sz];
5580         }
5582       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5583       [self windowDidMove:nil];   // Update top/left.
5584     }
5587 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5588 /* normalize frame to gridded text size */
5590   int extra = 0;
5591   int gsextra = 0;
5592 #ifdef NS_IMPL_GNUSTEP
5593   gsextra = 3;
5594 #endif
5596   NSTRACE (windowWillResize);
5597 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5599   if (fs_state == FULLSCREEN_MAXIMIZED
5600       && (maximized_width != (int)frameSize.width
5601           || maximized_height != (int)frameSize.height))
5602     [self setFSValue: FULLSCREEN_NONE];
5603   else if (fs_state == FULLSCREEN_WIDTH
5604            && maximized_width != (int)frameSize.width)
5605     [self setFSValue: FULLSCREEN_NONE];
5606   else if (fs_state == FULLSCREEN_HEIGHT
5607            && maximized_height != (int)frameSize.height)
5608     [self setFSValue: FULLSCREEN_NONE];
5609   if (fs_state == FULLSCREEN_NONE)
5610     maximized_width = maximized_height = -1;
5612   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5613                                          frameSize.width + gsextra);
5614   if (cols < MINWIDTH)
5615     cols = MINWIDTH;
5617   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5618                                            frameSize.height - extra);
5619   if (rows < MINHEIGHT)
5620     rows = MINHEIGHT;
5621 #ifdef NS_IMPL_COCOA
5622   {
5623     /* this sets window title to have size in it; the wm does this under GS */
5624     NSRect r = [[self window] frame];
5625     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5626       {
5627         if (old_title != 0)
5628           {
5629             xfree (old_title);
5630             old_title = 0;
5631           }
5632       }
5633     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5634       {
5635         char *size_title;
5636         NSWindow *window = [self window];
5637         if (old_title == 0)
5638           {
5639             char *t = strdup ([[[self window] title] UTF8String]);
5640             char *pos = strstr (t, "  â€”  ");
5641             if (pos)
5642               *pos = '\0';
5643             old_title = t;
5644           }
5645         size_title = xmalloc (strlen (old_title) + 40);
5646         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5647         [window setTitle: [NSString stringWithUTF8String: size_title]];
5648         [window display];
5649         xfree (size_title);
5650       }
5651   }
5652 #endif /* NS_IMPL_COCOA */
5653 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5655   return frameSize;
5659 - (void)windowDidResize: (NSNotification *)notification
5661   if (! [self fsIsNative])
5662     {
5663       NSWindow *theWindow = [notification object];
5664       /* We can get notification on the non-FS window when in
5665          fullscreen mode.  */
5666       if ([self window] != theWindow) return;
5667     }
5669 #ifdef NS_IMPL_GNUSTEP
5670   NSWindow *theWindow = [notification object];
5672    /* In GNUstep, at least currently, it's possible to get a didResize
5673       without getting a willResize.. therefore we need to act as if we got
5674       the willResize now */
5675   NSSize sz = [theWindow frame].size;
5676   sz = [self windowWillResize: theWindow toSize: sz];
5677 #endif /* NS_IMPL_GNUSTEP */
5679   NSTRACE (windowDidResize);
5680 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5682 if (cols > 0 && rows > 0)
5683     {
5684       [self updateFrameSize: YES];
5685     }
5687   ns_send_appdefined (-1);
5690 #ifdef NS_IMPL_COCOA
5691 - (void)viewDidEndLiveResize
5693   [super viewDidEndLiveResize];
5694   if (old_title != 0)
5695     {
5696       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
5697       xfree (old_title);
5698       old_title = 0;
5699     }
5700   maximizing_resize = NO;
5702 #endif /* NS_IMPL_COCOA */
5705 - (void)windowDidBecomeKey: (NSNotification *)notification
5706 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5708   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5709   struct frame *old_focus = dpyinfo->x_focus_frame;
5711   NSTRACE (windowDidBecomeKey);
5713   if (emacsframe != old_focus)
5714     dpyinfo->x_focus_frame = emacsframe;
5716   ns_frame_rehighlight (emacsframe);
5718   if (emacs_event)
5719     {
5720       emacs_event->kind = FOCUS_IN_EVENT;
5721       EV_TRAILER ((id)nil);
5722     }
5726 - (void)windowDidResignKey: (NSNotification *)notification
5727 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5729   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5730   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
5731   NSTRACE (windowDidResignKey);
5733   if (is_focus_frame)
5734     dpyinfo->x_focus_frame = 0;
5736   ns_frame_rehighlight (emacsframe);
5738   /* FIXME: for some reason needed on second and subsequent clicks away
5739             from sole-frame Emacs to get hollow box to show */
5740   if (!windowClosing && [[self window] isVisible] == YES)
5741     {
5742       x_update_cursor (emacsframe, 1);
5743       x_set_frame_alpha (emacsframe);
5744     }
5746   if (emacs_event && is_focus_frame)
5747     {
5748       [self deleteWorkingText];
5749       emacs_event->kind = FOCUS_OUT_EVENT;
5750       EV_TRAILER ((id)nil);
5751     }
5755 - (void)windowWillMiniaturize: sender
5757   NSTRACE (windowWillMiniaturize);
5761 - (BOOL)isFlipped
5763   return YES;
5767 - (BOOL)isOpaque
5769   return NO;
5773 - initFrameFromEmacs: (struct frame *)f
5775   NSRect r, wr;
5776   Lisp_Object tem;
5777   NSWindow *win;
5778   NSSize sz;
5779   NSColor *col;
5780   NSString *name;
5782   NSTRACE (initFrameFromEmacs);
5784   windowClosing = NO;
5785   processingCompose = NO;
5786   scrollbarsNeedingUpdate = 0;
5787   fs_state = FULLSCREEN_NONE;
5788   fs_before_fs = next_maximized = -1;
5789 #ifdef HAVE_NATIVE_FS
5790   fs_is_native = ns_use_native_fullscreen;
5791 #else
5792   fs_is_native = NO;
5793 #endif
5794   maximized_width = maximized_height = -1;
5795   nonfs_window = nil;
5797 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5799   ns_userRect = NSMakeRect (0, 0, 0, 0);
5800   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5801                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5802   [self initWithFrame: r];
5803   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5805   FRAME_NS_VIEW (f) = self;
5806   emacsframe = f;
5807 #ifdef NS_IMPL_COCOA
5808   old_title = 0;
5809   maximizing_resize = NO;
5810 #endif
5812   win = [[EmacsWindow alloc]
5813             initWithContentRect: r
5814                       styleMask: (NSResizableWindowMask |
5815 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5816                                   NSTitledWindowMask |
5817 #endif
5818                                   NSMiniaturizableWindowMask |
5819                                   NSClosableWindowMask)
5820                         backing: NSBackingStoreBuffered
5821                           defer: YES];
5823 #ifdef HAVE_NATIVE_FS
5824     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
5825 #endif
5827   wr = [win frame];
5828   bwidth = f->border_width = wr.size.width - r.size.width;
5829   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5831   [win setAcceptsMouseMovedEvents: YES];
5832   [win setDelegate: self];
5833   [win useOptimizedDrawing: YES];
5835   sz.width = FRAME_COLUMN_WIDTH (f);
5836   sz.height = FRAME_LINE_HEIGHT (f);
5837   [win setResizeIncrements: sz];
5839   [[win contentView] addSubview: self];
5841   if (ns_drag_types)
5842     [self registerForDraggedTypes: ns_drag_types];
5844   tem = f->name;
5845   name = [NSString stringWithUTF8String:
5846                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5847   [win setTitle: name];
5849   /* toolbar support */
5850   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5851                          [NSString stringWithFormat: @"Emacs Frame %d",
5852                                    ns_window_num]];
5853   [win setToolbar: toolbar];
5854   [toolbar setVisible: NO];
5855 #ifdef NS_IMPL_COCOA
5856   {
5857     NSButton *toggleButton;
5858   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5859   [toggleButton setTarget: self];
5860   [toggleButton setAction: @selector (toggleToolbar: )];
5861   }
5862 #endif
5863   FRAME_TOOLBAR_HEIGHT (f) = 0;
5865   tem = f->icon_name;
5866   if (!NILP (tem))
5867     [win setMiniwindowTitle:
5868            [NSString stringWithUTF8String: SSDATA (tem)]];
5870   {
5871     NSScreen *screen = [win screen];
5873     if (screen != 0)
5874       [win setFrameTopLeftPoint: NSMakePoint
5875            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5876             IN_BOUND (-SCREENMAX,
5877                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5878   }
5880   [win makeFirstResponder: self];
5882   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5883                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5884   [win setBackgroundColor: col];
5885   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
5886     [win setOpaque: NO];
5888   [self allocateGState];
5890   [NSApp registerServicesMenuSendTypes: ns_send_types
5891                            returnTypes: nil];
5893   ns_window_num++;
5894   return self;
5898 - (void)windowDidMove: sender
5900   NSWindow *win = [self window];
5901   NSRect r = [win frame];
5902   NSArray *screens = [NSScreen screens];
5903   NSScreen *screen = [screens objectAtIndex: 0];
5905   NSTRACE (windowDidMove);
5907   if (!emacsframe->output_data.ns)
5908     return;
5909   if (screen != nil)
5910     {
5911       emacsframe->left_pos = r.origin.x;
5912       emacsframe->top_pos =
5913         [screen frame].size.height - (r.origin.y + r.size.height);
5914     }
5918 /* Called AFTER method below, but before our windowWillResize call there leads
5919    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5920    location so set_window_size moves the frame. */
5921 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5923   emacsframe->output_data.ns->zooming = 1;
5924   return YES;
5928 /* Override to do something slightly nonstandard, but nice.  First click on
5929    zoom button will zoom vertically.  Second will zoom completely.  Third
5930    returns to original. */
5931 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5932                         defaultFrame:(NSRect)defaultFrame
5934   NSRect result = [sender frame];
5936   NSTRACE (windowWillUseStandardFrame);
5938   if (fs_before_fs != -1) /* Entering fullscreen */
5939       {
5940         result = defaultFrame;
5941       }
5942   else if (next_maximized == FULLSCREEN_HEIGHT
5943       || (next_maximized == -1
5944           && abs (defaultFrame.size.height - result.size.height)
5945           > FRAME_LINE_HEIGHT (emacsframe)))
5946     {
5947       /* first click */
5948       ns_userRect = result;
5949       maximized_height = result.size.height = defaultFrame.size.height;
5950       maximized_width = -1;
5951       result.origin.y = defaultFrame.origin.y;
5952       [self setFSValue: FULLSCREEN_HEIGHT];
5953 #ifdef NS_IMPL_COCOA
5954       maximizing_resize = YES;
5955 #endif
5956     }
5957   else if (next_maximized == FULLSCREEN_WIDTH)
5958     {
5959       ns_userRect = result;
5960       maximized_width = result.size.width = defaultFrame.size.width;
5961       maximized_height = -1;
5962       result.origin.x = defaultFrame.origin.x;
5963       [self setFSValue: FULLSCREEN_WIDTH];
5964     }
5965   else if (next_maximized == FULLSCREEN_MAXIMIZED
5966            || (next_maximized == -1
5967                && abs (defaultFrame.size.width - result.size.width)
5968                > FRAME_COLUMN_WIDTH (emacsframe)))
5969     {
5970       result = defaultFrame;  /* second click */
5971       maximized_width = result.size.width;
5972       maximized_height = result.size.height;
5973       [self setFSValue: FULLSCREEN_MAXIMIZED];
5974 #ifdef NS_IMPL_COCOA
5975       maximizing_resize = YES;
5976 #endif
5977     }
5978   else
5979     {
5980       /* restore */
5981       result = ns_userRect.size.height ? ns_userRect : result;
5982       ns_userRect = NSMakeRect (0, 0, 0, 0);
5983 #ifdef NS_IMPL_COCOA
5984       maximizing_resize = fs_state != FULLSCREEN_NONE;
5985 #endif
5986       [self setFSValue: FULLSCREEN_NONE];
5987       maximized_width = maximized_height = -1;
5988     }
5990   if (fs_before_fs == -1) next_maximized = -1;
5991   [self windowWillResize: sender toSize: result.size];
5992   return result;
5996 - (void)windowDidDeminiaturize: sender
5998   NSTRACE (windowDidDeminiaturize);
5999   if (!emacsframe->output_data.ns)
6000     return;
6002   SET_FRAME_ICONIFIED (emacsframe, 0);
6003   SET_FRAME_VISIBLE (emacsframe, 1);
6004   windows_or_buffers_changed++;
6006   if (emacs_event)
6007     {
6008       emacs_event->kind = DEICONIFY_EVENT;
6009       EV_TRAILER ((id)nil);
6010     }
6014 - (void)windowDidExpose: sender
6016   NSTRACE (windowDidExpose);
6017   if (!emacsframe->output_data.ns)
6018     return;
6020   SET_FRAME_VISIBLE (emacsframe, 1);
6021   SET_FRAME_GARBAGED (emacsframe);
6023   if (send_appdefined)
6024     ns_send_appdefined (-1);
6028 - (void)windowDidMiniaturize: sender
6030   NSTRACE (windowDidMiniaturize);
6031   if (!emacsframe->output_data.ns)
6032     return;
6034   SET_FRAME_ICONIFIED (emacsframe, 1);
6035   SET_FRAME_VISIBLE (emacsframe, 0);
6037   if (emacs_event)
6038     {
6039       emacs_event->kind = ICONIFY_EVENT;
6040       EV_TRAILER ((id)nil);
6041     }
6044 #ifdef HAVE_NATIVE_FS
6045 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6046       willUseFullScreenPresentationOptions:
6047   (NSApplicationPresentationOptions)proposedOptions
6049   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6051 #endif
6053 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6055   fs_before_fs = fs_state;
6058 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6060   [self setFSValue: FULLSCREEN_BOTH];
6061   if (! [self fsIsNative])
6062     {
6063       [self windowDidBecomeKey:notification];
6064       [nonfs_window orderOut:self];
6065     }
6066   else if (! FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6067     [toolbar setVisible:NO];
6070 - (void)windowWillExitFullScreen:(NSNotification *)notification
6072   if (next_maximized != -1)
6073     fs_before_fs = next_maximized;
6076 - (void)windowDidExitFullScreen:(NSNotification *)notification
6078   [self setFSValue: fs_before_fs];
6079   fs_before_fs = -1;
6080 #ifdef NS_IMPL_COCOA
6081   [self updateCollectionBehaviour];
6082 #endif
6083   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6084     {
6085       [toolbar setVisible:YES];
6086       update_frame_tool_bar (emacsframe);
6087       [self updateFrameSize:YES];
6088       [[self window] display];
6089     }
6090   else
6091     [toolbar setVisible:NO];
6093   if (next_maximized != -1)
6094     [[self window] performZoom:self];
6097 - (BOOL)fsIsNative
6099   return fs_is_native;
6102 - (BOOL)isFullscreen
6104   if (! fs_is_native) return nonfs_window != nil;
6105 #ifdef HAVE_NATIVE_FS
6106   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6107 #else
6108   return NO;
6109 #endif
6112 #ifdef HAVE_NATIVE_FS
6113 - (void)updateCollectionBehaviour
6115   if (! [self isFullscreen])
6116     {
6117       NSWindow *win = [self window];
6118       NSWindowCollectionBehavior b = [win collectionBehavior];
6119       if (ns_use_native_fullscreen)
6120         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6121       else
6122         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6124       [win setCollectionBehavior: b];
6125       fs_is_native = ns_use_native_fullscreen;
6126     }
6128 #endif
6130 - (void)toggleFullScreen: (id)sender
6132   NSWindow *w, *fw;
6133   BOOL onFirstScreen;
6134   struct frame *f;
6135   NSSize sz;
6136   NSRect r, wr;
6137   NSColor *col;
6139   if (fs_is_native)
6140     {
6141 #ifdef NS_IMPL_COCOA
6142       [[self window] toggleFullScreen:sender];
6143 #endif
6144       return;
6145     }
6147   w = [self window];
6148   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6149   f = emacsframe;
6150   wr = [w frame];
6151   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6152                                  (FRAME_DEFAULT_FACE (f)),
6153                                  f);
6155   sz.width = FRAME_COLUMN_WIDTH (f);
6156   sz.height = FRAME_LINE_HEIGHT (f);
6158   if (fs_state != FULLSCREEN_BOTH)
6159     {
6160       /* Hide dock and menubar if we are on the primary screen.  */
6161       if (onFirstScreen)
6162         {
6163 #if defined (NS_IMPL_COCOA) && \
6164   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6165           NSApplicationPresentationOptions options
6166             = NSApplicationPresentationAutoHideDock
6167             | NSApplicationPresentationAutoHideMenuBar;
6169           [NSApp setPresentationOptions: options];
6170 #else
6171           [NSMenu setMenuBarVisible:NO];
6172 #endif
6173         }
6175       fw = [[EmacsFSWindow alloc]
6176                        initWithContentRect:[w contentRectForFrameRect:wr]
6177                                  styleMask:NSBorderlessWindowMask
6178                                    backing:NSBackingStoreBuffered
6179                                      defer:YES
6180                                     screen:[w screen]];
6182       [fw setContentView:[w contentView]];
6183       [fw setTitle:[w title]];
6184       [fw setDelegate:self];
6185       [fw setAcceptsMouseMovedEvents: YES];
6186       [fw useOptimizedDrawing: YES];
6187       [fw setResizeIncrements: sz];
6188       [fw setBackgroundColor: col];
6189       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6190         [fw setOpaque: NO];
6192       f->border_width = 0;
6193       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6194       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6195       FRAME_TOOLBAR_HEIGHT (f) = 0;
6197       nonfs_window = w;
6199       [self windowWillEnterFullScreen:nil];
6200       [fw makeKeyAndOrderFront:NSApp];
6201       [fw makeFirstResponder:self];
6202       [w orderOut:self];
6203       r = [fw frameRectForContentRect:[[fw screen] frame]];
6204       [fw setFrame: r display:YES animate:YES];
6205       [self windowDidEnterFullScreen:nil];
6206       [fw display];
6207     }
6208   else
6209     {
6210       fw = w;
6211       w = nonfs_window;
6212       nonfs_window = nil;
6214       if (onFirstScreen)
6215         {
6216 #if defined (NS_IMPL_COCOA) && \
6217   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6218           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6219 #else
6220           [NSMenu setMenuBarVisible:YES];
6221 #endif
6222         }
6224       [w setContentView:[fw contentView]];
6225       [w setResizeIncrements: sz];
6226       [w setBackgroundColor: col];
6227       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6228         [w setOpaque: NO];
6230       f->border_width = bwidth;
6231       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6232       if (FRAME_EXTERNAL_TOOL_BAR (f))
6233         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6235       [self windowWillExitFullScreen:nil];
6236       [fw setFrame: [w frame] display:YES animate:YES];
6237       [fw close];
6238       [w makeKeyAndOrderFront:NSApp];
6239       [self windowDidExitFullScreen:nil];
6240       [self updateFrameSize:YES];
6241     }
6244 - (void)handleFS
6246   if (fs_state != emacsframe->want_fullscreen)
6247     {
6248       if (fs_state == FULLSCREEN_BOTH)
6249         {
6250           [self toggleFullScreen:self];
6251         }
6253       switch (emacsframe->want_fullscreen)
6254         {
6255         case FULLSCREEN_BOTH:
6256           [self toggleFullScreen:self];
6257           break;
6258         case FULLSCREEN_WIDTH:
6259           next_maximized = FULLSCREEN_WIDTH;
6260           if (fs_state != FULLSCREEN_BOTH)
6261             [[self window] performZoom:self];
6262           break;
6263         case FULLSCREEN_HEIGHT:
6264           next_maximized = FULLSCREEN_HEIGHT;
6265           if (fs_state != FULLSCREEN_BOTH)
6266             [[self window] performZoom:self];
6267           break;
6268         case FULLSCREEN_MAXIMIZED:
6269           next_maximized = FULLSCREEN_MAXIMIZED;
6270           if (fs_state != FULLSCREEN_BOTH)
6271             [[self window] performZoom:self];
6272           break;
6273         case FULLSCREEN_NONE:
6274           if (fs_state != FULLSCREEN_BOTH)
6275             {
6276               next_maximized = FULLSCREEN_NONE;
6277               [[self window] performZoom:self];
6278             }
6279           break;
6280         }
6282       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6283     }
6287 - (void) setFSValue: (int)value
6289   Lisp_Object lval = Qnil;
6290   switch (value)
6291     {
6292     case FULLSCREEN_BOTH:
6293       lval = Qfullboth;
6294       break;
6295     case FULLSCREEN_WIDTH:
6296       lval = Qfullwidth;
6297       break;
6298     case FULLSCREEN_HEIGHT:
6299       lval = Qfullheight;
6300       break;
6301     case FULLSCREEN_MAXIMIZED:
6302       lval = Qmaximized;
6303       break;
6304     }
6305   store_frame_param (emacsframe, Qfullscreen, lval);
6306   fs_state = value;
6309 - (void)mouseEntered: (NSEvent *)theEvent
6311   NSTRACE (mouseEntered);
6312   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6316 - (void)mouseExited: (NSEvent *)theEvent
6318   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6320   NSTRACE (mouseExited);
6322   if (!hlinfo)
6323     return;
6325   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6327   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6328     {
6329       clear_mouse_face (hlinfo);
6330       hlinfo->mouse_face_mouse_frame = 0;
6331     }
6335 - menuDown: sender
6337   NSTRACE (menuDown);
6338   if (context_menu_value == -1)
6339     context_menu_value = [sender tag];
6340   else
6341     {
6342       NSInteger tag = [sender tag];
6343       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6344                                     emacsframe->menu_bar_vector,
6345                                     (void *)tag);
6346     }
6348   ns_send_appdefined (-1);
6349   return self;
6353 - (EmacsToolbar *)toolbar
6355   return toolbar;
6359 /* this gets called on toolbar button click */
6360 - toolbarClicked: (id)item
6362   NSEvent *theEvent;
6363   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6365   NSTRACE (toolbarClicked);
6367   if (!emacs_event)
6368     return self;
6370   /* send first event (for some reason two needed) */
6371   theEvent = [[self window] currentEvent];
6372   emacs_event->kind = TOOL_BAR_EVENT;
6373   XSETFRAME (emacs_event->arg, emacsframe);
6374   EV_TRAILER (theEvent);
6376   emacs_event->kind = TOOL_BAR_EVENT;
6377 /*   XSETINT (emacs_event->code, 0); */
6378   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6379                            idx + TOOL_BAR_ITEM_KEY);
6380   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6381   EV_TRAILER (theEvent);
6382   return self;
6386 - toggleToolbar: (id)sender
6388   if (!emacs_event)
6389     return self;
6391   emacs_event->kind = NS_NONKEY_EVENT;
6392   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6393   EV_TRAILER ((id)nil);
6394   return self;
6398 - (void)drawRect: (NSRect)rect
6400   int x = NSMinX (rect), y = NSMinY (rect);
6401   int width = NSWidth (rect), height = NSHeight (rect);
6403   NSTRACE (drawRect);
6405   if (!emacsframe || !emacsframe->output_data.ns)
6406     return;
6408   ns_clear_frame_area (emacsframe, x, y, width, height);
6409   expose_frame (emacsframe, x, y, width, height);
6411   /*
6412     drawRect: may be called (at least in OS X 10.5) for invisible
6413     views as well for some reason.  Thus, do not infer visibility
6414     here.
6416     emacsframe->async_visible = 1;
6417     emacsframe->async_iconified = 0;
6418   */
6422 /* NSDraggingDestination protocol methods.  Actually this is not really a
6423    protocol, but a category of Object.  O well...  */
6425 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6427   NSTRACE (draggingEntered);
6428   return NSDragOperationGeneric;
6432 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6434   return YES;
6438 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6440   id pb;
6441   int x, y;
6442   NSString *type;
6443   NSEvent *theEvent = [[self window] currentEvent];
6444   NSPoint position;
6446   NSTRACE (performDragOperation);
6448   if (!emacs_event)
6449     return NO;
6451   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6452   x = lrint (position.x);  y = lrint (position.y);
6454   pb = [sender draggingPasteboard];
6455   type = [pb availableTypeFromArray: ns_drag_types];
6456   if (type == 0)
6457     {
6458       return NO;
6459     }
6460   else if ([type isEqualToString: NSFilenamesPboardType])
6461     {
6462       NSArray *files;
6463       NSEnumerator *fenum;
6464       NSString *file;
6466       if (!(files = [pb propertyListForType: type]))
6467         return NO;
6469       fenum = [files objectEnumerator];
6470       while ( (file = [fenum nextObject]) )
6471         {
6472           emacs_event->kind = NS_NONKEY_EVENT;
6473           emacs_event->code = KEY_NS_DRAG_FILE;
6474           XSETINT (emacs_event->x, x);
6475           XSETINT (emacs_event->y, y);
6476           ns_input_file = append2 (ns_input_file,
6477                                    build_string ([file UTF8String]));
6478           emacs_event->modifiers = EV_MODIFIERS (theEvent);
6479           EV_TRAILER (theEvent);
6480         }
6481       return YES;
6482     }
6483   else if ([type isEqualToString: NSURLPboardType])
6484     {
6485       NSString *file;
6486       NSURL *fileURL;
6488       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6489           [fileURL isFileURL] == NO)
6490         return NO;
6492       file = [fileURL path];
6493       emacs_event->kind = NS_NONKEY_EVENT;
6494       emacs_event->code = KEY_NS_DRAG_FILE;
6495       XSETINT (emacs_event->x, x);
6496       XSETINT (emacs_event->y, y);
6497       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6498       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6499       EV_TRAILER (theEvent);
6500       return YES;
6501     }
6502   else if ([type isEqualToString: NSStringPboardType]
6503            || [type isEqualToString: NSTabularTextPboardType])
6504     {
6505       NSString *data;
6507       if (! (data = [pb stringForType: type]))
6508         return NO;
6510       emacs_event->kind = NS_NONKEY_EVENT;
6511       emacs_event->code = KEY_NS_DRAG_TEXT;
6512       XSETINT (emacs_event->x, x);
6513       XSETINT (emacs_event->y, y);
6514       ns_input_text = build_string ([data UTF8String]);
6515       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6516       EV_TRAILER (theEvent);
6517       return YES;
6518     }
6519   else if ([type isEqualToString: NSColorPboardType])
6520     {
6521       NSColor *c = [NSColor colorFromPasteboard: pb];
6522       emacs_event->kind = NS_NONKEY_EVENT;
6523       emacs_event->code = KEY_NS_DRAG_COLOR;
6524       XSETINT (emacs_event->x, x);
6525       XSETINT (emacs_event->y, y);
6526       ns_input_color = ns_color_to_lisp (c);
6527       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6528       EV_TRAILER (theEvent);
6529       return YES;
6530     }
6531   else if ([type isEqualToString: NSFontPboardType])
6532     {
6533       /* impl based on GNUstep NSTextView.m */
6534       NSData *data = [pb dataForType: NSFontPboardType];
6535       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6536       NSFont *font = [dict objectForKey: NSFontAttributeName];
6537       char fontSize[10];
6539       if (font == nil)
6540         return NO;
6542       emacs_event->kind = NS_NONKEY_EVENT;
6543       emacs_event->code = KEY_NS_CHANGE_FONT;
6544       XSETINT (emacs_event->x, x);
6545       XSETINT (emacs_event->y, y);
6546       ns_input_font = build_string ([[font fontName] UTF8String]);
6547       snprintf (fontSize, 10, "%f", [font pointSize]);
6548       ns_input_fontsize = build_string (fontSize);
6549       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6550       EV_TRAILER (theEvent);
6551       return YES;
6552     }
6553   else
6554     {
6555       error ("Invalid data type in dragging pasteboard.");
6556       return NO;
6557     }
6561 - (id) validRequestorForSendType: (NSString *)typeSent
6562                       returnType: (NSString *)typeReturned
6564   NSTRACE (validRequestorForSendType);
6565   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6566       && typeReturned == nil)
6567     {
6568       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6569         return self;
6570     }
6572   return [super validRequestorForSendType: typeSent
6573                                returnType: typeReturned];
6577 /* The next two methods are part of NSServicesRequests informal protocol,
6578    supposedly called when a services menu item is chosen from this app.
6579    But this should not happen because we override the services menu with our
6580    own entries which call ns-perform-service.
6581    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6582    So let's at least stub them out until further investigation can be done. */
6584 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6586   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6587      be written into the buffer in place of the existing selection..
6588      ordinary service calls go through functions defined in ns-win.el */
6589   return NO;
6592 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6594   NSArray *typesDeclared;
6595   Lisp_Object val;
6597   /* We only support NSStringPboardType */
6598   if ([types containsObject:NSStringPboardType] == NO) {
6599     return NO;
6600   }
6602   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6603   if (CONSP (val) && SYMBOLP (XCAR (val)))
6604     {
6605       val = XCDR (val);
6606       if (CONSP (val) && NILP (XCDR (val)))
6607         val = XCAR (val);
6608     }
6609   if (! STRINGP (val))
6610     return NO;
6612   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6613   [pb declareTypes:typesDeclared owner:nil];
6614   ns_string_to_pasteboard (pb, val);
6615   return YES;
6619 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6620    (gives a miniaturized version of the window); currently we use the latter for
6621    frames whose active buffer doesn't correspond to any file
6622    (e.g., '*scratch*') */
6623 - setMiniwindowImage: (BOOL) setMini
6625   id image = [[self window] miniwindowImage];
6626   NSTRACE (setMiniwindowImage);
6628   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6629      about "AppleDockIconEnabled" notwithstanding, however the set message
6630      below has its effect nonetheless. */
6631   if (image != emacsframe->output_data.ns->miniimage)
6632     {
6633       if (image && [image isKindOfClass: [EmacsImage class]])
6634         [image release];
6635       [[self window] setMiniwindowImage:
6636                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6637     }
6639   return self;
6643 - (void) setRows: (int) r andColumns: (int) c
6645   rows = r;
6646   cols = c;
6649 @end  /* EmacsView */
6653 /* ==========================================================================
6655     EmacsWindow implementation
6657    ========================================================================== */
6659 @implementation EmacsWindow
6661 #ifdef NS_IMPL_COCOA
6662 - (id)accessibilityAttributeValue:(NSString *)attribute
6664   Lisp_Object str = Qnil;
6665   struct frame *f = SELECTED_FRAME ();
6666   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
6668   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6669     return NSAccessibilityTextFieldRole;
6671   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6672       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6673     {
6674       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6675     }
6676   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6677     {
6678       if (! NILP (BVAR (curbuf, mark_active)))
6679           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6681       if (NILP (str))
6682         {
6683           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6684           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6685           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6687           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6688             str = make_uninit_multibyte_string (range, byte_range);
6689           else
6690             str = make_uninit_string (range);
6691           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6692              Is this a problem?  */
6693           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6694         }
6695     }
6698   if (! NILP (str))
6699     {
6700       if (CONSP (str) && SYMBOLP (XCAR (str)))
6701         {
6702           str = XCDR (str);
6703           if (CONSP (str) && NILP (XCDR (str)))
6704             str = XCAR (str);
6705         }
6706       if (STRINGP (str))
6707         {
6708           const char *utfStr = SSDATA (str);
6709           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6710           return nsStr;
6711         }
6712     }
6714   return [super accessibilityAttributeValue:attribute];
6716 #endif /* NS_IMPL_COCOA */
6718 /* If we have multiple monitors, one above the other, we don't want to
6719    restrict the height to just one monitor.  So we override this.  */
6720 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6722   /* When making the frame visible for the first time or if there is just
6723      one screen, we want to constrain.  Other times not.  */
6724   NSUInteger nr_screens = [[NSScreen screens] count];
6725   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6726   NSTRACE (constrainFrameRect);
6728   if (nr_screens == 1)
6729     {
6730       NSRect r = [super constrainFrameRect:frameRect toScreen:screen];
6731       return r;
6732     }
6734   if (f->output_data.ns->dont_constrain
6735       || ns_menu_bar_should_be_hidden ())
6736     return frameRect;
6738   f->output_data.ns->dont_constrain = 1;
6739   return [super constrainFrameRect:frameRect toScreen:screen];
6742 @end /* EmacsWindow */
6745 @implementation EmacsFSWindow
6747 - (BOOL)canBecomeKeyWindow
6749   return YES;
6752 - (BOOL)canBecomeMainWindow
6754   return YES;
6757 @end
6759 /* ==========================================================================
6761     EmacsScroller implementation
6763    ========================================================================== */
6766 @implementation EmacsScroller
6768 /* for repeat button push */
6769 #define SCROLL_BAR_FIRST_DELAY 0.5
6770 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6772 + (CGFloat) scrollerWidth
6774   /* TODO: if we want to allow variable widths, this is the place to do it,
6775            however neither GNUstep nor Cocoa support it very well */
6776   return [NSScroller scrollerWidth];
6780 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6782   NSTRACE (EmacsScroller_initFrame);
6784   r.size.width = [EmacsScroller scrollerWidth];
6785   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6786   [self setContinuous: YES];
6787   [self setEnabled: YES];
6789   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6790      locked against the top and bottom edges, and right edge on OS X, where
6791      scrollers are on right. */
6792 #ifdef NS_IMPL_GNUSTEP
6793   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6794 #else
6795   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6796 #endif
6798   win = nwin;
6799   condemned = NO;
6800   pixel_height = NSHeight (r);
6801   if (pixel_height == 0) pixel_height = 1;
6802   min_portion = 20 / pixel_height;
6804   frame = XFRAME (XWINDOW (win)->frame);
6805   if (FRAME_LIVE_P (frame))
6806     {
6807       int i;
6808       EmacsView *view = FRAME_NS_VIEW (frame);
6809       NSView *sview = [[view window] contentView];
6810       NSArray *subs = [sview subviews];
6812       /* disable optimization stopping redraw of other scrollbars */
6813       view->scrollbarsNeedingUpdate = 0;
6814       for (i =[subs count]-1; i >= 0; i--)
6815         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6816           view->scrollbarsNeedingUpdate++;
6817       [sview addSubview: self];
6818     }
6820 /*  [self setFrame: r]; */
6822   return self;
6826 - (void)setFrame: (NSRect)newRect
6828   NSTRACE (EmacsScroller_setFrame);
6829 /*  block_input (); */
6830   pixel_height = NSHeight (newRect);
6831   if (pixel_height == 0) pixel_height = 1;
6832   min_portion = 20 / pixel_height;
6833   [super setFrame: newRect];
6834   [self display];
6835 /*  unblock_input (); */
6839 - (void)dealloc
6841   NSTRACE (EmacsScroller_dealloc);
6842   if (!NILP (win))
6843     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
6844   [super dealloc];
6848 - condemn
6850   NSTRACE (condemn);
6851   condemned =YES;
6852   return self;
6856 - reprieve
6858   NSTRACE (reprieve);
6859   condemned =NO;
6860   return self;
6864 - judge
6866   NSTRACE (judge);
6867   if (condemned)
6868     {
6869       EmacsView *view;
6870       block_input ();
6871       /* ensure other scrollbar updates after deletion */
6872       view = (EmacsView *)FRAME_NS_VIEW (frame);
6873       if (view != nil)
6874         view->scrollbarsNeedingUpdate++;
6875       [self removeFromSuperview];
6876       [self release];
6877       unblock_input ();
6878     }
6879   return self;
6883 - (void)resetCursorRects
6885   NSRect visible = [self visibleRect];
6886   NSTRACE (resetCursorRects);
6888   if (!NSIsEmptyRect (visible))
6889     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6890   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6894 - (int) checkSamePosition: (int) position portion: (int) portion
6895                     whole: (int) whole
6897   return em_position ==position && em_portion ==portion && em_whole ==whole
6898     && portion != whole; /* needed for resize empty buf */
6902 - setPosition: (int)position portion: (int)portion whole: (int)whole
6904   NSTRACE (setPosition);
6906   em_position = position;
6907   em_portion = portion;
6908   em_whole = whole;
6910   if (portion >= whole)
6911     {
6912 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6913       [self setKnobProportion: 1.0];
6914       [self setDoubleValue: 1.0];
6915 #else
6916       [self setFloatValue: 0.0 knobProportion: 1.0];
6917 #endif
6918     }
6919   else
6920     {
6921       float pos;
6922       CGFloat por;
6923       portion = max ((float)whole*min_portion/pixel_height, portion);
6924       pos = (float)position / (whole - portion);
6925       por = (CGFloat)portion/whole;
6926 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6927       [self setKnobProportion: por];
6928       [self setDoubleValue: pos];
6929 #else
6930       [self setFloatValue: pos knobProportion: por];
6931 #endif
6932     }
6934   /* Events may come here even if the event loop is not running.
6935      If we don't enter the event loop, the scroll bar will not update.
6936      So send SIGIO to ourselves.  */
6937   if (apploopnr == 0) raise (SIGIO);
6939   return self;
6942 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6943      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6944 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6945                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6947   *part = last_hit_part;
6948   *window = win;
6949   XSETINT (*y, pixel_height);
6950   if ([self floatValue] > 0.999F)
6951     XSETINT (*x, pixel_height);
6952   else
6953     XSETINT (*x, pixel_height * [self floatValue]);
6957 /* set up emacs_event */
6958 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6960   if (!emacs_event)
6961     return;
6963   emacs_event->part = last_hit_part;
6964   emacs_event->code = 0;
6965   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6966   emacs_event->frame_or_window = win;
6967   emacs_event->timestamp = EV_TIMESTAMP (e);
6968   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6969   emacs_event->arg = Qnil;
6970   XSETINT (emacs_event->x, loc * pixel_height);
6971   XSETINT (emacs_event->y, pixel_height-20);
6973   if (q_event_ptr)
6974     {
6975       n_emacs_events_pending++;
6976       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6977     }
6978   else
6979     hold_event (emacs_event);
6980   EVENT_INIT (*emacs_event);
6981   ns_send_appdefined (-1);
6985 /* called manually thru timer to implement repeated button action w/hold-down */
6986 - repeatScroll: (NSTimer *)scrollEntry
6988   NSEvent *e = [[self window] currentEvent];
6989   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6990   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6992   /* clear timer if need be */
6993   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6994     {
6995         [scroll_repeat_entry invalidate];
6996         [scroll_repeat_entry release];
6997         scroll_repeat_entry = nil;
6999         if (inKnob)
7000           return self;
7002         scroll_repeat_entry
7003           = [[NSTimer scheduledTimerWithTimeInterval:
7004                         SCROLL_BAR_CONTINUOUS_DELAY
7005                                             target: self
7006                                           selector: @selector (repeatScroll:)
7007                                           userInfo: 0
7008                                            repeats: YES]
7009               retain];
7010     }
7012   [self sendScrollEventAtLoc: 0 fromEvent: e];
7013   return self;
7017 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
7018    mouseDragged events without going into a modal loop. */
7019 - (void)mouseDown: (NSEvent *)e
7021   NSRect sr, kr;
7022   /* hitPart is only updated AFTER event is passed on */
7023   NSScrollerPart part = [self testPart: [e locationInWindow]];
7024   CGFloat inc = 0.0, loc, kloc, pos;
7025   int edge = 0;
7027   NSTRACE (EmacsScroller_mouseDown);
7029   switch (part)
7030     {
7031     case NSScrollerDecrementPage:
7032         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7033     case NSScrollerIncrementPage:
7034         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7035     case NSScrollerDecrementLine:
7036       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7037     case NSScrollerIncrementLine:
7038       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7039     case NSScrollerKnob:
7040       last_hit_part = scroll_bar_handle; break;
7041     case NSScrollerKnobSlot:  /* GNUstep-only */
7042       last_hit_part = scroll_bar_move_ratio; break;
7043     default:  /* NSScrollerNoPart? */
7044       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7045                (long) part);
7046       return;
7047     }
7049   if (inc != 0.0)
7050     {
7051       pos = 0;      /* ignored */
7053       /* set a timer to repeat, as we can't let superclass do this modally */
7054       scroll_repeat_entry
7055         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7056                                             target: self
7057                                           selector: @selector (repeatScroll:)
7058                                           userInfo: 0
7059                                            repeats: YES]
7060             retain];
7061     }
7062   else
7063     {
7064       /* handle, or on GNUstep possibly slot */
7065       NSEvent *fake_event;
7067       /* compute float loc in slot and mouse offset on knob */
7068       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7069                       toView: nil];
7070       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7071       if (loc <= 0.0)
7072         {
7073           loc = 0.0;
7074           edge = -1;
7075         }
7076       else if (loc >= NSHeight (sr))
7077         {
7078           loc = NSHeight (sr);
7079           edge = 1;
7080         }
7082       if (edge)
7083         kloc = 0.5 * edge;
7084       else
7085         {
7086           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7087                           toView: nil];
7088           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7089         }
7090       last_mouse_offset = kloc;
7092       /* if knob, tell emacs a location offset by knob pos
7093          (to indicate top of handle) */
7094       if (part == NSScrollerKnob)
7095           pos = (loc - last_mouse_offset) / NSHeight (sr);
7096       else
7097         /* else this is a slot click on GNUstep: go straight there */
7098         pos = loc / NSHeight (sr);
7100       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7101       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7102                                       location: [e locationInWindow]
7103                                  modifierFlags: [e modifierFlags]
7104                                      timestamp: [e timestamp]
7105                                   windowNumber: [e windowNumber]
7106                                        context: [e context]
7107                                    eventNumber: [e eventNumber]
7108                                     clickCount: [e clickCount]
7109                                       pressure: [e pressure]];
7110       [super mouseUp: fake_event];
7111     }
7113   if (part != NSScrollerKnob)
7114     [self sendScrollEventAtLoc: pos fromEvent: e];
7118 /* Called as we manually track scroller drags, rather than superclass. */
7119 - (void)mouseDragged: (NSEvent *)e
7121     NSRect sr;
7122     double loc, pos;
7124     NSTRACE (EmacsScroller_mouseDragged);
7126       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7127                       toView: nil];
7128       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7130       if (loc <= 0.0)
7131         {
7132           loc = 0.0;
7133         }
7134       else if (loc >= NSHeight (sr) + last_mouse_offset)
7135         {
7136           loc = NSHeight (sr) + last_mouse_offset;
7137         }
7139       pos = (loc - last_mouse_offset) / NSHeight (sr);
7140       [self sendScrollEventAtLoc: pos fromEvent: e];
7144 - (void)mouseUp: (NSEvent *)e
7146   if (scroll_repeat_entry)
7147     {
7148       [scroll_repeat_entry invalidate];
7149       [scroll_repeat_entry release];
7150       scroll_repeat_entry = nil;
7151     }
7152   last_hit_part = 0;
7156 /* treat scrollwheel events in the bar as though they were in the main window */
7157 - (void) scrollWheel: (NSEvent *)theEvent
7159   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7160   [view mouseDown: theEvent];
7163 @end  /* EmacsScroller */
7166 #ifdef NS_IMPL_GNUSTEP
7167 /* Dummy class to get rid of startup warnings.  */
7168 @implementation EmacsDocument
7170 @end
7171 #endif
7174 /* ==========================================================================
7176    Font-related functions; these used to be in nsfaces.m
7178    ========================================================================== */
7181 Lisp_Object
7182 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7184   struct font *font = XFONT_OBJECT (font_object);
7186   if (fontset < 0)
7187     fontset = fontset_from_font (font_object);
7188   FRAME_FONTSET (f) = fontset;
7190   if (FRAME_FONT (f) == font)
7191     /* This font is already set in frame F.  There's nothing more to
7192        do.  */
7193     return font_object;
7195   FRAME_FONT (f) = font;
7197   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7198   FRAME_COLUMN_WIDTH (f) = font->average_width;
7199   FRAME_LINE_HEIGHT (f) = font->height;
7201   compute_fringe_widths (f, 1);
7203   /* Compute the scroll bar width in character columns.  */
7204   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7205     {
7206       int wid = FRAME_COLUMN_WIDTH (f);
7207       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7208         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7209     }
7210   else
7211     {
7212       int wid = FRAME_COLUMN_WIDTH (f);
7213       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7214     }
7216   /* Now make the frame display the given font.  */
7217   if (FRAME_NS_WINDOW (f) != 0)
7218         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
7220   return font_object;
7224 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7225 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7226          in 1.43. */
7228 const char *
7229 ns_xlfd_to_fontname (const char *xlfd)
7230 /* --------------------------------------------------------------------------
7231     Convert an X font name (XLFD) to an NS font name.
7232     Only family is used.
7233     The string returned is temporarily allocated.
7234    -------------------------------------------------------------------------- */
7236   char *name = xmalloc (180);
7237   int i, len;
7238   const char *ret;
7240   if (!strncmp (xlfd, "--", 2))
7241     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7242   else
7243     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7245   /* stopgap for malformed XLFD input */
7246   if (strlen (name) == 0)
7247     strcpy (name, "Monaco");
7249   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7250      also uppercase after '-' or ' ' */
7251   name[0] = c_toupper (name[0]);
7252   for (len =strlen (name), i =0; i<len; i++)
7253     {
7254       if (name[i] == '$')
7255         {
7256           name[i] = '-';
7257           if (i+1<len)
7258             name[i+1] = c_toupper (name[i+1]);
7259         }
7260       else if (name[i] == '_')
7261         {
7262           name[i] = ' ';
7263           if (i+1<len)
7264             name[i+1] = c_toupper (name[i+1]);
7265         }
7266     }
7267 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7268   ret = [[NSString stringWithUTF8String: name] UTF8String];
7269   xfree (name);
7270   return ret;
7274 void
7275 syms_of_nsterm (void)
7277   NSTRACE (syms_of_nsterm);
7279   ns_antialias_threshold = 10.0;
7281   /* from 23+ we need to tell emacs what modifiers there are.. */
7282   DEFSYM (Qmodifier_value, "modifier-value");
7283   DEFSYM (Qalt, "alt");
7284   DEFSYM (Qhyper, "hyper");
7285   DEFSYM (Qmeta, "meta");
7286   DEFSYM (Qsuper, "super");
7287   DEFSYM (Qcontrol, "control");
7288   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7290   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7291   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7292   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7293   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7294   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7296   DEFVAR_LISP ("ns-input-file", ns_input_file,
7297               "The file specified in the last NS event.");
7298   ns_input_file =Qnil;
7300   DEFVAR_LISP ("ns-input-text", ns_input_text,
7301               "The data received in the last NS text drag event.");
7302   ns_input_text =Qnil;
7304   DEFVAR_LISP ("ns-working-text", ns_working_text,
7305               "String for visualizing working composition sequence.");
7306   ns_working_text =Qnil;
7308   DEFVAR_LISP ("ns-input-font", ns_input_font,
7309               "The font specified in the last NS event.");
7310   ns_input_font =Qnil;
7312   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7313               "The fontsize specified in the last NS event.");
7314   ns_input_fontsize =Qnil;
7316   DEFVAR_LISP ("ns-input-line", ns_input_line,
7317                "The line specified in the last NS event.");
7318   ns_input_line =Qnil;
7320   DEFVAR_LISP ("ns-input-color", ns_input_color,
7321                "The color specified in the last NS event.");
7322   ns_input_color =Qnil;
7324   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7325                "The service name specified in the last NS event.");
7326   ns_input_spi_name =Qnil;
7328   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7329                "The service argument specified in the last NS event.");
7330   ns_input_spi_arg =Qnil;
7332   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7333                "This variable describes the behavior of the alternate or option key.\n\
7334 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7335 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7336 at all, allowing it to be used at a lower level for accented character entry.");
7337   ns_alternate_modifier = Qmeta;
7339   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7340                "This variable describes the behavior of the right alternate or option key.\n\
7341 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7342 Set to left means be the same key as `ns-alternate-modifier'.\n\
7343 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7344 at all, allowing it to be used at a lower level for accented character entry.");
7345   ns_right_alternate_modifier = Qleft;
7347   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7348                "This variable describes the behavior of the command key.\n\
7349 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7350   ns_command_modifier = Qsuper;
7352   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7353                "This variable describes the behavior of the right command key.\n\
7354 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7355 Set to left means be the same key as `ns-command-modifier'.\n\
7356 Set to none means that the command / option key is not interpreted by Emacs\n\
7357 at all, allowing it to be used at a lower level for accented character entry.");
7358   ns_right_command_modifier = Qleft;
7360   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7361                "This variable describes the behavior of the control key.\n\
7362 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7363   ns_control_modifier = Qcontrol;
7365   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7366                "This variable describes the behavior of the right control key.\n\
7367 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7368 Set to left means be the same key as `ns-control-modifier'.\n\
7369 Set to none means that the control / option key is not interpreted by Emacs\n\
7370 at all, allowing it to be used at a lower level for accented character entry.");
7371   ns_right_control_modifier = Qleft;
7373   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7374                "This variable describes the behavior of the function key (on laptops).\n\
7375 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7376 Set to none means that the function key is not interpreted by Emacs at all,\n\
7377 allowing it to be used at a lower level for accented character entry.");
7378   ns_function_modifier = Qnone;
7380   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7381                "Non-nil (the default) means to render text antialiased.");
7382   ns_antialias_text = Qt;
7384   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7385                "Whether to confirm application quit using dialog.");
7386   ns_confirm_quit = Qnil;
7388   staticpro (&ns_display_name_list);
7389   ns_display_name_list = Qnil;
7391   staticpro (&last_mouse_motion_frame);
7392   last_mouse_motion_frame = Qnil;
7394   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7395                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7396 Only works on OSX 10.6 or later.  */);
7397   ns_auto_hide_menu_bar = Qnil;
7399   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7400      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7401 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7402 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7403 Default is t for OSX >= 10.7, nil otherwise. */);
7404 #ifdef HAVE_NATIVE_FS
7405   ns_use_native_fullscreen = YES;
7406 #else
7407   ns_use_native_fullscreen = NO;
7408 #endif
7409   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7411   /* TODO: move to common code */
7412   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7413                doc: /* Which toolkit scroll bars Emacs uses, if any.
7414 A value of nil means Emacs doesn't use toolkit scroll bars.
7415 With the X Window system, the value is a symbol describing the
7416 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7417 With MS Windows or Nextstep, the value is t.  */);
7418   Vx_toolkit_scroll_bars = Qt;
7420   DEFVAR_BOOL ("x-use-underline-position-properties",
7421                x_use_underline_position_properties,
7422      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7423 A value of nil means ignore them.  If you encounter fonts with bogus
7424 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7425 to 4.1, set this to nil. */);
7426   x_use_underline_position_properties = 0;
7428   DEFVAR_BOOL ("x-underline-at-descent-line",
7429                x_underline_at_descent_line,
7430      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7431 A value of nil means to draw the underline according to the value of the
7432 variable `x-use-underline-position-properties', which is usually at the
7433 baseline level.  The default value is nil.  */);
7434   x_underline_at_descent_line = 0;
7436   /* Tell Emacs about this window system.  */
7437   Fprovide (Qns, Qnil);