Auto-commit of generated files.
[emacs.git] / src / nsterm.m
blobf374bfd90c630f9a521dba44bacd5d024cc0b0be
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 EMACS_TIME select_timeout = { 0, 0 };
218 static int selfds[2] = { -1, -1 };
219 static pthread_mutex_t select_mutex;
220 static int apploopnr = 0;
221 static NSAutoreleasePool *outerpool;
222 static struct input_event *emacs_event = NULL;
223 static struct input_event *q_event_ptr = NULL;
224 static int n_emacs_events_pending = 0;
225 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
226   *ns_pending_service_args;
227 static BOOL ns_do_open_file = NO;
228 static BOOL ns_last_use_native_fullscreen;
230 static struct {
231   struct input_event *q;
232   int nr, cap;
233 } hold_event_q = {
234   NULL, 0, 0
237 #ifdef NS_IMPL_COCOA
239  * State for pending menu activation:
240  * MENU_NONE     Normal state
241  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
242  *               run lisp to update the menu.
243  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
244  *               will open.
245  */
246 #define MENU_NONE 0
247 #define MENU_PENDING 1
248 #define MENU_OPENING 2
249 static int menu_will_open_state = MENU_NONE;
251 /* Saved position for menu click.  */
252 static CGPoint menu_mouse_point;
253 #endif
255 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
256 #define NS_FUNCTION_KEY_MASK 0x800000
257 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
258 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
259 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
260 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
261 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
262 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
263 #define EV_MODIFIERS(e)                               \
264     ((([e modifierFlags] & NSHelpKeyMask) ?           \
265            hyper_modifier : 0)                        \
266      | (!EQ (ns_right_alternate_modifier, Qleft) && \
267         (([e modifierFlags] & NSRightAlternateKeyMask) \
268          == NSRightAlternateKeyMask) ? \
269            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
270      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
271            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
272      | (([e modifierFlags] & NSShiftKeyMask) ?     \
273            shift_modifier : 0)                        \
274      | (!EQ (ns_right_control_modifier, Qleft) && \
275         (([e modifierFlags] & NSRightControlKeyMask) \
276          == NSRightControlKeyMask) ? \
277            parse_solitary_modifier (ns_right_control_modifier) : 0) \
278      | (([e modifierFlags] & NSControlKeyMask) ?      \
279            parse_solitary_modifier (ns_control_modifier) : 0)     \
280      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
281            parse_solitary_modifier (ns_function_modifier) : 0)    \
282      | (!EQ (ns_right_command_modifier, Qleft) && \
283         (([e modifierFlags] & NSRightCommandKeyMask) \
284          == NSRightCommandKeyMask) ? \
285            parse_solitary_modifier (ns_right_command_modifier) : 0) \
286      | (([e modifierFlags] & NSCommandKeyMask) ?      \
287            parse_solitary_modifier (ns_command_modifier):0))
289 #define EV_UDMODIFIERS(e)                                      \
290     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
291      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
292      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
293      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
294      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
295      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
296      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
297      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
298      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
300 #define EV_BUTTON(e)                                                         \
301     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
302       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
303      [e buttonNumber] - 1)
305 /* Convert the time field to a timestamp in milliseconds. */
306 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
308 /* This is a piece of code which is common to all the event handling
309    methods.  Maybe it should even be a function.  */
310 #define EV_TRAILER(e)                                                   \
311     {                                                                   \
312       XSETFRAME (emacs_event->frame_or_window, emacsframe);             \
313       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
314       if (q_event_ptr)                                                  \
315         {                                                               \
316           n_emacs_events_pending++;                                     \
317           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
318         }                                                               \
319       else                                                              \
320         hold_event (emacs_event);                                       \
321       EVENT_INIT (*emacs_event);                                        \
322       ns_send_appdefined (-1);                                          \
323     }
325 /* TODO: get rid of need for these forward declarations */
326 static void ns_condemn_scroll_bars (struct frame *f);
327 static void ns_judge_scroll_bars (struct frame *f);
328 void x_set_frame_alpha (struct frame *f);
331 /* ==========================================================================
333     Utilities
335    ========================================================================== */
337 static void
338 hold_event (struct input_event *event)
340   if (hold_event_q.nr == hold_event_q.cap)
341     {
342       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
343       else hold_event_q.cap *= 2;
344       hold_event_q.q =
345         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
346     }
348   hold_event_q.q[hold_event_q.nr++] = *event;
349   /* Make sure ns_read_socket is called, i.e. we have input.  */
350   raise (SIGIO);
351   send_appdefined = YES;
354 static Lisp_Object
355 append2 (Lisp_Object list, Lisp_Object item)
356 /* --------------------------------------------------------------------------
357    Utility to append to a list
358    -------------------------------------------------------------------------- */
360   Lisp_Object array[2];
361   array[0] = list;
362   array[1] = list1 (item);
363   return Fnconc (2, &array[0]);
367 const char *
368 ns_etc_directory (void)
369 /* If running as a self-contained app bundle, return as a string the
370    filename of the etc directory, if present; else nil.  */
372   NSBundle *bundle = [NSBundle mainBundle];
373   NSString *resourceDir = [bundle resourcePath];
374   NSString *resourcePath;
375   NSFileManager *fileManager = [NSFileManager defaultManager];
376   BOOL isDir;
378   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
379   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
380     {
381       if (isDir) return [resourcePath UTF8String];
382     }
383   return NULL;
387 const char *
388 ns_exec_path (void)
389 /* If running as a self-contained app bundle, return as a path string
390    the filenames of the libexec and bin directories, ie libexec:bin.
391    Otherwise, return nil.
392    Normally, Emacs does not add its own bin/ directory to the PATH.
393    However, a self-contained NS build has a different layout, with
394    bin/ and libexec/ subdirectories in the directory that contains
395    Emacs.app itself.
396    We put libexec first, because init_callproc_1 uses the first
397    element to initialize exec-directory.  An alternative would be
398    for init_callproc to check for invocation-directory/libexec.
401   NSBundle *bundle = [NSBundle mainBundle];
402   NSString *resourceDir = [bundle resourcePath];
403   NSString *binDir = [bundle bundlePath];
404   NSString *resourcePath, *resourcePaths;
405   NSRange range;
406   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
407   NSFileManager *fileManager = [NSFileManager defaultManager];
408   NSArray *paths;
409   NSEnumerator *pathEnum;
410   BOOL isDir;
412   range = [resourceDir rangeOfString: @"Contents"];
413   if (range.location != NSNotFound)
414     {
415       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
416 #ifdef NS_IMPL_COCOA
417       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
418 #endif
419     }
421   paths = [binDir stringsByAppendingPaths:
422                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
423   pathEnum = [paths objectEnumerator];
424   resourcePaths = @"";
426   while ((resourcePath = [pathEnum nextObject]))
427     {
428       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
429         if (isDir)
430           {
431             if ([resourcePaths length] > 0)
432               resourcePaths
433                 = [resourcePaths stringByAppendingString: pathSeparator];
434             resourcePaths
435               = [resourcePaths stringByAppendingString: resourcePath];
436           }
437     }
438   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
440   return NULL;
444 const char *
445 ns_load_path (void)
446 /* If running as a self-contained app bundle, return as a path string
447    the filenames of the site-lisp, lisp and leim directories.
448    Ie, site-lisp:lisp:leim.  Otherwise, return nil.  */
450   NSBundle *bundle = [NSBundle mainBundle];
451   NSString *resourceDir = [bundle resourcePath];
452   NSString *resourcePath, *resourcePaths;
453   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
454   NSFileManager *fileManager = [NSFileManager defaultManager];
455   BOOL isDir;
456   NSArray *paths = [resourceDir stringsByAppendingPaths:
457                               [NSArray arrayWithObjects:
458                                          @"site-lisp", @"lisp", @"leim", nil]];
459   NSEnumerator *pathEnum = [paths objectEnumerator];
460   resourcePaths = @"";
462   /* Hack to skip site-lisp.  */
463   if (no_site_lisp) resourcePath = [pathEnum nextObject];
465   while ((resourcePath = [pathEnum nextObject]))
466     {
467       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
468         if (isDir)
469           {
470             if ([resourcePaths length] > 0)
471               resourcePaths
472                 = [resourcePaths stringByAppendingString: pathSeparator];
473             resourcePaths
474               = [resourcePaths stringByAppendingString: resourcePath];
475           }
476     }
477   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
479   return NULL;
482 static void
483 ns_timeout (int usecs)
484 /* --------------------------------------------------------------------------
485      Blocking timer utility used by ns_ring_bell
486    -------------------------------------------------------------------------- */
488   EMACS_TIME wakeup = add_emacs_time (current_emacs_time (),
489                                       make_emacs_time (0, usecs * 1000));
491   /* Keep waiting until past the time wakeup.  */
492   while (1)
493     {
494       EMACS_TIME timeout, now = current_emacs_time ();
495       if (EMACS_TIME_LE (wakeup, now))
496         break;
497       timeout = sub_emacs_time (wakeup, now);
499       /* Try to wait that long--but we might wake up sooner.  */
500       pselect (0, NULL, NULL, NULL, &timeout, NULL);
501     }
505 void
506 ns_release_object (void *obj)
507 /* --------------------------------------------------------------------------
508     Release an object (callable from C)
509    -------------------------------------------------------------------------- */
511     [(id)obj release];
515 void
516 ns_retain_object (void *obj)
517 /* --------------------------------------------------------------------------
518     Retain an object (callable from C)
519    -------------------------------------------------------------------------- */
521     [(id)obj retain];
525 void *
526 ns_alloc_autorelease_pool (void)
527 /* --------------------------------------------------------------------------
528      Allocate a pool for temporary objects (callable from C)
529    -------------------------------------------------------------------------- */
531   return [[NSAutoreleasePool alloc] init];
535 void
536 ns_release_autorelease_pool (void *pool)
537 /* --------------------------------------------------------------------------
538      Free a pool and temporary objects it refers to (callable from C)
539    -------------------------------------------------------------------------- */
541   ns_release_object (pool);
546 /* ==========================================================================
548     Focus (clipping) and screen update
550    ========================================================================== */
553 // Window constraining
554 // -------------------
556 // To ensure that the windows are not placed under the menu bar, they
557 // are typically moved by the call-back constrainFrameRect. However,
558 // by overriding it, it's possible to inhibit this, leaving the window
559 // in it's original position.
561 // It's possible to hide the menu bar. However, technically, it's only
562 // possible to hide it when the application is active. To ensure that
563 // this work properly, the menu bar and window constraining are
564 // deferred until the application becomes active.
566 // Even though it's not possible to manually move a window above the
567 // top of the screen, it is allowed if it's done programmatically,
568 // when the menu is hidden. This allows the editable area to cover the
569 // full screen height.
571 // Test cases
572 // ----------
574 // Use the following extra files:
576 //    init.el:
577 //       ;; Hide menu and place frame slightly above the top of the screen.
578 //       (setq ns-auto-hide-menu-bar t)
579 //       (set-frame-position (selected-frame) 0 -20)
581 // Test 1:
583 //    emacs -Q -l init.el
585 //    Result: No menu bar, and the title bar should be above the screen.
587 // Test 2:
589 //    emacs -Q
591 //    Result: Menu bar visible, frame placed immediately below the menu.
594 static void
595 ns_constrain_all_frames (void)
597   Lisp_Object tail, frame;
599   FOR_EACH_FRAME (tail, frame)
600     {
601       struct frame *f = XFRAME (frame);
602       if (FRAME_NS_P (f))
603         {
604           NSView *view = FRAME_NS_VIEW (f);
605           /* This no-op will trigger the default window placing
606            * constraint system. */
607           f->output_data.ns->dont_constrain = 0;
608           [[view window] setFrameOrigin:[[view window] frame].origin];
609         }
610     }
614 /* True, if the menu bar should be hidden.  */
616 static BOOL
617 ns_menu_bar_should_be_hidden (void)
619   return !NILP (ns_auto_hide_menu_bar)
620     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
624 /* Show or hide the menu bar, based on user setting.  */
626 static void
627 ns_update_auto_hide_menu_bar (void)
629 #ifdef NS_IMPL_COCOA
630 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
631   block_input ();
633   NSTRACE (ns_update_auto_hide_menu_bar);
635   if (NSApp != nil
636       && [NSApp isActive]
637       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
638     {
639       // Note, "setPresentationOptions" triggers an error unless the
640       // application is active.
641       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
643       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
644         {
645           NSApplicationPresentationOptions options
646             = NSApplicationPresentationAutoHideDock;
648           if (menu_bar_should_be_hidden)
649             options |= NSApplicationPresentationAutoHideMenuBar;
651           [NSApp setPresentationOptions: options];
653           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
655           if (!ns_menu_bar_is_hidden)
656             {
657               ns_constrain_all_frames ();
658             }
659         }
660     }
662   unblock_input ();
663 #endif
664 #endif
668 static void
669 ns_update_begin (struct frame *f)
670 /* --------------------------------------------------------------------------
671    Prepare for a grouped sequence of drawing calls
672    external (RIF) call; whole frame, called before update_window_begin
673    -------------------------------------------------------------------------- */
675   NSView *view = FRAME_NS_VIEW (f);
676   NSTRACE (ns_update_begin);
678   ns_update_auto_hide_menu_bar ();
680   ns_updating_frame = f;
681   [view lockFocus];
683   /* drawRect may have been called for say the minibuffer, and then clip path
684      is for the minibuffer.  But the display engine may draw more because
685      we have set the frame as garbaged.  So reset clip path to the whole
686      view.  */
687 #ifdef NS_IMPL_COCOA
688   {
689     NSBezierPath *bp;
690     NSRect r = [view frame];
691     NSRect cr = [[view window] frame];
692     /* If a large frame size is set, r may be larger than the window frame
693        before constrained.  In that case don't change the clip path, as we
694        will clear in to the tool bar and title bar.  */
695     if (r.size.height
696         + FRAME_NS_TITLEBAR_HEIGHT (f)
697         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
698       {
699         bp = [[NSBezierPath bezierPathWithRect: r] retain];
700         [bp setClip];
701         [bp release];
702       }
703   }
704 #endif
706 #ifdef NS_IMPL_GNUSTEP
707   uRect = NSMakeRect (0, 0, 0, 0);
708 #endif
712 static void
713 ns_update_window_begin (struct window *w)
714 /* --------------------------------------------------------------------------
715    Prepare for a grouped sequence of drawing calls
716    external (RIF) call; for one window, called after update_begin
717    -------------------------------------------------------------------------- */
719   struct frame *f = XFRAME (WINDOW_FRAME (w));
720   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
722   NSTRACE (ns_update_window_begin);
723   set_output_cursor (&w->cursor);
725   block_input ();
727   if (f == hlinfo->mouse_face_mouse_frame)
728     {
729       /* Don't do highlighting for mouse motion during the update.  */
730       hlinfo->mouse_face_defer = 1;
732         /* If the frame needs to be redrawn,
733            simply forget about any prior mouse highlighting.  */
734       if (FRAME_GARBAGED_P (f))
735         hlinfo->mouse_face_window = Qnil;
737       /* (further code for mouse faces ifdef'd out in other terms elided) */
738     }
740   unblock_input ();
744 static void
745 ns_update_window_end (struct window *w, int cursor_on_p,
746                       int mouse_face_overwritten_p)
747 /* --------------------------------------------------------------------------
748    Finished a grouped sequence of drawing calls
749    external (RIF) call; for one window called before update_end
750    -------------------------------------------------------------------------- */
752   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
754   /* note: this fn is nearly identical in all terms */
755   if (!w->pseudo_window_p)
756     {
757       block_input ();
759       if (cursor_on_p)
760         display_and_set_cursor (w, 1,
761                                 output_cursor.hpos, output_cursor.vpos,
762                                 output_cursor.x, output_cursor.y);
764       if (draw_window_fringes (w, 1))
765         x_draw_vertical_border (w);
767       unblock_input ();
768     }
770   /* If a row with mouse-face was overwritten, arrange for
771      frame_up_to_date to redisplay the mouse highlight.  */
772   if (mouse_face_overwritten_p)
773     {
774       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
775       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
776       hlinfo->mouse_face_window = Qnil;
777     }
779   NSTRACE (update_window_end);
783 static void
784 ns_update_end (struct frame *f)
785 /* --------------------------------------------------------------------------
786    Finished a grouped sequence of drawing calls
787    external (RIF) call; for whole frame, called after update_window_end
788    -------------------------------------------------------------------------- */
790   EmacsView *view = FRAME_NS_VIEW (f);
792 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
793   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
795   block_input ();
797   [view unlockFocus];
798   [[view window] flushWindow];
800   unblock_input ();
801   ns_updating_frame = NULL;
802   NSTRACE (ns_update_end);
806 static void
807 ns_flush (struct frame *f)
808 /* --------------------------------------------------------------------------
809    external (RIF) call
810    NS impl is no-op since currently we flush in ns_update_end and elsewhere
811    -------------------------------------------------------------------------- */
813     NSTRACE (ns_flush);
817 static void
818 ns_focus (struct frame *f, NSRect *r, int n)
819 /* --------------------------------------------------------------------------
820    Internal: Focus on given frame.  During small local updates this is used to
821      draw, however during large updates, ns_update_begin and ns_update_end are
822      called to wrap the whole thing, in which case these calls are stubbed out.
823      Except, on GNUstep, we accumulate the rectangle being drawn into, because
824      the back end won't do this automatically, and will just end up flushing
825      the entire window.
826    -------------------------------------------------------------------------- */
828 //  NSTRACE (ns_focus);
829 /* static int c =0;
830    fprintf (stderr, "focus: %d", c++);
831    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
832    fprintf (stderr, "\n"); */
834   if (f != ns_updating_frame)
835     {
836       NSView *view = FRAME_NS_VIEW (f);
837       if (view != focus_view)
838         {
839           if (focus_view != NULL)
840             {
841               [focus_view unlockFocus];
842               [[focus_view window] flushWindow];
843 /*debug_lock--; */
844             }
846           if (view)
847             [view lockFocus];
848           focus_view = view;
849 /*if (view) debug_lock++; */
850         }
851     }
853   /* clipping */
854   if (r)
855     {
856       [[NSGraphicsContext currentContext] saveGraphicsState];
857       if (n == 2)
858         NSRectClipList (r, 2);
859       else
860         NSRectClip (*r);
861       gsaved = YES;
862     }
866 static void
867 ns_unfocus (struct frame *f)
868 /* --------------------------------------------------------------------------
869      Internal: Remove focus on given frame
870    -------------------------------------------------------------------------- */
872 //  NSTRACE (ns_unfocus);
874   if (gsaved)
875     {
876       [[NSGraphicsContext currentContext] restoreGraphicsState];
877       gsaved = NO;
878     }
880   if (f != ns_updating_frame)
881     {
882       if (focus_view != NULL)
883         {
884           [focus_view unlockFocus];
885           [[focus_view window] flushWindow];
886           focus_view = NULL;
887 /*debug_lock--; */
888         }
889     }
893 static void
894 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
895 /* --------------------------------------------------------------------------
896      Internal (but parallels other terms): Focus drawing on given row
897    -------------------------------------------------------------------------- */
899   struct frame *f = XFRAME (WINDOW_FRAME (w));
900   NSRect clip_rect;
901   int window_x, window_y, window_width;
903   window_box (w, area, &window_x, &window_y, &window_width, 0);
905   clip_rect.origin.x = window_x;
906   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
907   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
908   clip_rect.size.width = window_width;
909   clip_rect.size.height = row->visible_height;
911   ns_focus (f, &clip_rect, 1);
915 static void
916 ns_ring_bell (struct frame *f)
917 /* --------------------------------------------------------------------------
918      "Beep" routine
919    -------------------------------------------------------------------------- */
921   NSTRACE (ns_ring_bell);
922   if (visible_bell)
923     {
924       NSAutoreleasePool *pool;
925       struct frame *frame = SELECTED_FRAME ();
926       NSView *view;
928       block_input ();
929       pool = [[NSAutoreleasePool alloc] init];
931       view = FRAME_NS_VIEW (frame);
932       if (view != nil)
933         {
934           NSRect r, surr;
935           NSPoint dim = NSMakePoint (128, 128);
937           r = [view bounds];
938           r.origin.x += (r.size.width - dim.x) / 2;
939           r.origin.y += (r.size.height - dim.y) / 2;
940           r.size.width = dim.x;
941           r.size.height = dim.y;
942           surr = NSInsetRect (r, -2, -2);
943           ns_focus (frame, &surr, 1);
944           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
945           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
946                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
947           NSRectFill (r);
948           [[view window] flushWindow];
949           ns_timeout (150000);
950           [[view window] restoreCachedImage];
951           [[view window] flushWindow];
952           ns_unfocus (frame);
953         }
954       [pool release];
955       unblock_input ();
956     }
957   else
958     {
959       NSBeep ();
960     }
964 static void
965 ns_reset_terminal_modes (struct terminal *terminal)
966 /*  Externally called as hook */
968   NSTRACE (ns_reset_terminal_modes);
972 static void
973 ns_set_terminal_modes (struct terminal *terminal)
974 /*  Externally called as hook */
976   NSTRACE (ns_set_terminal_modes);
981 /* ==========================================================================
983     Frame / window manager related functions
985    ========================================================================== */
988 static void
989 ns_raise_frame (struct frame *f)
990 /* --------------------------------------------------------------------------
991      Bring window to foreground and make it active
992    -------------------------------------------------------------------------- */
994   NSView *view;
995   check_window_system (f);
996   view = FRAME_NS_VIEW (f);
997   block_input ();
998   if (FRAME_VISIBLE_P (f))
999     [[view window] makeKeyAndOrderFront: NSApp];
1000   unblock_input ();
1004 static void
1005 ns_lower_frame (struct frame *f)
1006 /* --------------------------------------------------------------------------
1007      Send window to back
1008    -------------------------------------------------------------------------- */
1010   NSView *view;
1011   check_window_system (f);
1012   view = FRAME_NS_VIEW (f);
1013   block_input ();
1014   [[view window] orderBack: NSApp];
1015   unblock_input ();
1019 static void
1020 ns_frame_raise_lower (struct frame *f, int raise)
1021 /* --------------------------------------------------------------------------
1022      External (hook)
1023    -------------------------------------------------------------------------- */
1025   NSTRACE (ns_frame_raise_lower);
1027   if (raise)
1028     ns_raise_frame (f);
1029   else
1030     ns_lower_frame (f);
1034 static void
1035 ns_frame_rehighlight (struct frame *frame)
1036 /* --------------------------------------------------------------------------
1037      External (hook): called on things like window switching within frame
1038    -------------------------------------------------------------------------- */
1040   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1041   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1043   NSTRACE (ns_frame_rehighlight);
1044   if (dpyinfo->x_focus_frame)
1045     {
1046       dpyinfo->x_highlight_frame
1047         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1048            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1049            : dpyinfo->x_focus_frame);
1050       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1051         {
1052           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1053           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1054         }
1055     }
1056   else
1057       dpyinfo->x_highlight_frame = 0;
1059   if (dpyinfo->x_highlight_frame &&
1060          dpyinfo->x_highlight_frame != old_highlight)
1061     {
1062       if (old_highlight)
1063         {
1064           x_update_cursor (old_highlight, 1);
1065           x_set_frame_alpha (old_highlight);
1066         }
1067       if (dpyinfo->x_highlight_frame)
1068         {
1069           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1070           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1071         }
1072     }
1076 void
1077 x_make_frame_visible (struct frame *f)
1078 /* --------------------------------------------------------------------------
1079      External: Show the window (X11 semantics)
1080    -------------------------------------------------------------------------- */
1082   NSTRACE (x_make_frame_visible);
1083   /* XXX: at some points in past this was not needed, as the only place that
1084      called this (frame.c:Fraise_frame ()) also called raise_lower;
1085      if this ends up the case again, comment this out again. */
1086   if (!FRAME_VISIBLE_P (f))
1087     {
1088       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1090       SET_FRAME_VISIBLE (f, 1);
1091       ns_raise_frame (f);
1093       /* Making a new frame from a fullscreen frame will make the new frame
1094          fullscreen also.  So skip handleFS as this will print an error.  */
1095       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1096           && [view isFullscreen])
1097         return;
1099       if (f->want_fullscreen != FULLSCREEN_NONE)
1100         {
1101           block_input ();
1102           [view handleFS];
1103           unblock_input ();
1104         }
1105     }
1109 void
1110 x_make_frame_invisible (struct frame *f)
1111 /* --------------------------------------------------------------------------
1112      External: Hide the window (X11 semantics)
1113    -------------------------------------------------------------------------- */
1115   NSView *view;
1116   NSTRACE (x_make_frame_invisible);
1117   check_window_system (f);
1118   view = FRAME_NS_VIEW (f);
1119   [[view window] orderOut: NSApp];
1120   SET_FRAME_VISIBLE (f, 0);
1121   SET_FRAME_ICONIFIED (f, 0);
1125 void
1126 x_iconify_frame (struct frame *f)
1127 /* --------------------------------------------------------------------------
1128      External: Iconify window
1129    -------------------------------------------------------------------------- */
1131   NSView *view;
1132   struct ns_display_info *dpyinfo;
1134   NSTRACE (x_iconify_frame);
1135   check_window_system (f);
1136   view = FRAME_NS_VIEW (f);
1137   dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1139   if (dpyinfo->x_highlight_frame == f)
1140     dpyinfo->x_highlight_frame = 0;
1142   if ([[view window] windowNumber] <= 0)
1143     {
1144       /* the window is still deferred.  Make it very small, bring it
1145          on screen and order it out. */
1146       NSRect s = { { 100, 100}, {0, 0} };
1147       NSRect t;
1148       t = [[view window] frame];
1149       [[view window] setFrame: s display: NO];
1150       [[view window] orderBack: NSApp];
1151       [[view window] orderOut: NSApp];
1152       [[view window] setFrame: t display: NO];
1153     }
1154   [[view window] miniaturize: NSApp];
1157 /* Free X resources of frame F.  */
1159 void
1160 x_free_frame_resources (struct frame *f)
1162   NSView *view;
1163   struct ns_display_info *dpyinfo;
1164   Mouse_HLInfo *hlinfo;
1166   NSTRACE (x_free_frame_resources);
1167   check_window_system (f);
1168   view = FRAME_NS_VIEW (f);
1169   dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1170   hlinfo = MOUSE_HL_INFO (f);
1172   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1174   block_input ();
1176   free_frame_menubar (f);
1178   if (FRAME_FACE_CACHE (f))
1179     free_frame_faces (f);
1181   if (f == dpyinfo->x_focus_frame)
1182     dpyinfo->x_focus_frame = 0;
1183   if (f == dpyinfo->x_highlight_frame)
1184     dpyinfo->x_highlight_frame = 0;
1185   if (f == hlinfo->mouse_face_mouse_frame)
1186     {
1187       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1188       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1189       hlinfo->mouse_face_window = Qnil;
1190       hlinfo->mouse_face_mouse_frame = 0;
1191     }
1193   if (f->output_data.ns->miniimage != nil)
1194     [f->output_data.ns->miniimage release];
1196   [[view window] close];
1197   [view release];
1199   xfree (f->output_data.ns);
1201   unblock_input ();
1204 void
1205 x_destroy_window (struct frame *f)
1206 /* --------------------------------------------------------------------------
1207      External: Delete the window
1208    -------------------------------------------------------------------------- */
1210   NSTRACE (x_destroy_window);
1211   check_window_system (f);
1212   x_free_frame_resources (f);
1213   ns_window_num--;
1217 void
1218 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1219 /* --------------------------------------------------------------------------
1220      External: Position the window
1221    -------------------------------------------------------------------------- */
1223   NSView *view = FRAME_NS_VIEW (f);
1224   NSArray *screens = [NSScreen screens];
1225   NSScreen *fscreen = [screens objectAtIndex: 0];
1226   NSScreen *screen = [[view window] screen];
1228   NSTRACE (x_set_offset);
1230   block_input ();
1232   f->left_pos = xoff;
1233   f->top_pos = yoff;
1235   if (view != nil && screen && fscreen)
1236     {
1237       f->left_pos = f->size_hint_flags & XNegative
1238         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1239         : f->left_pos;
1240       /* We use visibleFrame here to take menu bar into account.
1241          Ideally we should also adjust left/top with visibleFrame.origin.  */
1243       f->top_pos = f->size_hint_flags & YNegative
1244         ? ([screen visibleFrame].size.height + f->top_pos
1245            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1246            - FRAME_TOOLBAR_HEIGHT (f))
1247         : f->top_pos;
1248 #ifdef NS_IMPL_GNUSTEP
1249       if (f->left_pos < 100)
1250         f->left_pos = 100;  /* don't overlap menu */
1251 #endif
1252       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1253          menu bar.  */
1254       f->output_data.ns->dont_constrain = 0;
1255       [[view window] setFrameTopLeftPoint:
1256                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1257                                     SCREENMAXBOUND ([fscreen frame].size.height
1258                                                     - NS_TOP_POS (f)))];
1259       f->size_hint_flags &= ~(XNegative|YNegative);
1260     }
1262   unblock_input ();
1266 void
1267 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1268 /* --------------------------------------------------------------------------
1269      Adjust window pixel size based on given character grid size
1270      Impl is a bit more complex than other terms, need to do some
1271      internal clipping.
1272    -------------------------------------------------------------------------- */
1274   EmacsView *view = FRAME_NS_VIEW (f);
1275   NSWindow *window = [view window];
1276   NSRect wr = [window frame];
1277   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1278   int pixelwidth, pixelheight;
1280   NSTRACE (x_set_window_size);
1282   if (view == nil)
1283     return;
1285 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1287   block_input ();
1289   check_frame_size (f, &rows, &cols);
1291   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1292   compute_fringe_widths (f, 0);
1294   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1295   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1297   /* If we have a toolbar, take its height into account. */
1298   if (tb && ! [view isFullscreen])
1299     {
1300     /* NOTE: previously this would generate wrong result if toolbar not
1301              yet displayed and fixing toolbar_height=32 helped, but
1302              now (200903) seems no longer needed */
1303     FRAME_TOOLBAR_HEIGHT (f) =
1304       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1305         - FRAME_NS_TITLEBAR_HEIGHT (f);
1306 #ifdef NS_IMPL_GNUSTEP
1307       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1308 #endif
1309     }
1310   else
1311     FRAME_TOOLBAR_HEIGHT (f) = 0;
1313   wr.size.width = pixelwidth + f->border_width;
1314   wr.size.height = pixelheight;
1315   if (! [view isFullscreen])
1316     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1317       + FRAME_TOOLBAR_HEIGHT (f);
1319   /* Do not try to constrain to this screen.  We may have multiple
1320      screens, and want Emacs to span those.  Constraining to screen
1321      prevents that, and that is not nice to the user.  */
1322  if (f->output_data.ns->zooming)
1323    f->output_data.ns->zooming = 0;
1324  else
1325    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1327   [view setRows: rows andColumns: cols];
1328   [window setFrame: wr display: YES];
1330 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1332   /* This is a trick to compensate for Emacs' managing the scrollbar area
1333      as a fixed number of standard character columns.  Instead of leaving
1334      blank space for the extra, we chopped it off above.  Now for
1335      left-hand scrollbars, we shift all rendering to the left by the
1336      difference between the real width and Emacs' imagined one.  For
1337      right-hand bars, don't worry about it since the extra is never used.
1338      (Obviously doesn't work for vertically split windows tho..) */
1339   {
1340     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1341       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1342                      - NS_SCROLL_BAR_WIDTH (f), 0)
1343       : NSMakePoint (0, 0);
1344     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1345     [view setBoundsOrigin: origin];
1346   }
1348   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1349   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1350   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1351 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1353   mark_window_cursors_off (XWINDOW (f->root_window));
1354   cancel_mouse_face (f);
1356   unblock_input ();
1360 static void
1361 ns_fullscreen_hook (struct frame *f)
1363   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1365   if (!FRAME_VISIBLE_P (f))
1366     return;
1368    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1369     {
1370       /* Old style fs don't initiate correctly if created from
1371          init/default-frame alist, so use a timer (not nice...).
1372       */
1373       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1374                                      selector: @selector (handleFS)
1375                                      userInfo: nil repeats: NO];
1376       return;
1377     }
1379   block_input ();
1380   [view handleFS];
1381   unblock_input ();
1384 /* ==========================================================================
1386     Color management
1388    ========================================================================== */
1391 NSColor *
1392 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1394   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1395   if (idx < 1 || idx >= color_table->avail)
1396     return nil;
1397   return color_table->colors[idx];
1401 unsigned long
1402 ns_index_color (NSColor *color, struct frame *f)
1404   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1405   ptrdiff_t idx;
1406   ptrdiff_t i;
1408   if (!color_table->colors)
1409     {
1410       color_table->size = NS_COLOR_CAPACITY;
1411       color_table->avail = 1; /* skip idx=0 as marker */
1412       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1413       color_table->colors[0] = nil;
1414       color_table->empty_indices = [[NSMutableSet alloc] init];
1415     }
1417   /* do we already have this color ? */
1418   for (i = 1; i < color_table->avail; i++)
1419     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1420       return i;
1422   if ([color_table->empty_indices count] > 0)
1423     {
1424       NSNumber *index = [color_table->empty_indices anyObject];
1425       [color_table->empty_indices removeObject: index];
1426       idx = [index unsignedLongValue];
1427     }
1428   else
1429     {
1430       if (color_table->avail == color_table->size)
1431         color_table->colors =
1432           xpalloc (color_table->colors, &color_table->size, 1,
1433                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1434       idx = color_table->avail++;
1435     }
1437   color_table->colors[idx] = color;
1438   [color retain];
1439 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1440   return idx;
1444 void
1445 ns_free_indexed_color (unsigned long idx, struct frame *f)
1447   struct ns_color_table *color_table;
1448   NSColor *color;
1449   NSNumber *index;
1451   if (!f)
1452     return;
1454   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1456   if (idx <= 0 || idx >= color_table->size) {
1457     message1 ("ns_free_indexed_color: Color index out of range.\n");
1458     return;
1459   }
1461   index = [NSNumber numberWithUnsignedInt: idx];
1462   if ([color_table->empty_indices containsObject: index]) {
1463     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1464     return;
1465   }
1467   color = color_table->colors[idx];
1468   [color release];
1469   color_table->colors[idx] = nil;
1470   [color_table->empty_indices addObject: index];
1471 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1475 static int
1476 ns_get_color (const char *name, NSColor **col)
1477 /* --------------------------------------------------------------------------
1478      Parse a color name
1479    -------------------------------------------------------------------------- */
1480 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1481    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1482    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1484   NSColor *new = nil;
1485   static char hex[20];
1486   int scaling;
1487   float r = -1.0, g, b;
1488   NSString *nsname = [NSString stringWithUTF8String: name];
1490 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1491   block_input ();
1493   if ([nsname isEqualToString: @"ns_selection_color"])
1494     {
1495       nsname = ns_selection_color;
1496       name = [ns_selection_color UTF8String];
1497     }
1499   /* First, check for some sort of numeric specification. */
1500   hex[0] = '\0';
1502   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1503     {
1504       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1505       [scanner scanFloat: &r];
1506       [scanner scanFloat: &g];
1507       [scanner scanFloat: &b];
1508     }
1509   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1510     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1511   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1512     {
1513       int len = (strlen(name) - 1);
1514       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1515       int i;
1516       scaling = strlen(name+start) / 3;
1517       for (i = 0; i < 3; i++)
1518         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1519                  name + start + i * scaling);
1520       hex[3 * (scaling + 1) - 1] = '\0';
1521     }
1523   if (hex[0])
1524     {
1525       int rr, gg, bb;
1526       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1527       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1528         {
1529           r = rr / fscale;
1530           g = gg / fscale;
1531           b = bb / fscale;
1532         }
1533     }
1535   if (r >= 0.0F)
1536     {
1537       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1538       unblock_input ();
1539       return 0;
1540     }
1542   /* Otherwise, color is expected to be from a list */
1543   {
1544     NSEnumerator *lenum, *cenum;
1545     NSString *name;
1546     NSColorList *clist;
1548 #ifdef NS_IMPL_GNUSTEP
1549     /* XXX: who is wrong, the requestor or the implementation? */
1550     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1551         == NSOrderedSame)
1552       nsname = @"highlightColor";
1553 #endif
1555     lenum = [[NSColorList availableColorLists] objectEnumerator];
1556     while ( (clist = [lenum nextObject]) && new == nil)
1557       {
1558         cenum = [[clist allKeys] objectEnumerator];
1559         while ( (name = [cenum nextObject]) && new == nil )
1560           {
1561             if ([name compare: nsname
1562                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1563               new = [clist colorWithKey: name];
1564           }
1565       }
1566   }
1568   if (new)
1569     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1570   unblock_input ();
1571   return new ? 0 : 1;
1576 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1577 /* --------------------------------------------------------------------------
1578      Convert a Lisp string object to a NS color
1579    -------------------------------------------------------------------------- */
1581   NSTRACE (ns_lisp_to_color);
1582   if (STRINGP (color))
1583     return ns_get_color (SSDATA (color), col);
1584   else if (SYMBOLP (color))
1585     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1586   return 1;
1590 Lisp_Object
1591 ns_color_to_lisp (NSColor *col)
1592 /* --------------------------------------------------------------------------
1593      Convert a color to a lisp string with the RGB equivalent
1594    -------------------------------------------------------------------------- */
1596   EmacsCGFloat red, green, blue, alpha, gray;
1597   char buf[1024];
1598   const char *str;
1599   NSTRACE (ns_color_to_lisp);
1601   block_input ();
1602   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1604       if ((str =[[col colorNameComponent] UTF8String]))
1605         {
1606           unblock_input ();
1607           return build_string ((char *)str);
1608         }
1610     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1611         getRed: &red green: &green blue: &blue alpha: &alpha];
1612   if (red ==green && red ==blue)
1613     {
1614       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1615             getWhite: &gray alpha: &alpha];
1616       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1617                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1618       unblock_input ();
1619       return build_string (buf);
1620     }
1622   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1623             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1625   unblock_input ();
1626   return build_string (buf);
1630 void
1631 ns_query_color(void *col, XColor *color_def, int setPixel)
1632 /* --------------------------------------------------------------------------
1633          Get ARGB values out of NSColor col and put them into color_def.
1634          If setPixel, set the pixel to a concatenated version.
1635          and set color_def pixel to the resulting index.
1636    -------------------------------------------------------------------------- */
1638   EmacsCGFloat r, g, b, a;
1640   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1641   color_def->red   = r * 65535;
1642   color_def->green = g * 65535;
1643   color_def->blue  = b * 65535;
1645   if (setPixel == YES)
1646     color_def->pixel
1647       = ARGB_TO_ULONG((int)(a*255),
1648                       (int)(r*255), (int)(g*255), (int)(b*255));
1652 bool
1653 ns_defined_color (struct frame *f,
1654                   const char *name,
1655                   XColor *color_def,
1656                   bool alloc,
1657                   bool makeIndex)
1658 /* --------------------------------------------------------------------------
1659          Return true if named color found, and set color_def rgb accordingly.
1660          If makeIndex and alloc are nonzero put the color in the color_table,
1661          and set color_def pixel to the resulting index.
1662          If makeIndex is zero, set color_def pixel to ARGB.
1663          Return false if not found
1664    -------------------------------------------------------------------------- */
1666   NSColor *col;
1667   NSTRACE (ns_defined_color);
1669   block_input ();
1670   if (ns_get_color (name, &col) != 0) /* Color not found  */
1671     {
1672       unblock_input ();
1673       return 0;
1674     }
1675   if (makeIndex && alloc)
1676     color_def->pixel = ns_index_color (col, f);
1677   ns_query_color (col, color_def, !makeIndex);
1678   unblock_input ();
1679   return 1;
1683 void
1684 x_set_frame_alpha (struct frame *f)
1685 /* --------------------------------------------------------------------------
1686      change the entire-frame transparency
1687    -------------------------------------------------------------------------- */
1689   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1690   double alpha = 1.0;
1691   double alpha_min = 1.0;
1693   if (dpyinfo->x_highlight_frame == f)
1694     alpha = f->alpha[0];
1695   else
1696     alpha = f->alpha[1];
1698   if (FLOATP (Vframe_alpha_lower_limit))
1699     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1700   else if (INTEGERP (Vframe_alpha_lower_limit))
1701     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1703   if (alpha < 0.0)
1704     return;
1705   else if (1.0 < alpha)
1706     alpha = 1.0;
1707   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1708     alpha = alpha_min;
1710 #ifdef NS_IMPL_COCOA
1711   {
1712     EmacsView *view = FRAME_NS_VIEW (f);
1713   [[view window] setAlphaValue: alpha];
1714   }
1715 #endif
1719 /* ==========================================================================
1721     Mouse handling
1723    ========================================================================== */
1726 void
1727 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1728 /* --------------------------------------------------------------------------
1729      Programmatically reposition mouse pointer in pixel coordinates
1730    -------------------------------------------------------------------------- */
1732   NSTRACE (x_set_mouse_pixel_position);
1733   ns_raise_frame (f);
1734 #if 0
1735   /* FIXME: this does not work, and what about GNUstep? */
1736 #ifdef NS_IMPL_COCOA
1737   [FRAME_NS_VIEW (f) lockFocus];
1738   PSsetmouse ((float)pix_x, (float)pix_y);
1739   [FRAME_NS_VIEW (f) unlockFocus];
1740 #endif
1741 #endif
1745 void
1746 x_set_mouse_position (struct frame *f, int h, int v)
1747 /* --------------------------------------------------------------------------
1748      Programmatically reposition mouse pointer in character coordinates
1749    -------------------------------------------------------------------------- */
1751   int pix_x, pix_y;
1753   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1754   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1756   if (pix_x < 0) pix_x = 0;
1757   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1759   if (pix_y < 0) pix_y = 0;
1760   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1762   x_set_mouse_pixel_position (f, pix_x, pix_y);
1766 static int
1767 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1768 /*   ------------------------------------------------------------------------
1769      Called by EmacsView on mouseMovement events.  Passes on
1770      to emacs mainstream code if we moved off of a rect of interest
1771      known as last_mouse_glyph.
1772      ------------------------------------------------------------------------ */
1774 //  NSTRACE (note_mouse_movement);
1776   XSETFRAME (last_mouse_motion_frame, frame);
1778   /* Note, this doesn't get called for enter/leave, since we don't have a
1779      position.  Those are taken care of in the corresponding NSView methods. */
1781   /* has movement gone beyond last rect we were tracking? */
1782   if (x < last_mouse_glyph.origin.x ||
1783       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1784       y < last_mouse_glyph.origin.y ||
1785       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1786     {
1787       ns_update_begin(frame);
1788       frame->mouse_moved = 1;
1789       note_mouse_highlight (frame, x, y);
1790       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1791       ns_update_end(frame);
1792       return 1;
1793     }
1795   return 0;
1799 static void
1800 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1801                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1802                    Time *time)
1803 /* --------------------------------------------------------------------------
1804     External (hook): inform emacs about mouse position and hit parts.
1805     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1806     x & y should be position in the scrollbar (the whole bar, not the handle)
1807     and length of scrollbar respectively
1808    -------------------------------------------------------------------------- */
1810   id view;
1811   NSPoint position;
1812   Lisp_Object frame, tail;
1813   struct frame *f;
1814   struct ns_display_info *dpyinfo;
1816   NSTRACE (ns_mouse_position);
1818   if (*fp == NULL)
1819     {
1820       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1821       return;
1822     }
1824   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1826   block_input ();
1828   if (last_mouse_scroll_bar != nil && insist == 0)
1829     {
1830       /* TODO: we do not use this path at the moment because drag events will
1831            go directly to the EmacsScroller.  Leaving code in for now. */
1832       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1833                                               x: x y: y];
1834       if (time) *time = last_mouse_movement_time;
1835       last_mouse_scroll_bar = nil;
1836     }
1837   else
1838     {
1839       /* Clear the mouse-moved flag for every frame on this display.  */
1840       FOR_EACH_FRAME (tail, frame)
1841         if (FRAME_NS_P (XFRAME (frame))
1842             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1843           XFRAME (frame)->mouse_moved = 0;
1845       last_mouse_scroll_bar = nil;
1846       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1847         f = last_mouse_frame;
1848       else
1849         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1850                                     : SELECTED_FRAME ();
1852       if (f && FRAME_NS_P (f))
1853         {
1854           view = FRAME_NS_VIEW (*fp);
1856           position = [[view window] mouseLocationOutsideOfEventStream];
1857           position = [view convertPoint: position fromView: nil];
1858           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1859 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1861           if (bar_window) *bar_window = Qnil;
1862           if (part) *part = 0; /*scroll_bar_handle; */
1864           if (x) XSETINT (*x, lrint (position.x));
1865           if (y) XSETINT (*y, lrint (position.y));
1866           if (time) *time = last_mouse_movement_time;
1867           *fp = f;
1868         }
1869     }
1871   unblock_input ();
1875 static void
1876 ns_frame_up_to_date (struct frame *f)
1877 /* --------------------------------------------------------------------------
1878     External (hook): Fix up mouse highlighting right after a full update.
1879     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1880    -------------------------------------------------------------------------- */
1882   NSTRACE (ns_frame_up_to_date);
1884   if (FRAME_NS_P (f))
1885     {
1886       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1887       if (f == hlinfo->mouse_face_mouse_frame)
1888         {
1889           block_input ();
1890           ns_update_begin(f);
1891           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1892                                 hlinfo->mouse_face_mouse_x,
1893                                 hlinfo->mouse_face_mouse_y);
1894           ns_update_end(f);
1895           unblock_input ();
1896         }
1897     }
1901 static void
1902 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1903 /* --------------------------------------------------------------------------
1904     External (RIF): set frame mouse pointer type.
1905    -------------------------------------------------------------------------- */
1907   NSTRACE (ns_define_frame_cursor);
1908   if (FRAME_POINTER_TYPE (f) != cursor)
1909     {
1910       EmacsView *view = FRAME_NS_VIEW (f);
1911       FRAME_POINTER_TYPE (f) = cursor;
1912       [[view window] invalidateCursorRectsForView: view];
1913       /* Redisplay assumes this function also draws the changed frame
1914          cursor, but this function doesn't, so do it explicitly.  */
1915       x_update_cursor (f, 1);
1916     }
1921 /* ==========================================================================
1923     Keyboard handling
1925    ========================================================================== */
1928 static unsigned
1929 ns_convert_key (unsigned code)
1930 /* --------------------------------------------------------------------------
1931     Internal call used by NSView-keyDown.
1932    -------------------------------------------------------------------------- */
1934   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1935                                 / sizeof (convert_ns_to_X_keysym[0]));
1936   unsigned keysym;
1937   /* An array would be faster, but less easy to read. */
1938   for (keysym = 0; keysym < last_keysym; keysym += 2)
1939     if (code == convert_ns_to_X_keysym[keysym])
1940       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1941   return 0;
1942 /* if decide to use keyCode and Carbon table, use this line:
1943      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1947 char *
1948 x_get_keysym_name (int keysym)
1949 /* --------------------------------------------------------------------------
1950     Called by keyboard.c.  Not sure if the return val is important, except
1951     that it be unique.
1952    -------------------------------------------------------------------------- */
1954   static char value[16];
1955   NSTRACE (x_get_keysym_name);
1956   sprintf (value, "%d", keysym);
1957   return value;
1962 /* ==========================================================================
1964     Block drawing operations
1966    ========================================================================== */
1969 static void
1970 ns_redraw_scroll_bars (struct frame *f)
1972   int i;
1973   id view;
1974   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1975   NSTRACE (ns_redraw_scroll_bars);
1976   for (i =[subviews count]-1; i >= 0; i--)
1977     {
1978       view = [subviews objectAtIndex: i];
1979       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1980       [view display];
1981     }
1985 void
1986 ns_clear_frame (struct frame *f)
1987 /* --------------------------------------------------------------------------
1988       External (hook): Erase the entire frame
1989    -------------------------------------------------------------------------- */
1991   NSView *view = FRAME_NS_VIEW (f);
1992   NSRect r;
1994   NSTRACE (ns_clear_frame);
1996  /* comes on initial frame because we have
1997     after-make-frame-functions = select-frame */
1998  if (!FRAME_DEFAULT_FACE (f))
1999    return;
2001   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2003   output_cursor.hpos = output_cursor.vpos = 0;
2004   output_cursor.x = -1;
2006   r = [view bounds];
2008   block_input ();
2009   ns_focus (f, &r, 1);
2010   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2011   NSRectFill (r);
2012   ns_unfocus (f);
2014   /* as of 2006/11 or so this is now needed */
2015   ns_redraw_scroll_bars (f);
2016   unblock_input ();
2020 static void
2021 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2022 /* --------------------------------------------------------------------------
2023     External (RIF):  Clear section of frame
2024    -------------------------------------------------------------------------- */
2026   NSRect r = NSMakeRect (x, y, width, height);
2027   NSView *view = FRAME_NS_VIEW (f);
2028   struct face *face = FRAME_DEFAULT_FACE (f);
2030   if (!view || !face)
2031     return;
2033   NSTRACE (ns_clear_frame_area);
2035   r = NSIntersectionRect (r, [view frame]);
2036   ns_focus (f, &r, 1);
2037   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2039   NSRectFill (r);
2041   ns_unfocus (f);
2042   return;
2046 static void
2047 ns_scroll_run (struct window *w, struct run *run)
2048 /* --------------------------------------------------------------------------
2049     External (RIF):  Insert or delete n lines at line vpos
2050    -------------------------------------------------------------------------- */
2052   struct frame *f = XFRAME (w->frame);
2053   int x, y, width, height, from_y, to_y, bottom_y;
2055   NSTRACE (ns_scroll_run);
2057   /* begin copy from other terms */
2058   /* Get frame-relative bounding box of the text display area of W,
2059      without mode lines.  Include in this box the left and right
2060      fringe of W.  */
2061   window_box (w, -1, &x, &y, &width, &height);
2063   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2064   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2065   bottom_y = y + height;
2067   if (to_y < from_y)
2068     {
2069       /* Scrolling up.  Make sure we don't copy part of the mode
2070          line at the bottom.  */
2071       if (from_y + run->height > bottom_y)
2072         height = bottom_y - from_y;
2073       else
2074         height = run->height;
2075     }
2076   else
2077     {
2078       /* Scrolling down.  Make sure we don't copy over the mode line.
2079          at the bottom.  */
2080       if (to_y + run->height > bottom_y)
2081         height = bottom_y - to_y;
2082       else
2083         height = run->height;
2084     }
2085   /* end copy from other terms */
2087   if (height == 0)
2088       return;
2090   block_input ();
2092   x_clear_cursor (w);
2094   {
2095     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2096     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2097     NSPoint dstOrigin = NSMakePoint (x, to_y);
2099     ns_focus (f, &dstRect, 1);
2100     NSCopyBits (0, srcRect , dstOrigin);
2101     ns_unfocus (f);
2102   }
2104   unblock_input ();
2108 static void
2109 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2110 /* --------------------------------------------------------------------------
2111     External (RIF): preparatory to fringe update after text was updated
2112    -------------------------------------------------------------------------- */
2114   struct frame *f;
2115   int width, height;
2117   NSTRACE (ns_after_update_window_line);
2119   /* begin copy from other terms */
2120   eassert (w);
2122   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2123     desired_row->redraw_fringe_bitmaps_p = 1;
2125   /* When a window has disappeared, make sure that no rest of
2126      full-width rows stays visible in the internal border.  */
2127   if (windows_or_buffers_changed
2128       && desired_row->full_width_p
2129       && (f = XFRAME (w->frame),
2130           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2131           width != 0)
2132       && (height = desired_row->visible_height,
2133           height > 0))
2134     {
2135       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2137       block_input ();
2138       ns_clear_frame_area (f, 0, y, width, height);
2139       ns_clear_frame_area (f,
2140                            FRAME_PIXEL_WIDTH (f) - width,
2141                            y, width, height);
2142       unblock_input ();
2143     }
2147 static void
2148 ns_shift_glyphs_for_insert (struct frame *f,
2149                            int x, int y, int width, int height,
2150                            int shift_by)
2151 /* --------------------------------------------------------------------------
2152     External (RIF): copy an area horizontally, don't worry about clearing src
2153    -------------------------------------------------------------------------- */
2155   NSRect srcRect = NSMakeRect (x, y, width, height);
2156   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2157   NSPoint dstOrigin = dstRect.origin;
2159   NSTRACE (ns_shift_glyphs_for_insert);
2161   ns_focus (f, &dstRect, 1);
2162   NSCopyBits (0, srcRect, dstOrigin);
2163   ns_unfocus (f);
2168 /* ==========================================================================
2170     Character encoding and metrics
2172    ========================================================================== */
2175 static void
2176 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2177 /* --------------------------------------------------------------------------
2178      External (RIF); compute left/right overhang of whole string and set in s
2179    -------------------------------------------------------------------------- */
2181   struct font *font = s->font;
2183   if (s->char2b)
2184     {
2185       struct font_metrics metrics;
2186       unsigned int codes[2];
2187       codes[0] = *(s->char2b);
2188       codes[1] = *(s->char2b + s->nchars - 1);
2190       font->driver->text_extents (font, codes, 2, &metrics);
2191       s->left_overhang = -metrics.lbearing;
2192       s->right_overhang
2193         = metrics.rbearing > metrics.width
2194         ? metrics.rbearing - metrics.width : 0;
2195     }
2196   else
2197     {
2198       s->left_overhang = 0;
2199       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2200         FONT_HEIGHT (font) * 0.2 : 0;
2201     }
2206 /* ==========================================================================
2208     Fringe and cursor drawing
2210    ========================================================================== */
2213 extern int max_used_fringe_bitmap;
2214 static void
2215 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2216                       struct draw_fringe_bitmap_params *p)
2217 /* --------------------------------------------------------------------------
2218     External (RIF); fringe-related
2219    -------------------------------------------------------------------------- */
2221   struct frame *f = XFRAME (WINDOW_FRAME (w));
2222   struct face *face = p->face;
2223   static EmacsImage **bimgs = NULL;
2224   static int nBimgs = 0;
2226   /* grow bimgs if needed */
2227   if (nBimgs < max_used_fringe_bitmap)
2228     {
2229       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2230       memset (bimgs + nBimgs, 0,
2231               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2232       nBimgs = max_used_fringe_bitmap;
2233     }
2235   /* Must clip because of partially visible lines.  */
2236   ns_clip_to_row (w, row, -1, YES);
2238   if (!p->overlay_p)
2239     {
2240       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2242       /* If the fringe is adjacent to the left (right) scroll bar of a
2243          leftmost (rightmost, respectively) window, then extend its
2244          background to the gap between the fringe and the bar.  */
2245       if ((WINDOW_LEFTMOST_P (w)
2246            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2247           || (WINDOW_RIGHTMOST_P (w)
2248               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2249         {
2250           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2252           if (sb_width > 0)
2253             {
2254               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2255               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2256                                     * FRAME_COLUMN_WIDTH (f));
2258               if (bx < 0)
2259                 {
2260                   /* Bitmap fills the fringe.  */
2261                   if (bar_area_x + bar_area_width == p->x)
2262                     bx = bar_area_x + sb_width;
2263                   else if (p->x + p->wd == bar_area_x)
2264                     bx = bar_area_x;
2265                   if (bx >= 0)
2266                     {
2267                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2269                       nx = bar_area_width - sb_width;
2270                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2271                                                             row->y));
2272                       ny = row->visible_height;
2273                     }
2274                 }
2275               else
2276                 {
2277                   if (bar_area_x + bar_area_width == bx)
2278                     {
2279                       bx = bar_area_x + sb_width;
2280                       nx += bar_area_width - sb_width;
2281                     }
2282                   else if (bx + nx == bar_area_x)
2283                     nx += bar_area_width - sb_width;
2284                 }
2285             }
2286         }
2288       if (bx >= 0 && nx > 0)
2289         {
2290           NSRect r = NSMakeRect (bx, by, nx, ny);
2291           NSRectClip (r);
2292           [ns_lookup_indexed_color (face->background, f) set];
2293           NSRectFill (r);
2294         }
2295     }
2297   if (p->which)
2298     {
2299       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2300       EmacsImage *img = bimgs[p->which - 1];
2302       if (!img)
2303         {
2304           unsigned short *bits = p->bits + p->dh;
2305           int len = p->h;
2306           int i;
2307           unsigned char *cbits = xmalloc (len);
2309           for (i = 0; i < len; i++)
2310             cbits[i] = ~(bits[i] & 0xff);
2311           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2312                                            flip: NO];
2313           bimgs[p->which - 1] = img;
2314           xfree (cbits);
2315         }
2317       NSRectClip (r);
2318       /* Since we composite the bitmap instead of just blitting it, we need
2319          to erase the whole background. */
2320       [ns_lookup_indexed_color(face->background, f) set];
2321       NSRectFill (r);
2322       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2323 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2324       [img drawInRect: r
2325               fromRect: NSZeroRect
2326              operation: NSCompositeSourceOver
2327               fraction: 1.0
2328            respectFlipped: YES
2329                 hints: nil];
2330 #else
2331       {
2332         NSPoint pt = r.origin;
2333         pt.y += p->h;
2334         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2335       }
2336 #endif
2337     }
2338   ns_unfocus (f);
2342 static void
2343 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2344                        int x, int y, int cursor_type, int cursor_width,
2345                        int on_p, int active_p)
2346 /* --------------------------------------------------------------------------
2347      External call (RIF): draw cursor.
2348      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2349    -------------------------------------------------------------------------- */
2351   NSRect r, s;
2352   int fx, fy, h, cursor_height;
2353   struct frame *f = WINDOW_XFRAME (w);
2354   struct glyph *phys_cursor_glyph;
2355   struct glyph *cursor_glyph;
2356   struct face *face;
2357   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2359   /* If cursor is out of bounds, don't draw garbage.  This can happen
2360      in mini-buffer windows when switching between echo area glyphs
2361      and mini-buffer.  */
2363   NSTRACE (dumpcursor);
2365   if (!on_p)
2366     return;
2368   w->phys_cursor_type = cursor_type;
2369   w->phys_cursor_on_p = on_p;
2371   if (cursor_type == NO_CURSOR)
2372     {
2373       w->phys_cursor_width = 0;
2374       return;
2375     }
2377   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2378     {
2379       if (glyph_row->exact_window_width_line_p
2380           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2381         {
2382           glyph_row->cursor_in_fringe_p = 1;
2383           draw_fringe_bitmap (w, glyph_row, 0);
2384         }
2385       return;
2386     }
2388   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2389      (other terminals do it the other way round).  We must set
2390      w->phys_cursor_width to the cursor width.  For bar cursors, that
2391      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2392   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2394   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2395      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2396   if (cursor_type == BAR_CURSOR)
2397     {
2398       if (cursor_width < 1)
2399         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2400       w->phys_cursor_width = cursor_width;
2401     }
2402   /* If we have an HBAR, "cursor_width" MAY specify height. */
2403   else if (cursor_type == HBAR_CURSOR)
2404     {
2405       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2406       fy += h - cursor_height;
2407       h = cursor_height;
2408     }
2410   r.origin.x = fx, r.origin.y = fy;
2411   r.size.height = h;
2412   r.size.width = w->phys_cursor_width;
2414   /* TODO: only needed in rare cases with last-resort font in HELLO..
2415      should we do this more efficiently? */
2416   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2419   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2420   if (face && NS_FACE_BACKGROUND (face)
2421       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2422     {
2423       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2424       hollow_color = FRAME_CURSOR_COLOR (f);
2425     }
2426   else
2427     [FRAME_CURSOR_COLOR (f) set];
2429 #ifdef NS_IMPL_COCOA
2430   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2431            atomic.  Cleaner ways of doing this should be investigated.
2432            One way would be to set a global variable DRAWING_CURSOR
2433            when making the call to draw_phys..(), don't focus in that
2434            case, then move the ns_unfocus() here after that call. */
2435   NSDisableScreenUpdates ();
2436 #endif
2438   switch (cursor_type)
2439     {
2440     case NO_CURSOR:
2441       break;
2442     case FILLED_BOX_CURSOR:
2443       NSRectFill (r);
2444       break;
2445     case HOLLOW_BOX_CURSOR:
2446       NSRectFill (r);
2447       [hollow_color set];
2448       NSRectFill (NSInsetRect (r, 1, 1));
2449       [FRAME_CURSOR_COLOR (f) set];
2450       break;
2451     case HBAR_CURSOR:
2452       NSRectFill (r);
2453       break;
2454     case BAR_CURSOR:
2455       s = r;
2456       /* If the character under cursor is R2L, draw the bar cursor
2457          on the right of its glyph, rather than on the left.  */
2458       cursor_glyph = get_phys_cursor_glyph (w);
2459       if ((cursor_glyph->resolved_level & 1) != 0)
2460         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2462       NSRectFill (s);
2463       break;
2464     }
2465   ns_unfocus (f);
2467   /* draw the character under the cursor */
2468   if (cursor_type != NO_CURSOR)
2469     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2471 #ifdef NS_IMPL_COCOA
2472   NSEnableScreenUpdates ();
2473 #endif
2478 static void
2479 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2480 /* --------------------------------------------------------------------------
2481      External (RIF): Draw a vertical line.
2482    -------------------------------------------------------------------------- */
2484   struct frame *f = XFRAME (WINDOW_FRAME (w));
2485   struct face *face;
2486   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2488   NSTRACE (ns_draw_vertical_window_border);
2490   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2491   if (face)
2492       [ns_lookup_indexed_color(face->foreground, f) set];
2494   ns_focus (f, &r, 1);
2495   NSRectFill(r);
2496   ns_unfocus (f);
2500 void
2501 show_hourglass (struct atimer *timer)
2503   if (hourglass_shown_p)
2504     return;
2506   block_input ();
2508   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2510   hourglass_shown_p = 1;
2511   unblock_input ();
2515 void
2516 hide_hourglass (void)
2518   if (!hourglass_shown_p)
2519     return;
2521   block_input ();
2523   /* TODO: remove NSProgressIndicator from all frames */
2525   hourglass_shown_p = 0;
2526   unblock_input ();
2531 /* ==========================================================================
2533     Glyph drawing operations
2535    ========================================================================== */
2537 static int
2538 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2539 /* --------------------------------------------------------------------------
2540     Wrapper utility to account for internal border width on full-width lines,
2541     and allow top full-width rows to hit the frame top.  nr should be pointer
2542     to two successive NSRects.  Number of rects actually used is returned.
2543    -------------------------------------------------------------------------- */
2545   int n = get_glyph_string_clip_rects (s, nr, 2);
2546   return n;
2549 /* --------------------------------------------------------------------
2550    Draw a wavy line under glyph string s. The wave fills wave_height
2551    pixels from y.
2553                     x          wave_length = 2
2554                                  --
2555                 y    *   *   *   *   *
2556                      |* * * * * * * * *
2557     wave_height = 3  | *   *   *   *
2558   --------------------------------------------------------------------- */
2560 static void
2561 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2563   int wave_height = 3, wave_length = 2;
2564   int y, dx, dy, odd, xmax;
2565   NSPoint a, b;
2566   NSRect waveClip;
2568   dx = wave_length;
2569   dy = wave_height - 1;
2570   y =  s->ybase - wave_height + 3;
2571   xmax = x + width;
2573   /* Find and set clipping rectangle */
2574   waveClip = NSMakeRect (x, y, width, wave_height);
2575   [[NSGraphicsContext currentContext] saveGraphicsState];
2576   NSRectClip (waveClip);
2578   /* Draw the waves */
2579   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2580   b.x = a.x + dx;
2581   odd = (int)(a.x/dx) % 2;
2582   a.y = b.y = y + 0.5;
2584   if (odd)
2585     a.y += dy;
2586   else
2587     b.y += dy;
2589   while (a.x <= xmax)
2590     {
2591       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2592       a.x = b.x, a.y = b.y;
2593       b.x += dx, b.y = y + 0.5 + odd*dy;
2594       odd = !odd;
2595     }
2597   /* Restore previous clipping rectangle(s) */
2598   [[NSGraphicsContext currentContext] restoreGraphicsState];
2603 void
2604 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2605                          NSColor *defaultCol, CGFloat width, CGFloat x)
2606 /* --------------------------------------------------------------------------
2607    Draw underline, overline, and strike-through on glyph string s.
2608    -------------------------------------------------------------------------- */
2610   if (s->for_overlaps)
2611     return;
2613   /* Do underline. */
2614   if (face->underline_p)
2615     {
2616       if (s->face->underline_type == FACE_UNDER_WAVE)
2617         {
2618           if (face->underline_defaulted_p)
2619             [defaultCol set];
2620           else
2621             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2623           ns_draw_underwave (s, width, x);
2624         }
2625       else if (s->face->underline_type == FACE_UNDER_LINE)
2626         {
2628           NSRect r;
2629           unsigned long thickness, position;
2631           /* If the prev was underlined, match its appearance. */
2632           if (s->prev && s->prev->face->underline_p
2633               && s->prev->face->underline_type == FACE_UNDER_LINE
2634               && s->prev->underline_thickness > 0)
2635             {
2636               thickness = s->prev->underline_thickness;
2637               position = s->prev->underline_position;
2638             }
2639           else
2640             {
2641               struct font *font;
2642               unsigned long descent;
2644               font=s->font;
2645               descent = s->y + s->height - s->ybase;
2647               /* Use underline thickness of font, defaulting to 1. */
2648               thickness = (font && font->underline_thickness > 0)
2649                 ? font->underline_thickness : 1;
2651               /* Determine the offset of underlining from the baseline. */
2652               if (x_underline_at_descent_line)
2653                 position = descent - thickness;
2654               else if (x_use_underline_position_properties
2655                        && font && font->underline_position >= 0)
2656                 position = font->underline_position;
2657               else if (font)
2658                 position = lround (font->descent / 2);
2659               else
2660                 position = underline_minimum_offset;
2662               position = max (position, underline_minimum_offset);
2664               /* Ensure underlining is not cropped. */
2665               if (descent <= position)
2666                 {
2667                   position = descent - 1;
2668                   thickness = 1;
2669                 }
2670               else if (descent < position + thickness)
2671                 thickness = 1;
2672             }
2674           s->underline_thickness = thickness;
2675           s->underline_position = position;
2677           r = NSMakeRect (x, s->ybase + position, width, thickness);
2679           if (face->underline_defaulted_p)
2680             [defaultCol set];
2681           else
2682             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2683           NSRectFill (r);
2684         }
2685     }
2686   /* Do overline. We follow other terms in using a thickness of 1
2687      and ignoring overline_margin. */
2688   if (face->overline_p)
2689     {
2690       NSRect r;
2691       r = NSMakeRect (x, s->y, width, 1);
2693       if (face->overline_color_defaulted_p)
2694         [defaultCol set];
2695       else
2696         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2697       NSRectFill (r);
2698     }
2700   /* Do strike-through.  We follow other terms for thickness and
2701      vertical position.*/
2702   if (face->strike_through_p)
2703     {
2704       NSRect r;
2705       unsigned long dy;
2707       dy = lrint ((s->height - 1) / 2);
2708       r = NSMakeRect (x, s->y + dy, width, 1);
2710       if (face->strike_through_color_defaulted_p)
2711         [defaultCol set];
2712       else
2713         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2714       NSRectFill (r);
2715     }
2718 static void
2719 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2720              char left_p, char right_p)
2721 /* --------------------------------------------------------------------------
2722     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2723     Note we can't just use an NSDrawRect command, because of the possibility
2724     of some sides not being drawn, and because the rect will be filled.
2725    -------------------------------------------------------------------------- */
2727   NSRect s = r;
2728   [col set];
2730   /* top, bottom */
2731   s.size.height = thickness;
2732   NSRectFill (s);
2733   s.origin.y += r.size.height - thickness;
2734   NSRectFill (s);
2736   s.size.height = r.size.height;
2737   s.origin.y = r.origin.y;
2739   /* left, right (optional) */
2740   s.size.width = thickness;
2741   if (left_p)
2742     NSRectFill (s);
2743   if (right_p)
2744     {
2745       s.origin.x += r.size.width - thickness;
2746       NSRectFill (s);
2747     }
2751 static void
2752 ns_draw_relief (NSRect r, int thickness, char raised_p,
2753                char top_p, char bottom_p, char left_p, char right_p,
2754                struct glyph_string *s)
2755 /* --------------------------------------------------------------------------
2756     Draw a relief rect inside r, optionally leaving some sides open.
2757     Note we can't just use an NSDrawBezel command, because of the possibility
2758     of some sides not being drawn, and because the rect will be filled.
2759    -------------------------------------------------------------------------- */
2761   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2762   NSColor *newBaseCol = nil;
2763   NSRect sr = r;
2765   NSTRACE (ns_draw_relief);
2767   /* set up colors */
2769   if (s->face->use_box_color_for_shadows_p)
2770     {
2771       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2772     }
2773 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2774            && s->img->pixmap
2775            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2776        {
2777          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2778        } */
2779   else
2780     {
2781       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2782     }
2784   if (newBaseCol == nil)
2785     newBaseCol = [NSColor grayColor];
2787   if (newBaseCol != baseCol)  /* TODO: better check */
2788     {
2789       [baseCol release];
2790       baseCol = [newBaseCol retain];
2791       [lightCol release];
2792       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2793       [darkCol release];
2794       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2795     }
2797   [(raised_p ? lightCol : darkCol) set];
2799   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2801   /* top */
2802   sr.size.height = thickness;
2803   if (top_p) NSRectFill (sr);
2805   /* left */
2806   sr.size.height = r.size.height;
2807   sr.size.width = thickness;
2808   if (left_p) NSRectFill (sr);
2810   [(raised_p ? darkCol : lightCol) set];
2812   /* bottom */
2813   sr.size.width = r.size.width;
2814   sr.size.height = thickness;
2815   sr.origin.y += r.size.height - thickness;
2816   if (bottom_p) NSRectFill (sr);
2818   /* right */
2819   sr.size.height = r.size.height;
2820   sr.origin.y = r.origin.y;
2821   sr.size.width = thickness;
2822   sr.origin.x += r.size.width - thickness;
2823   if (right_p) NSRectFill (sr);
2827 static void
2828 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2829 /* --------------------------------------------------------------------------
2830       Function modeled after x_draw_glyph_string_box ().
2831       Sets up parameters for drawing.
2832    -------------------------------------------------------------------------- */
2834   int right_x, last_x;
2835   char left_p, right_p;
2836   struct glyph *last_glyph;
2837   NSRect r;
2838   int thickness;
2839   struct face *face;
2841   if (s->hl == DRAW_MOUSE_FACE)
2842     {
2843       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2844       if (!face)
2845         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2846     }
2847   else
2848     face = s->face;
2850   thickness = face->box_line_width;
2852   NSTRACE (ns_dumpglyphs_box_or_relief);
2854   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2855             ? WINDOW_RIGHT_EDGE_X (s->w)
2856             : window_box_right (s->w, s->area));
2857   last_glyph = (s->cmp || s->img
2858                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2860   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2861               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2863   left_p = (s->first_glyph->left_box_line_p
2864             || (s->hl == DRAW_MOUSE_FACE
2865                 && (s->prev == NULL || s->prev->hl != s->hl)));
2866   right_p = (last_glyph->right_box_line_p
2867              || (s->hl == DRAW_MOUSE_FACE
2868                  && (s->next == NULL || s->next->hl != s->hl)));
2870   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2872   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2873   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2874     {
2875       ns_draw_box (r, abs (thickness),
2876                    ns_lookup_indexed_color (face->box_color, s->f),
2877                   left_p, right_p);
2878     }
2879   else
2880     {
2881       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2882                      1, 1, left_p, right_p, s);
2883     }
2887 static void
2888 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2889 /* --------------------------------------------------------------------------
2890       Modeled after x_draw_glyph_string_background, which draws BG in
2891       certain cases.  Others are left to the text rendering routine.
2892    -------------------------------------------------------------------------- */
2894   NSTRACE (ns_maybe_dumpglyphs_background);
2896   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2897     {
2898       int box_line_width = max (s->face->box_line_width, 0);
2899       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2900           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2901         {
2902           struct face *face;
2903           if (s->hl == DRAW_MOUSE_FACE)
2904             {
2905               face = FACE_FROM_ID (s->f,
2906                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2907               if (!face)
2908                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2909             }
2910           else
2911             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2912           if (!face->stipple)
2913             [(NS_FACE_BACKGROUND (face) != 0
2914               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2915               : FRAME_BACKGROUND_COLOR (s->f)) set];
2916           else
2917             {
2918               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2919               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2920             }
2922           if (s->hl != DRAW_CURSOR)
2923             {
2924               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2925                                     s->background_width,
2926                                     s->height-2*box_line_width);
2927               NSRectFill (r);
2928             }
2930           s->background_filled_p = 1;
2931         }
2932     }
2936 static void
2937 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2938 /* --------------------------------------------------------------------------
2939       Renders an image and associated borders.
2940    -------------------------------------------------------------------------- */
2942   EmacsImage *img = s->img->pixmap;
2943   int box_line_vwidth = max (s->face->box_line_width, 0);
2944   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2945   int bg_x, bg_y, bg_height;
2946   int th;
2947   char raised_p;
2948   NSRect br;
2949   struct face *face;
2950   NSColor *tdCol;
2952   NSTRACE (ns_dumpglyphs_image);
2954   if (s->face->box != FACE_NO_BOX
2955       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2956     x += abs (s->face->box_line_width);
2958   bg_x = x;
2959   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2960   bg_height = s->height;
2961   /* other terms have this, but was causing problems w/tabbar mode */
2962   /* - 2 * box_line_vwidth; */
2964   if (s->slice.x == 0) x += s->img->hmargin;
2965   if (s->slice.y == 0) y += s->img->vmargin;
2967   /* Draw BG: if we need larger area than image itself cleared, do that,
2968      otherwise, since we composite the image under NS (instead of mucking
2969      with its background color), we must clear just the image area. */
2970   if (s->hl == DRAW_MOUSE_FACE)
2971     {
2972       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2973       if (!face)
2974        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2975     }
2976   else
2977     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2979   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2981   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2982       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2983     {
2984       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2985       s->background_filled_p = 1;
2986     }
2987   else
2988     {
2989       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2990     }
2992   NSRectFill (br);
2994   /* Draw the image.. do we need to draw placeholder if img ==nil? */
2995   if (img != nil)
2996     {
2997 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2998       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
2999       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3000                               s->slice.width, s->slice.height);
3001       [img drawInRect: dr
3002              fromRect: ir
3003              operation: NSCompositeSourceOver
3004               fraction: 1.0
3005            respectFlipped: YES
3006                 hints: nil];
3007 #else
3008       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3009                   operation: NSCompositeSourceOver];
3010 #endif
3011     }
3013   if (s->hl == DRAW_CURSOR)
3014     {
3015     [FRAME_CURSOR_COLOR (s->f) set];
3016     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3017       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3018     else
3019       /* Currently on NS img->mask is always 0. Since
3020          get_window_cursor_type specifies a hollow box cursor when on
3021          a non-masked image we never reach this clause. But we put it
3022          in in anticipation of better support for image masks on
3023          NS. */
3024       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3025     }
3026   else
3027     {
3028       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3029     }
3031   /* Draw underline, overline, strike-through. */
3032   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3034   /* Draw relief, if requested */
3035   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3036     {
3037       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3038         {
3039           th = tool_bar_button_relief >= 0 ?
3040             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3041           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3042         }
3043       else
3044         {
3045           th = abs (s->img->relief);
3046           raised_p = (s->img->relief > 0);
3047         }
3049       r.origin.x = x - th;
3050       r.origin.y = y - th;
3051       r.size.width = s->slice.width + 2*th-1;
3052       r.size.height = s->slice.height + 2*th-1;
3053       ns_draw_relief (r, th, raised_p,
3054                       s->slice.y == 0,
3055                       s->slice.y + s->slice.height == s->img->height,
3056                       s->slice.x == 0,
3057                       s->slice.x + s->slice.width == s->img->width, s);
3058     }
3060   /* If there is no mask, the background won't be seen,
3061      so draw a rectangle on the image for the cursor.
3062      Do this for all images, getting transparency right is not reliable.  */
3063   if (s->hl == DRAW_CURSOR)
3064     {
3065       int thickness = abs (s->img->relief);
3066       if (thickness == 0) thickness = 1;
3067       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3068     }
3072 static void
3073 ns_dumpglyphs_stretch (struct glyph_string *s)
3075   NSRect r[2];
3076   int n, i;
3077   struct face *face;
3078   NSColor *fgCol, *bgCol;
3080   if (!s->background_filled_p)
3081     {
3082       n = ns_get_glyph_string_clip_rect (s, r);
3083       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3085       ns_focus (s->f, r, n);
3087       if (s->hl == DRAW_MOUSE_FACE)
3088        {
3089          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3090          if (!face)
3091            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3092        }
3093       else
3094        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3096       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3097       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3099       for (i = 0; i < n; ++i)
3100         {
3101           if (!s->row->full_width_p)
3102             {
3103               int overrun, leftoverrun;
3105               /* truncate to avoid overwriting fringe and/or scrollbar */
3106               overrun = max (0, (s->x + s->background_width)
3107                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3108                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3109               r[i].size.width -= overrun;
3111               /* truncate to avoid overwriting to left of the window box */
3112               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3113                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3115               if (leftoverrun > 0)
3116                 {
3117                   r[i].origin.x += leftoverrun;
3118                   r[i].size.width -= leftoverrun;
3119                 }
3121               /* XXX: Try to work between problem where a stretch glyph on
3122                  a partially-visible bottom row will clear part of the
3123                  modeline, and another where list-buffers headers and similar
3124                  rows erroneously have visible_height set to 0.  Not sure
3125                  where this is coming from as other terms seem not to show. */
3126               r[i].size.height = min (s->height, s->row->visible_height);
3127             }
3129           [bgCol set];
3131           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3132              overwriting cursor (usually when cursor on a tab) */
3133           if (s->hl == DRAW_CURSOR)
3134             {
3135               CGFloat x, width;
3137               x = r[i].origin.x;
3138               width = s->w->phys_cursor_width;
3139               r[i].size.width -= width;
3140               r[i].origin.x += width;
3142               NSRectFill (r[i]);
3144               /* Draw overlining, etc. on the cursor. */
3145               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3146                 ns_draw_text_decoration (s, face, bgCol, width, x);
3147               else
3148                 ns_draw_text_decoration (s, face, fgCol, width, x);
3149             }
3150           else
3151             {
3152               NSRectFill (r[i]);
3153             }
3155           /* Draw overlining, etc. on the stretch glyph (or the part
3156              of the stretch glyph after the cursor). */
3157           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3158                                    r[i].origin.x);
3159         }
3160       ns_unfocus (s->f);
3161       s->background_filled_p = 1;
3162     }
3166 static void
3167 ns_draw_glyph_string (struct glyph_string *s)
3168 /* --------------------------------------------------------------------------
3169       External (RIF): Main draw-text call.
3170    -------------------------------------------------------------------------- */
3172   /* TODO (optimize): focus for box and contents draw */
3173   NSRect r[2];
3174   int n;
3175   char box_drawn_p = 0;
3177   NSTRACE (ns_draw_glyph_string);
3179   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3180     {
3181       int width;
3182       struct glyph_string *next;
3184       for (width = 0, next = s->next;
3185            next && width < s->right_overhang;
3186            width += next->width, next = next->next)
3187         if (next->first_glyph->type != IMAGE_GLYPH)
3188           {
3189             if (next->first_glyph->type != STRETCH_GLYPH)
3190               {
3191                 n = ns_get_glyph_string_clip_rect (s->next, r);
3192                 ns_focus (s->f, r, n);
3193                 ns_maybe_dumpglyphs_background (s->next, 1);
3194                 ns_unfocus (s->f);
3195               }
3196             else
3197               {
3198                 ns_dumpglyphs_stretch (s->next);
3199               }
3200             next->num_clips = 0;
3201           }
3202     }
3204   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3205         && (s->first_glyph->type == CHAR_GLYPH
3206             || s->first_glyph->type == COMPOSITE_GLYPH))
3207     {
3208       n = ns_get_glyph_string_clip_rect (s, r);
3209       ns_focus (s->f, r, n);
3210       ns_maybe_dumpglyphs_background (s, 1);
3211       ns_dumpglyphs_box_or_relief (s);
3212       ns_unfocus (s->f);
3213       box_drawn_p = 1;
3214     }
3216   switch (s->first_glyph->type)
3217     {
3219     case IMAGE_GLYPH:
3220       n = ns_get_glyph_string_clip_rect (s, r);
3221       ns_focus (s->f, r, n);
3222       ns_dumpglyphs_image (s, r[0]);
3223       ns_unfocus (s->f);
3224       break;
3226     case STRETCH_GLYPH:
3227       ns_dumpglyphs_stretch (s);
3228       break;
3230     case CHAR_GLYPH:
3231     case COMPOSITE_GLYPH:
3232       n = ns_get_glyph_string_clip_rect (s, r);
3233       ns_focus (s->f, r, n);
3235       if (s->for_overlaps || (s->cmp_from > 0
3236                               && ! s->first_glyph->u.cmp.automatic))
3237         s->background_filled_p = 1;
3238       else
3239         ns_maybe_dumpglyphs_background
3240           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3242       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3243                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3244                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3245                       NS_DUMPGLYPH_NORMAL));
3246       ns_tmp_font = (struct nsfont_info *)s->face->font;
3247       if (ns_tmp_font == NULL)
3248           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3250       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3251         {
3252           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3253           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3254           NS_FACE_FOREGROUND (s->face) = tmp;
3255         }
3257       ns_tmp_font->font.driver->draw
3258         (s, 0, s->nchars, s->x, s->y,
3259          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3260          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3262       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3263         {
3264           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3265           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3266           NS_FACE_FOREGROUND (s->face) = tmp;
3267         }
3269       ns_unfocus (s->f);
3270       break;
3272     case GLYPHLESS_GLYPH:
3273       n = ns_get_glyph_string_clip_rect (s, r);
3274       ns_focus (s->f, r, n);
3276       if (s->for_overlaps || (s->cmp_from > 0
3277                               && ! s->first_glyph->u.cmp.automatic))
3278         s->background_filled_p = 1;
3279       else
3280         ns_maybe_dumpglyphs_background
3281           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3282       /* ... */
3283       /* Not yet implemented.  */
3284       /* ... */
3285       ns_unfocus (s->f);
3286       break;
3288     default:
3289       emacs_abort ();
3290     }
3292   /* Draw box if not done already. */
3293   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3294     {
3295       n = ns_get_glyph_string_clip_rect (s, r);
3296       ns_focus (s->f, r, n);
3297       ns_dumpglyphs_box_or_relief (s);
3298       ns_unfocus (s->f);
3299     }
3301   s->num_clips = 0;
3306 /* ==========================================================================
3308     Event loop
3310    ========================================================================== */
3313 static void
3314 ns_send_appdefined (int value)
3315 /* --------------------------------------------------------------------------
3316     Internal: post an appdefined event which EmacsApp-sendEvent will
3317               recognize and take as a command to halt the event loop.
3318    -------------------------------------------------------------------------- */
3320   /*NSTRACE (ns_send_appdefined); */
3322 #ifdef NS_IMPL_GNUSTEP
3323   // GNUStep needs postEvent to happen on the main thread.
3324   if (! [[NSThread currentThread] isMainThread])
3325     {
3326       EmacsApp *app = (EmacsApp *)NSApp;
3327       app->nextappdefined = value;
3328       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3329                             withObject:nil
3330                          waitUntilDone:YES];
3331       return;
3332     }
3333 #endif
3335   /* Only post this event if we haven't already posted one.  This will end
3336        the [NXApp run] main loop after having processed all events queued at
3337        this moment.  */
3338   if (send_appdefined)
3339     {
3340       NSEvent *nxev;
3342       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3343       send_appdefined = NO;
3345       /* Don't need wakeup timer any more */
3346       if (timed_entry)
3347         {
3348           [timed_entry invalidate];
3349           [timed_entry release];
3350           timed_entry = nil;
3351         }
3353       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3354                                 location: NSMakePoint (0, 0)
3355                            modifierFlags: 0
3356                                timestamp: 0
3357                             windowNumber: [[NSApp mainWindow] windowNumber]
3358                                  context: [NSApp context]
3359                                  subtype: 0
3360                                    data1: value
3361                                    data2: 0];
3363       /* Post an application defined event on the event queue.  When this is
3364          received the [NXApp run] will return, thus having processed all
3365          events which are currently queued.  */
3366       [NSApp postEvent: nxev atStart: NO];
3367     }
3370 #ifdef HAVE_NATIVE_FS
3371 static void
3372 check_native_fs ()
3374   Lisp_Object frame, tail;
3376   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3377     return;
3379   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3381   /* Clear the mouse-moved flag for every frame on this display.  */
3382   FOR_EACH_FRAME (tail, frame)
3383     {
3384       struct frame *f = XFRAME (frame);
3385       if (FRAME_NS_P (f))
3386         {
3387           EmacsView *view = FRAME_NS_VIEW (f);
3388           [view updateCollectionBehaviour];
3389         }
3390     }
3392 #endif
3394 /* GNUStep and OSX <= 10.4 does not have cancelTracking.  */
3395 #if defined (NS_IMPL_COCOA) && \
3396   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
3397 /* Check if menu open should be cancelled or continued as normal.  */
3398 void
3399 ns_check_menu_open (NSMenu *menu)
3401   /* Click in menu bar? */
3402   NSArray *a = [[NSApp mainMenu] itemArray];
3403   int i;
3404   BOOL found = NO;
3406   if (menu == nil) // Menu tracking ended.
3407     {
3408       if (menu_will_open_state == MENU_OPENING)
3409         menu_will_open_state = MENU_NONE;
3410       return;
3411     }
3413   for (i = 0; ! found && i < [a count]; i++)
3414     found = menu == [[a objectAtIndex:i] submenu];
3415   if (found)
3416     {
3417       if (menu_will_open_state == MENU_NONE && emacs_event)
3418         {
3419           NSEvent *theEvent = [NSApp currentEvent];
3420           struct frame *emacsframe = SELECTED_FRAME ();
3422           [menu cancelTracking];
3423           menu_will_open_state = MENU_PENDING;
3424           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3425           EV_TRAILER (theEvent);
3427           CGEventRef ourEvent = CGEventCreate (NULL);
3428           menu_mouse_point = CGEventGetLocation (ourEvent);
3429           CFRelease (ourEvent);
3430         }
3431       else if (menu_will_open_state == MENU_OPENING)
3432         {
3433           menu_will_open_state = MENU_NONE;
3434         }
3435     }
3438 /* Redo saved menu click if state is MENU_PENDING.  */
3439 void
3440 ns_check_pending_open_menu ()
3442   if (menu_will_open_state == MENU_PENDING)
3443     {
3444       CGEventSourceRef source
3445         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3447       CGEventRef event = CGEventCreateMouseEvent (source,
3448                                                   kCGEventLeftMouseDown,
3449                                                   menu_mouse_point,
3450                                                   kCGMouseButtonLeft);
3451       CGEventSetType (event, kCGEventLeftMouseDown);
3452       CGEventPost (kCGHIDEventTap, event);
3453       CFRelease (event);
3454       CFRelease (source);
3456       menu_will_open_state = MENU_OPENING;
3457     }
3459 #endif /* NS_IMPL_COCOA) && >= MAC_OS_X_VERSION_10_5 */
3461 static int
3462 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3463 /* --------------------------------------------------------------------------
3464      External (hook): Post an event to ourself and keep reading events until
3465      we read it back again.  In effect process all events which were waiting.
3466      From 21+ we have to manage the event buffer ourselves.
3467    -------------------------------------------------------------------------- */
3469   struct input_event ev;
3470   int nevents;
3472 /* NSTRACE (ns_read_socket); */
3474 #ifdef HAVE_NATIVE_FS
3475   check_native_fs ();
3476 #endif
3478   if ([NSApp modalWindow] != nil)
3479     return -1;
3481   if (hold_event_q.nr > 0)
3482     {
3483       int i;
3484       for (i = 0; i < hold_event_q.nr; ++i)
3485         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3486       hold_event_q.nr = 0;
3487       return i;
3488     }
3490   block_input ();
3491   n_emacs_events_pending = 0;
3492   EVENT_INIT (ev);
3493   emacs_event = &ev;
3494   q_event_ptr = hold_quit;
3496   /* we manage autorelease pools by allocate/reallocate each time around
3497      the loop; strict nesting is occasionally violated but seems not to
3498      matter.. earlier methods using full nesting caused major memory leaks */
3499   [outerpool release];
3500   outerpool = [[NSAutoreleasePool alloc] init];
3502   /* If have pending open-file requests, attend to the next one of those. */
3503   if (ns_pending_files && [ns_pending_files count] != 0
3504       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3505     {
3506       [ns_pending_files removeObjectAtIndex: 0];
3507     }
3508   /* Deal with pending service requests. */
3509   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3510     && [(EmacsApp *)
3511          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3512                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3513     {
3514       [ns_pending_service_names removeObjectAtIndex: 0];
3515       [ns_pending_service_args removeObjectAtIndex: 0];
3516     }
3517   else
3518     {
3519       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3520          to ourself, otherwise [NXApp run] will never exit.  */
3521       send_appdefined = YES;
3522       ns_send_appdefined (-1);
3524       if (++apploopnr != 1)
3525         {
3526           emacs_abort ();
3527         }
3528       [NSApp run];
3529       --apploopnr;
3530     }
3532   nevents = n_emacs_events_pending;
3533   n_emacs_events_pending = 0;
3534   emacs_event = q_event_ptr = NULL;
3535   unblock_input ();
3537   return nevents;
3542 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3543            fd_set *exceptfds, EMACS_TIME *timeout, sigset_t *sigmask)
3544 /* --------------------------------------------------------------------------
3545      Replacement for select, checking for events
3546    -------------------------------------------------------------------------- */
3548   int result;
3549   int t, k, nr = 0;
3550   struct input_event event;
3551   char c;
3553 /*  NSTRACE (ns_select); */
3555 #ifdef HAVE_NATIVE_FS
3556   check_native_fs ();
3557 #endif
3559   if (hold_event_q.nr > 0)
3560     {
3561       /* We already have events pending. */
3562       raise (SIGIO);
3563       errno = EINTR;
3564       return -1;
3565     }
3567   for (k = 0; k < nfds+1; k++)
3568     {
3569       if (readfds && FD_ISSET(k, readfds)) ++nr;
3570       if (writefds && FD_ISSET(k, writefds)) ++nr;
3571     }
3573   if (NSApp == nil
3574       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3575     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3577   [outerpool release];
3578   outerpool = [[NSAutoreleasePool alloc] init];
3581   send_appdefined = YES;
3582   if (nr > 0)
3583     {
3584       pthread_mutex_lock (&select_mutex);
3585       select_nfds = nfds;
3586       select_valid = 0;
3587       if (readfds)
3588         {
3589           select_readfds = *readfds;
3590           select_valid += SELECT_HAVE_READ;
3591         }
3592       if (writefds)
3593         {
3594           select_writefds = *writefds;
3595           select_valid += SELECT_HAVE_WRITE;
3596         }
3598       if (timeout)
3599         {
3600           select_timeout = *timeout;
3601           select_valid += SELECT_HAVE_TMO;
3602         }
3604       pthread_mutex_unlock (&select_mutex);
3606       /* Inform fd_handler that select should be called */
3607       c = 'g';
3608       emacs_write_sig (selfds[1], &c, 1);
3609     }
3610   else if (nr == 0 && timeout)
3611     {
3612       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3613       double time = EMACS_TIME_TO_DOUBLE (*timeout);
3614       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3615                                                       target: NSApp
3616                                                     selector:
3617                                   @selector (timeout_handler:)
3618                                                     userInfo: 0
3619                                                      repeats: NO]
3620                       retain];
3621     }
3622   else /* No timeout and no file descriptors, can this happen?  */
3623     {
3624       /* Send appdefined so we exit from the loop */
3625       ns_send_appdefined (-1);
3626     }
3628   EVENT_INIT (event);
3629   block_input ();
3630   emacs_event = &event;
3631   if (++apploopnr != 1)
3632     {
3633       emacs_abort ();
3634     }
3635   [NSApp run];
3636   --apploopnr;
3637   emacs_event = NULL;
3638   if (nr > 0 && readfds)
3639     {
3640       c = 's';
3641       emacs_write_sig (selfds[1], &c, 1);
3642     }
3643   unblock_input ();
3645   t = last_appdefined_event_data;
3647   if (t != NO_APPDEFINED_DATA)
3648     {
3649       last_appdefined_event_data = NO_APPDEFINED_DATA;
3651       if (t == -2)
3652         {
3653           /* The NX_APPDEFINED event we received was a timeout. */
3654           result = 0;
3655         }
3656       else if (t == -1)
3657         {
3658           /* The NX_APPDEFINED event we received was the result of
3659              at least one real input event arriving.  */
3660           errno = EINTR;
3661           result = -1;
3662         }
3663       else
3664         {
3665           /* Received back from select () in fd_handler; copy the results */
3666           pthread_mutex_lock (&select_mutex);
3667           if (readfds) *readfds = select_readfds;
3668           if (writefds) *writefds = select_writefds;
3669           if (timeout) *timeout = select_timeout;
3670           pthread_mutex_unlock (&select_mutex);
3671           result = t;
3672         }
3673     }
3674   else
3675     {
3676       errno = EINTR;
3677       result = -1;
3678     }
3680   return result;
3685 /* ==========================================================================
3687     Scrollbar handling
3689    ========================================================================== */
3692 static void
3693 ns_set_vertical_scroll_bar (struct window *window,
3694                            int portion, int whole, int position)
3695 /* --------------------------------------------------------------------------
3696       External (hook): Update or add scrollbar
3697    -------------------------------------------------------------------------- */
3699   Lisp_Object win;
3700   NSRect r, v;
3701   struct frame *f = XFRAME (WINDOW_FRAME (window));
3702   EmacsView *view = FRAME_NS_VIEW (f);
3703   int window_y, window_height;
3704   int top, left, height, width, sb_width, sb_left;
3705   EmacsScroller *bar;
3706   BOOL fringe_extended_p;
3708   /* optimization; display engine sends WAY too many of these.. */
3709   if (!NILP (window->vertical_scroll_bar))
3710     {
3711       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3712       if ([bar checkSamePosition: position portion: portion whole: whole])
3713         {
3714           if (view->scrollbarsNeedingUpdate == 0)
3715             {
3716               if (!windows_or_buffers_changed)
3717                   return;
3718             }
3719           else
3720             view->scrollbarsNeedingUpdate--;
3721         }
3722     }
3724   NSTRACE (ns_set_vertical_scroll_bar);
3726   /* Get dimensions.  */
3727   window_box (window, -1, 0, &window_y, 0, &window_height);
3728   top = window_y;
3729   height = window_height;
3730   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3731   left = WINDOW_SCROLL_BAR_AREA_X (window);
3733   /* allow for displaying a skinnier scrollbar than char area allotted */
3734   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3735     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3736   sb_left = left;
3738   r = NSMakeRect (sb_left, top, sb_width, height);
3739   /* the parent view is flipped, so we need to flip y value */
3740   v = [view frame];
3741   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3743   fringe_extended_p = WINDOW_FRINGE_EXTENDED_P (window);
3745   XSETWINDOW (win, window);
3746   block_input ();
3748   /* we want at least 5 lines to display a scrollbar */
3749   if (WINDOW_TOTAL_LINES (window) < 5)
3750     {
3751       if (!NILP (window->vertical_scroll_bar))
3752         {
3753           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3754           [bar removeFromSuperview];
3755           wset_vertical_scroll_bar (window, Qnil);
3756         }
3757       ns_clear_frame_area (f, sb_left, top, width, height);
3758       unblock_input ();
3759       return;
3760     }
3762   if (NILP (window->vertical_scroll_bar))
3763     {
3764       if (width > 0 && height > 0)
3765         {
3766           if (fringe_extended_p)
3767             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3768           else
3769             ns_clear_frame_area (f, left, top, width, height);
3770         }
3772       bar = [[EmacsScroller alloc] initFrame: r window: win];
3773       wset_vertical_scroll_bar (window, make_save_ptr (bar));
3774     }
3775   else
3776     {
3777       NSRect oldRect;
3778       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3779       oldRect = [bar frame];
3780       r.size.width = oldRect.size.width;
3781       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3782         {
3783           if (oldRect.origin.x != r.origin.x)
3784               ns_clear_frame_area (f, sb_left, top, width, height);
3785           [bar setFrame: r];
3786         }
3787     }
3789   [bar setPosition: position portion: portion whole: whole];
3790   unblock_input ();
3794 static void
3795 ns_condemn_scroll_bars (struct frame *f)
3796 /* --------------------------------------------------------------------------
3797      External (hook): arrange for all frame's scrollbars to be removed
3798      at next call to judge_scroll_bars, except for those redeemed.
3799    -------------------------------------------------------------------------- */
3801   int i;
3802   id view;
3803   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3805   NSTRACE (ns_condemn_scroll_bars);
3807   for (i =[subviews count]-1; i >= 0; i--)
3808     {
3809       view = [subviews objectAtIndex: i];
3810       if ([view isKindOfClass: [EmacsScroller class]])
3811         [view condemn];
3812     }
3816 static void
3817 ns_redeem_scroll_bar (struct window *window)
3818 /* --------------------------------------------------------------------------
3819      External (hook): arrange to spare this window's scrollbar
3820      at next call to judge_scroll_bars.
3821    -------------------------------------------------------------------------- */
3823   id bar;
3824   NSTRACE (ns_redeem_scroll_bar);
3825   if (!NILP (window->vertical_scroll_bar))
3826     {
3827       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3828       [bar reprieve];
3829     }
3833 static void
3834 ns_judge_scroll_bars (struct frame *f)
3835 /* --------------------------------------------------------------------------
3836      External (hook): destroy all scrollbars on frame that weren't
3837      redeemed after call to condemn_scroll_bars.
3838    -------------------------------------------------------------------------- */
3840   int i;
3841   id view;
3842   EmacsView *eview = FRAME_NS_VIEW (f);
3843   NSArray *subviews = [[eview superview] subviews];
3844   BOOL removed = NO;
3846   NSTRACE (ns_judge_scroll_bars);
3847   for (i = [subviews count]-1; i >= 0; --i)
3848     {
3849       view = [subviews objectAtIndex: i];
3850       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3851       [view judge];
3852       removed = YES;
3853     }
3855   if (removed)
3856     [eview updateFrameSize: NO];
3859 /* ==========================================================================
3861     Initialization
3863    ========================================================================== */
3866 x_display_pixel_height (struct ns_display_info *dpyinfo)
3868   NSArray *screens = [NSScreen screens];
3869   NSEnumerator *enumerator = [screens objectEnumerator];
3870   NSScreen *screen;
3871   NSRect frame;
3873   frame = NSZeroRect;
3874   while ((screen = [enumerator nextObject]) != nil)
3875     frame = NSUnionRect (frame, [screen frame]);
3877   return NSHeight (frame);
3881 x_display_pixel_width (struct ns_display_info *dpyinfo)
3883   NSArray *screens = [NSScreen screens];
3884   NSEnumerator *enumerator = [screens objectEnumerator];
3885   NSScreen *screen;
3886   NSRect frame;
3888   frame = NSZeroRect;
3889   while ((screen = [enumerator nextObject]) != nil)
3890     frame = NSUnionRect (frame, [screen frame]);
3892   return NSWidth (frame);
3896 static Lisp_Object ns_string_to_lispmod (const char *s)
3897 /* --------------------------------------------------------------------------
3898      Convert modifier name to lisp symbol
3899    -------------------------------------------------------------------------- */
3901   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3902     return Qmeta;
3903   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3904     return Qsuper;
3905   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3906     return Qcontrol;
3907   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3908     return Qalt;
3909   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3910     return Qhyper;
3911   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3912     return Qnone;
3913   else
3914     return Qnil;
3918 static void
3919 ns_default (const char *parameter, Lisp_Object *result,
3920            Lisp_Object yesval, Lisp_Object noval,
3921            BOOL is_float, BOOL is_modstring)
3922 /* --------------------------------------------------------------------------
3923       Check a parameter value in user's preferences
3924    -------------------------------------------------------------------------- */
3926   const char *value = ns_get_defaults_value (parameter);
3928   if (value)
3929     {
3930       double f;
3931       char *pos;
3932       if (c_strcasecmp (value, "YES") == 0)
3933         *result = yesval;
3934       else if (c_strcasecmp (value, "NO") == 0)
3935         *result = noval;
3936       else if (is_float && (f = strtod (value, &pos), pos != value))
3937         *result = make_float (f);
3938       else if (is_modstring && value)
3939         *result = ns_string_to_lispmod (value);
3940       else fprintf (stderr,
3941                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3942     }
3946 static void
3947 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3948 /* --------------------------------------------------------------------------
3949       Initialize global info and storage for display.
3950    -------------------------------------------------------------------------- */
3952     NSScreen *screen = [NSScreen mainScreen];
3953     NSWindowDepth depth = [screen depth];
3954     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3956     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3957     dpyinfo->resy = 72.27;
3958     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3959                                                   NSColorSpaceFromDepth (depth)]
3960                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3961                                                  NSColorSpaceFromDepth (depth)];
3962     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3963     dpyinfo->image_cache = make_image_cache ();
3964     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
3965     dpyinfo->color_table->colors = NULL;
3966     dpyinfo->root_window = 42; /* a placeholder.. */
3968     hlinfo->mouse_face_mouse_frame = NULL;
3969     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3970     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3971     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3972     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3973     hlinfo->mouse_face_hidden = 0;
3975     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3976     hlinfo->mouse_face_defer = 0;
3978     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3980     dpyinfo->n_fonts = 0;
3981     dpyinfo->smallest_font_height = 1;
3982     dpyinfo->smallest_char_width = 1;
3986 /* This and next define (many of the) public functions in this file. */
3987 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3988          with using despite presence in the "system dependent" redisplay
3989          interface.  In addition, many of the ns_ methods have code that is
3990          shared with all terms, indicating need for further refactoring. */
3991 extern frame_parm_handler ns_frame_parm_handlers[];
3992 static struct redisplay_interface ns_redisplay_interface =
3994   ns_frame_parm_handlers,
3995   x_produce_glyphs,
3996   x_write_glyphs,
3997   x_insert_glyphs,
3998   x_clear_end_of_line,
3999   ns_scroll_run,
4000   ns_after_update_window_line,
4001   ns_update_window_begin,
4002   ns_update_window_end,
4003   x_cursor_to,
4004   ns_flush,
4005   0, /* flush_display_optional */
4006   x_clear_window_mouse_face,
4007   x_get_glyph_overhangs,
4008   x_fix_overlapping_area,
4009   ns_draw_fringe_bitmap,
4010   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4011   0, /* destroy_fringe_bitmap */
4012   ns_compute_glyph_string_overhangs,
4013   ns_draw_glyph_string, /* interface to nsfont.m */
4014   ns_define_frame_cursor,
4015   ns_clear_frame_area,
4016   ns_draw_window_cursor,
4017   ns_draw_vertical_window_border,
4018   ns_shift_glyphs_for_insert
4022 static void
4023 ns_delete_display (struct ns_display_info *dpyinfo)
4025   /* TODO... */
4029 /* This function is called when the last frame on a display is deleted. */
4030 static void
4031 ns_delete_terminal (struct terminal *terminal)
4033   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4035   /* Protect against recursive calls.  delete_frame in
4036      delete_terminal calls us back when it deletes our last frame.  */
4037   if (!terminal->name)
4038     return;
4040   block_input ();
4042   x_destroy_all_bitmaps (dpyinfo);
4043   ns_delete_display (dpyinfo);
4044   unblock_input ();
4048 static struct terminal *
4049 ns_create_terminal (struct ns_display_info *dpyinfo)
4050 /* --------------------------------------------------------------------------
4051       Set up use of NS before we make the first connection.
4052    -------------------------------------------------------------------------- */
4054   struct terminal *terminal;
4056   NSTRACE (ns_create_terminal);
4058   terminal = create_terminal ();
4060   terminal->type = output_ns;
4061   terminal->display_info.ns = dpyinfo;
4062   dpyinfo->terminal = terminal;
4064   terminal->rif = &ns_redisplay_interface;
4066   terminal->clear_frame_hook = ns_clear_frame;
4067   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4068   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
4069   terminal->ring_bell_hook = ns_ring_bell;
4070   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
4071   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
4072   terminal->update_begin_hook = ns_update_begin;
4073   terminal->update_end_hook = ns_update_end;
4074   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4075   terminal->read_socket_hook = ns_read_socket;
4076   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4077   terminal->mouse_position_hook = ns_mouse_position;
4078   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4079   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4081   terminal->fullscreen_hook = ns_fullscreen_hook;
4083   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4084   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4085   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4086   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4088   terminal->delete_frame_hook = x_destroy_window;
4089   terminal->delete_terminal_hook = ns_delete_terminal;
4091   terminal->scroll_region_ok = 1;
4092   terminal->char_ins_del_ok = 1;
4093   terminal->line_ins_del_ok = 1;
4094   terminal->fast_clear_end_of_line = 1;
4095   terminal->memory_below_frame = 0;
4097   return terminal;
4101 struct ns_display_info *
4102 ns_term_init (Lisp_Object display_name)
4103 /* --------------------------------------------------------------------------
4104      Start the Application and get things rolling.
4105    -------------------------------------------------------------------------- */
4107   struct terminal *terminal;
4108   struct ns_display_info *dpyinfo;
4109   static int ns_initialized = 0;
4110   Lisp_Object tmp;
4112   if (ns_initialized) return x_display_list;
4113   ns_initialized = 1;
4115   NSTRACE (ns_term_init);
4117   [outerpool release];
4118   outerpool = [[NSAutoreleasePool alloc] init];
4120   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4121   /*GSDebugAllocationActive (YES); */
4122   block_input ();
4124   baud_rate = 38400;
4125   Fset_input_interrupt_mode (Qnil);
4127   if (selfds[0] == -1)
4128     {
4129       if (emacs_pipe (selfds) != 0)
4130         {
4131           fprintf (stderr, "Failed to create pipe: %s\n",
4132                    emacs_strerror (errno));
4133           emacs_abort ();
4134         }
4136       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4137       FD_ZERO (&select_readfds);
4138       FD_ZERO (&select_writefds);
4139       pthread_mutex_init (&select_mutex, NULL);
4140     }
4142   ns_pending_files = [[NSMutableArray alloc] init];
4143   ns_pending_service_names = [[NSMutableArray alloc] init];
4144   ns_pending_service_args = [[NSMutableArray alloc] init];
4146 /* Start app and create the main menu, window, view.
4147      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4148      The view will then ask the NSApp to stop and return to Emacs. */
4149   [EmacsApp sharedApplication];
4150   if (NSApp == nil)
4151     return NULL;
4152   [NSApp setDelegate: NSApp];
4154   /* Start the select thread.  */
4155   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4156                            toTarget:NSApp
4157                          withObject:nil];
4159   /* debugging: log all notifications */
4160   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4161                                          selector: @selector (logNotification:)
4162                                              name: nil object: nil]; */
4164   dpyinfo = xzalloc (sizeof *dpyinfo);
4166   ns_initialize_display_info (dpyinfo);
4167   terminal = ns_create_terminal (dpyinfo);
4169   terminal->kboard = xmalloc (sizeof *terminal->kboard);
4170   init_kboard (terminal->kboard);
4171   kset_window_system (terminal->kboard, Qns);
4172   terminal->kboard->next_kboard = all_kboards;
4173   all_kboards = terminal->kboard;
4174   /* Don't let the initial kboard remain current longer than necessary.
4175      That would cause problems if a file loaded on startup tries to
4176      prompt in the mini-buffer.  */
4177   if (current_kboard == initial_kboard)
4178     current_kboard = terminal->kboard;
4179   terminal->kboard->reference_count++;
4181   dpyinfo->next = x_display_list;
4182   x_display_list = dpyinfo;
4184   /* Put it on ns_display_name_list */
4185   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4186                                 ns_display_name_list);
4187   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4189   terminal->name = xstrdup (SSDATA (display_name));
4191   unblock_input ();
4193   if (!inhibit_x_resources)
4194     {
4195       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4196                  Qt, Qnil, NO, NO);
4197       tmp = Qnil;
4198       /* this is a standard variable */
4199       ns_default ("AppleAntiAliasingThreshold", &tmp,
4200                  make_float (10.0), make_float (6.0), YES, NO);
4201       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4202     }
4204   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4205                          stringForKey: @"AppleHighlightColor"];
4206   if (ns_selection_color == nil)
4207     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4209   {
4210     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4212     if ( cl == nil )
4213       {
4214         Lisp_Object color_file, color_map, color;
4215         unsigned long c;
4216         char *name;
4218         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4219                          Fsymbol_value (intern ("data-directory")));
4221         color_map = Fx_load_color_file (color_file);
4222         if (NILP (color_map))
4223           fatal ("Could not read %s.\n", SDATA (color_file));
4225         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4226         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4227           {
4228             color = XCAR (color_map);
4229             name = SSDATA (XCAR (color));
4230             c = XINT (XCDR (color));
4231             [cl setColor:
4232                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4233                                             green: GREEN_FROM_ULONG (c) / 255.0
4234                                              blue: BLUE_FROM_ULONG (c) / 255.0
4235                                             alpha: 1.0]
4236                   forKey: [NSString stringWithUTF8String: name]];
4237           }
4238         [cl writeToFile: nil];
4239       }
4240   }
4242   {
4243 #ifdef NS_IMPL_GNUSTEP
4244     Vwindow_system_version = build_string (gnustep_base_version);
4245 #else
4246     /*PSnextrelease (128, c); */
4247     char c[DBL_BUFSIZE_BOUND];
4248     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4249     Vwindow_system_version = make_unibyte_string (c, len);
4250 #endif
4251   }
4253   delete_keyboard_wait_descriptor (0);
4255   ns_app_name = [[NSProcessInfo processInfo] processName];
4257 /* Set up OS X app menu */
4258 #ifdef NS_IMPL_COCOA
4259   {
4260     NSMenu *appMenu;
4261     NSMenuItem *item;
4262     /* set up the application menu */
4263     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4264     [svcsMenu setAutoenablesItems: NO];
4265     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4266     [appMenu setAutoenablesItems: NO];
4267     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4268     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4270     [appMenu insertItemWithTitle: @"About Emacs"
4271                           action: @selector (orderFrontStandardAboutPanel:)
4272                    keyEquivalent: @""
4273                          atIndex: 0];
4274     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4275     [appMenu insertItemWithTitle: @"Preferences..."
4276                           action: @selector (showPreferencesWindow:)
4277                    keyEquivalent: @","
4278                          atIndex: 2];
4279     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4280     item = [appMenu insertItemWithTitle: @"Services"
4281                                  action: @selector (menuDown:)
4282                           keyEquivalent: @""
4283                                 atIndex: 4];
4284     [appMenu setSubmenu: svcsMenu forItem: item];
4285     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4286     [appMenu insertItemWithTitle: @"Hide Emacs"
4287                           action: @selector (hide:)
4288                    keyEquivalent: @"h"
4289                          atIndex: 6];
4290     item =  [appMenu insertItemWithTitle: @"Hide Others"
4291                           action: @selector (hideOtherApplications:)
4292                    keyEquivalent: @"h"
4293                          atIndex: 7];
4294     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4295     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4296     [appMenu insertItemWithTitle: @"Quit Emacs"
4297                           action: @selector (terminate:)
4298                    keyEquivalent: @"q"
4299                          atIndex: 9];
4301     item = [mainMenu insertItemWithTitle: ns_app_name
4302                                   action: @selector (menuDown:)
4303                            keyEquivalent: @""
4304                                  atIndex: 0];
4305     [mainMenu setSubmenu: appMenu forItem: item];
4306     [dockMenu insertItemWithTitle: @"New Frame"
4307                            action: @selector (newFrame:)
4308                     keyEquivalent: @""
4309                           atIndex: 0];
4311     [NSApp setMainMenu: mainMenu];
4312     [NSApp setAppleMenu: appMenu];
4313     [NSApp setServicesMenu: svcsMenu];
4314     /* Needed at least on Cocoa, to get dock menu to show windows */
4315     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4317     [[NSNotificationCenter defaultCenter]
4318       addObserver: mainMenu
4319          selector: @selector (trackingNotification:)
4320              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4321     [[NSNotificationCenter defaultCenter]
4322       addObserver: mainMenu
4323          selector: @selector (trackingNotification:)
4324              name: NSMenuDidEndTrackingNotification object: mainMenu];
4325   }
4326 #endif /* MAC OS X menu setup */
4328   /* Register our external input/output types, used for determining
4329      applicable services and also drag/drop eligibility. */
4330   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4331   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4332                       retain];
4333   ns_drag_types = [[NSArray arrayWithObjects:
4334                             NSStringPboardType,
4335                             NSTabularTextPboardType,
4336                             NSFilenamesPboardType,
4337                             NSURLPboardType,
4338                             NSColorPboardType,
4339                             NSFontPboardType, nil] retain];
4341   /* If fullscreen is in init/default-frame-alist, focus isn't set
4342      right for fullscreen windows, so set this.  */
4343   [NSApp activateIgnoringOtherApps:YES];
4345   [NSApp run];
4346   ns_do_open_file = YES;
4348 #ifdef NS_IMPL_GNUSTEP
4349   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4350      We must re-catch it so subprocess works.  */
4351   catch_child_signal ();
4352 #endif
4353   return dpyinfo;
4357 void
4358 ns_term_shutdown (int sig)
4360   [[NSUserDefaults standardUserDefaults] synchronize];
4362   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4363   if (STRINGP (Vauto_save_list_file_name))
4364     unlink (SSDATA (Vauto_save_list_file_name));
4366   if (sig == 0 || sig == SIGTERM)
4367     {
4368       [NSApp terminate: NSApp];
4369     }
4370   else // force a stack trace to happen
4371     {
4372       emacs_abort ();
4373     }
4377 /* ==========================================================================
4379     EmacsApp implementation
4381    ========================================================================== */
4384 @implementation EmacsApp
4386 - (void)logNotification: (NSNotification *)notification
4388   const char *name = [[notification name] UTF8String];
4389   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4390       && !strstr (name, "WindowNumber"))
4391     NSLog (@"notification: '%@'", [notification name]);
4395 - (void)sendEvent: (NSEvent *)theEvent
4396 /* --------------------------------------------------------------------------
4397      Called when NSApp is running for each event received.  Used to stop
4398      the loop when we choose, since there's no way to just run one iteration.
4399    -------------------------------------------------------------------------- */
4401   int type = [theEvent type];
4402   NSWindow *window = [theEvent window];
4404 /*  NSTRACE (sendEvent); */
4405 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4407 #ifdef NS_IMPL_GNUSTEP
4408   // Keyboard events aren't propagated to file dialogs for some reason.
4409   if ([NSApp modalWindow] != nil &&
4410       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4411     {
4412       [[NSApp modalWindow] sendEvent: theEvent];
4413       return;
4414     }
4415 #endif
4417   if (type == NSApplicationDefined)
4418     {
4419       switch ([theEvent data2])
4420         {
4421 #ifdef NS_IMPL_COCOA
4422         case NSAPP_DATA2_RUNASSCRIPT:
4423           ns_run_ascript ();
4424           [self stop: self];
4425           return;
4426 #endif
4427         case NSAPP_DATA2_RUNFILEDIALOG:
4428           ns_run_file_dialog ();
4429           [self stop: self];
4430           return;
4431         }
4432     }
4434   if (type == NSCursorUpdate && window == nil)
4435     {
4436       fprintf (stderr, "Dropping external cursor update event.\n");
4437       return;
4438     }
4440   if (type == NSApplicationDefined)
4441     {
4442       /* Events posted by ns_send_appdefined interrupt the run loop here.
4443          But, if a modal window is up, an appdefined can still come through,
4444          (e.g., from a makeKeyWindow event) but stopping self also stops the
4445          modal loop. Just defer it until later. */
4446       if ([NSApp modalWindow] == nil)
4447         {
4448           last_appdefined_event_data = [theEvent data1];
4449           [self stop: self];
4450         }
4451       else
4452         {
4453           send_appdefined = YES;
4454         }
4455     }
4458 #ifdef NS_IMPL_COCOA
4459   /* If no dialog and none of our frames have focus and it is a move, skip it.
4460      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4461      such as Wifi, sound, date or similar.
4462      This prevents "spooky" highlighting in the frame under the menu.  */
4463   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4464     {
4465       struct ns_display_info *di;
4466       BOOL has_focus = NO;
4467       for (di = x_display_list; ! has_focus && di; di = di->next)
4468         has_focus = di->x_focus_frame != 0;
4469       if (! has_focus)
4470         return;
4471     }
4472 #endif
4474   [super sendEvent: theEvent];
4478 - (void)showPreferencesWindow: (id)sender
4480   struct frame *emacsframe = SELECTED_FRAME ();
4481   NSEvent *theEvent = [NSApp currentEvent];
4483   if (!emacs_event)
4484     return;
4485   emacs_event->kind = NS_NONKEY_EVENT;
4486   emacs_event->code = KEY_NS_SHOW_PREFS;
4487   emacs_event->modifiers = 0;
4488   EV_TRAILER (theEvent);
4492 - (void)newFrame: (id)sender
4494   struct frame *emacsframe = SELECTED_FRAME ();
4495   NSEvent *theEvent = [NSApp currentEvent];
4497   if (!emacs_event)
4498     return;
4499   emacs_event->kind = NS_NONKEY_EVENT;
4500   emacs_event->code = KEY_NS_NEW_FRAME;
4501   emacs_event->modifiers = 0;
4502   EV_TRAILER (theEvent);
4506 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4507 - (BOOL) openFile: (NSString *)fileName
4509   struct frame *emacsframe = SELECTED_FRAME ();
4510   NSEvent *theEvent = [NSApp currentEvent];
4512   if (!emacs_event)
4513     return NO;
4515   emacs_event->kind = NS_NONKEY_EVENT;
4516   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4517   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4518   ns_input_line = Qnil; /* can be start or cons start,end */
4519   emacs_event->modifiers =0;
4520   EV_TRAILER (theEvent);
4522   return YES;
4526 /* **************************************************************************
4528       EmacsApp delegate implementation
4530    ************************************************************************** */
4532 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4533 /* --------------------------------------------------------------------------
4534      When application is loaded, terminate event loop in ns_term_init
4535    -------------------------------------------------------------------------- */
4537   NSTRACE (applicationDidFinishLaunching);
4538   [NSApp setServicesProvider: NSApp];
4539   ns_send_appdefined (-2);
4543 /* Termination sequences:
4544     C-x C-c:
4545     Cmd-Q:
4546     MenuBar | File | Exit:
4547     Select Quit from App menubar:
4548         -terminate
4549         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4550         ns_term_shutdown()
4552     Select Quit from Dock menu:
4553     Logout attempt:
4554         -appShouldTerminate
4555           Cancel -> Nothing else
4556           Accept ->
4558           -terminate
4559           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4560           ns_term_shutdown()
4564 - (void) terminate: (id)sender
4566   struct frame *emacsframe = SELECTED_FRAME ();
4568   if (!emacs_event)
4569     return;
4571   emacs_event->kind = NS_NONKEY_EVENT;
4572   emacs_event->code = KEY_NS_POWER_OFF;
4573   emacs_event->arg = Qt; /* mark as non-key event */
4574   EV_TRAILER ((id)nil);
4578 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4580   int ret;
4582   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4583     return NSTerminateNow;
4585     ret = NSRunAlertPanel(ns_app_name,
4586                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4587                           @"Save Buffers and Exit", @"Cancel", nil);
4589     if (ret == NSAlertDefaultReturn)
4590         return NSTerminateNow;
4591     else if (ret == NSAlertAlternateReturn)
4592         return NSTerminateCancel;
4593     return NSTerminateNow;  /* just in case */
4596 static int
4597 not_in_argv (NSString *arg)
4599   int k;
4600   const char *a = [arg UTF8String];
4601   for (k = 1; k < initial_argc; ++k)
4602     if (strcmp (a, initial_argv[k]) == 0) return 0;
4603   return 1;
4606 /*   Notification from the Workspace to open a file */
4607 - (BOOL)application: sender openFile: (NSString *)file
4609   if (ns_do_open_file || not_in_argv (file))
4610     [ns_pending_files addObject: file];
4611   return YES;
4615 /*   Open a file as a temporary file */
4616 - (BOOL)application: sender openTempFile: (NSString *)file
4618   if (ns_do_open_file || not_in_argv (file))
4619     [ns_pending_files addObject: file];
4620   return YES;
4624 /*   Notification from the Workspace to open a file noninteractively (?) */
4625 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4627   if (ns_do_open_file || not_in_argv (file))
4628     [ns_pending_files addObject: file];
4629   return YES;
4632 /*   Notification from the Workspace to open multiple files */
4633 - (void)application: sender openFiles: (NSArray *)fileList
4635   NSEnumerator *files = [fileList objectEnumerator];
4636   NSString *file;
4637   /* Don't open files from the command line unconditionally,
4638      Cocoa parses the command line wrong, --option value tries to open value
4639      if --option is the last option.  */
4640   while ((file = [files nextObject]) != nil)
4641     if (ns_do_open_file || not_in_argv (file))
4642       [ns_pending_files addObject: file];
4644   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4649 /* Handle dock menu requests.  */
4650 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4652   return dockMenu;
4656 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4657 - (void)applicationWillBecomeActive: (NSNotification *)notification
4659   //ns_app_active=YES;
4661 - (void)applicationDidBecomeActive: (NSNotification *)notification
4663   NSTRACE (applicationDidBecomeActive);
4665   //ns_app_active=YES;
4667   ns_update_auto_hide_menu_bar ();
4668   // No constraining takes place when the application is not active.
4669   ns_constrain_all_frames ();
4671 - (void)applicationDidResignActive: (NSNotification *)notification
4673   //ns_app_active=NO;
4674   ns_send_appdefined (-1);
4679 /* ==========================================================================
4681     EmacsApp aux handlers for managing event loop
4683    ========================================================================== */
4686 - (void)timeout_handler: (NSTimer *)timedEntry
4687 /* --------------------------------------------------------------------------
4688      The timeout specified to ns_select has passed.
4689    -------------------------------------------------------------------------- */
4691   /*NSTRACE (timeout_handler); */
4692   ns_send_appdefined (-2);
4695 #ifdef NS_IMPL_GNUSTEP
4696 - (void)sendFromMainThread:(id)unused
4698   ns_send_appdefined (nextappdefined);
4700 #endif
4702 - (void)fd_handler:(id)unused
4703 /* --------------------------------------------------------------------------
4704      Check data waiting on file descriptors and terminate if so
4705    -------------------------------------------------------------------------- */
4707   int result;
4708   int waiting = 1, nfds;
4709   char c;
4711   SELECT_TYPE readfds, writefds, *wfds;
4712   EMACS_TIME timeout, *tmo;
4713   NSAutoreleasePool *pool = nil;
4715   /* NSTRACE (fd_handler); */
4717   for (;;)
4718     {
4719       [pool release];
4720       pool = [[NSAutoreleasePool alloc] init];
4722       if (waiting)
4723         {
4724           SELECT_TYPE fds;
4725           FD_ZERO (&fds);
4726           FD_SET (selfds[0], &fds);
4727           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4728           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4729             waiting = 0;
4730         }
4731       else
4732         {
4733           pthread_mutex_lock (&select_mutex);
4734           nfds = select_nfds;
4736           if (select_valid & SELECT_HAVE_READ)
4737             readfds = select_readfds;
4738           else
4739             FD_ZERO (&readfds);
4741           if (select_valid & SELECT_HAVE_WRITE)
4742             {
4743               writefds = select_writefds;
4744               wfds = &writefds;
4745             }
4746           else
4747             wfds = NULL;
4748           if (select_valid & SELECT_HAVE_TMO)
4749             {
4750               timeout = select_timeout;
4751               tmo = &timeout;
4752             }
4753           else
4754             tmo = NULL;
4756           pthread_mutex_unlock (&select_mutex);
4758           FD_SET (selfds[0], &readfds);
4759           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4761           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4763           if (result == 0)
4764             ns_send_appdefined (-2);
4765           else if (result > 0)
4766             {
4767               if (FD_ISSET (selfds[0], &readfds))
4768                 {
4769                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4770                     waiting = 1;
4771                 }
4772               else
4773                 {
4774                   pthread_mutex_lock (&select_mutex);
4775                   if (select_valid & SELECT_HAVE_READ)
4776                     select_readfds = readfds;
4777                   if (select_valid & SELECT_HAVE_WRITE)
4778                     select_writefds = writefds;
4779                   if (select_valid & SELECT_HAVE_TMO)
4780                     select_timeout = timeout;
4781                   pthread_mutex_unlock (&select_mutex);
4783                   ns_send_appdefined (result);
4784                 }
4785             }
4786           waiting = 1;
4787         }
4788     }
4793 /* ==========================================================================
4795     Service provision
4797    ========================================================================== */
4799 /* called from system: queue for next pass through event loop */
4800 - (void)requestService: (NSPasteboard *)pboard
4801               userData: (NSString *)userData
4802                  error: (NSString **)error
4804   [ns_pending_service_names addObject: userData];
4805   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4806       SSDATA (ns_string_from_pasteboard (pboard))]];
4810 /* called from ns_read_socket to clear queue */
4811 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4813   struct frame *emacsframe = SELECTED_FRAME ();
4814   NSEvent *theEvent = [NSApp currentEvent];
4816   if (!emacs_event)
4817     return NO;
4819   emacs_event->kind = NS_NONKEY_EVENT;
4820   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4821   ns_input_spi_name = build_string ([name UTF8String]);
4822   ns_input_spi_arg = build_string ([arg UTF8String]);
4823   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4824   EV_TRAILER (theEvent);
4826   return YES;
4830 @end  /* EmacsApp */
4834 /* ==========================================================================
4836     EmacsView implementation
4838    ========================================================================== */
4841 @implementation EmacsView
4843 /* needed to inform when window closed from LISP */
4844 - (void) setWindowClosing: (BOOL)closing
4846   windowClosing = closing;
4850 - (void)dealloc
4852   NSTRACE (EmacsView_dealloc);
4853   [toolbar release];
4854   if (fs_state == FULLSCREEN_BOTH)
4855     [nonfs_window release];
4856   [super dealloc];
4860 /* called on font panel selection */
4861 - (void)changeFont: (id)sender
4863   NSEvent *e =[[self window] currentEvent];
4864   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4865   id newFont;
4866   CGFloat size;
4868   NSTRACE (changeFont);
4869   if (!emacs_event)
4870     return;
4872   if ((newFont = [sender convertFont:
4873                            ((struct nsfont_info *)face->font)->nsfont]))
4874     {
4875       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4877       emacs_event->kind = NS_NONKEY_EVENT;
4878       emacs_event->modifiers = 0;
4879       emacs_event->code = KEY_NS_CHANGE_FONT;
4881       size = [newFont pointSize];
4882       ns_input_fontsize = make_number (lrint (size));
4883       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4884       EV_TRAILER (e);
4885     }
4889 - (BOOL)acceptsFirstResponder
4891   NSTRACE (acceptsFirstResponder);
4892   return YES;
4896 - (void)resetCursorRects
4898   NSRect visible = [self visibleRect];
4899   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4900   NSTRACE (resetCursorRects);
4902   if (currentCursor == nil)
4903     currentCursor = [NSCursor arrowCursor];
4905   if (!NSIsEmptyRect (visible))
4906     [self addCursorRect: visible cursor: currentCursor];
4907   [currentCursor setOnMouseEntered: YES];
4912 /*****************************************************************************/
4913 /* Keyboard handling. */
4914 #define NS_KEYLOG 0
4916 - (void)keyDown: (NSEvent *)theEvent
4918   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4919   int code;
4920   unsigned fnKeysym = 0;
4921   static NSMutableArray *nsEvArray;
4922 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4923   static BOOL firstTime = YES;
4924 #endif
4925   int left_is_none;
4926   unsigned int flags = [theEvent modifierFlags];
4928   NSTRACE (keyDown);
4930   /* Rhapsody and OS X give up and down events for the arrow keys */
4931   if (ns_fake_keydown == YES)
4932     ns_fake_keydown = NO;
4933   else if ([theEvent type] != NSKeyDown)
4934     return;
4936   if (!emacs_event)
4937     return;
4939  if (![[self window] isKeyWindow]
4940      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4941      /* we must avoid an infinite loop here. */
4942      && (EmacsView *)[[theEvent window] delegate] != self)
4943    {
4944      /* XXX: There is an occasional condition in which, when Emacs display
4945          updates a different frame from the current one, and temporarily
4946          selects it, then processes some interrupt-driven input
4947          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4948          for some reason that window has its first responder set to the NSView
4949          most recently updated (I guess), which is not the correct one. */
4950      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4951      return;
4952    }
4954   if (nsEvArray == nil)
4955     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4957   [NSCursor setHiddenUntilMouseMoves: YES];
4959   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4960     {
4961       clear_mouse_face (hlinfo);
4962       hlinfo->mouse_face_hidden = 1;
4963     }
4965   if (!processingCompose)
4966     {
4967       /* When using screen sharing, no left or right information is sent,
4968          so use Left key in those cases.  */
4969       int is_left_key, is_right_key;
4971       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4972         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4974       /* (Carbon way: [theEvent keyCode]) */
4976       /* is it a "function key"? */
4977       fnKeysym = (code < 0x00ff && (flags&NSNumericPadKeyMask))
4978         ? ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask)
4979         : ns_convert_key (code);
4981       if (fnKeysym)
4982         {
4983           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4984              because Emacs treats Delete and KP-Delete same (in simple.el). */
4985           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4986 #ifdef NS_IMPL_GNUSTEP
4987               /*  GNUstep uses incompatible keycodes, even for those that are
4988                   supposed to be hardware independent.  Just check for delete.
4989                   Keypad delete does not have keysym 0xFFFF.
4990                   See http://savannah.gnu.org/bugs/?25395
4991               */
4992               || (fnKeysym == 0xFFFF && code == 127)
4993 #endif
4994             )
4995             code = 0xFF08; /* backspace */
4996           else
4997             code = fnKeysym;
4998         }
5000       /* are there modifiers? */
5001       emacs_event->modifiers = 0;
5003       if (flags & NSHelpKeyMask)
5004           emacs_event->modifiers |= hyper_modifier;
5006       if (flags & NSShiftKeyMask)
5007         emacs_event->modifiers |= shift_modifier;
5009       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5010       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5011         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5013       if (is_right_key)
5014         emacs_event->modifiers |= parse_solitary_modifier
5015           (EQ (ns_right_command_modifier, Qleft)
5016            ? ns_command_modifier
5017            : ns_right_command_modifier);
5019       if (is_left_key)
5020         {
5021           emacs_event->modifiers |= parse_solitary_modifier
5022             (ns_command_modifier);
5024           /* if super (default), take input manager's word so things like
5025              dvorak / qwerty layout work */
5026           if (EQ (ns_command_modifier, Qsuper)
5027               && !fnKeysym
5028               && [[theEvent characters] length] != 0)
5029             {
5030               /* XXX: the code we get will be unshifted, so if we have
5031                  a shift modifier, must convert ourselves */
5032               if (!(flags & NSShiftKeyMask))
5033                 code = [[theEvent characters] characterAtIndex: 0];
5034 #if 0
5035               /* this is ugly and also requires linking w/Carbon framework
5036                  (for LMGetKbdType) so for now leave this rare (?) case
5037                  undealt with.. in future look into CGEvent methods */
5038               else
5039                 {
5040                   long smv = GetScriptManagerVariable (smKeyScript);
5041                   Handle uchrHandle = GetResource
5042                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5043                   UInt32 dummy = 0;
5044                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5045                                  [[theEvent characters] characterAtIndex: 0],
5046                                  kUCKeyActionDisplay,
5047                                  (flags & ~NSCommandKeyMask) >> 8,
5048                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5049                                  &dummy, 1, &dummy, &code);
5050                   code &= 0xFF;
5051                 }
5052 #endif
5053             }
5054         }
5056       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5057       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5058         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5060       if (is_right_key)
5061           emacs_event->modifiers |= parse_solitary_modifier
5062               (EQ (ns_right_control_modifier, Qleft)
5063                ? ns_control_modifier
5064                : ns_right_control_modifier);
5066       if (is_left_key)
5067         emacs_event->modifiers |= parse_solitary_modifier
5068           (ns_control_modifier);
5070       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5071           emacs_event->modifiers |=
5072             parse_solitary_modifier (ns_function_modifier);
5074       left_is_none = NILP (ns_alternate_modifier)
5075         || EQ (ns_alternate_modifier, Qnone);
5077       is_right_key = (flags & NSRightAlternateKeyMask)
5078         == NSRightAlternateKeyMask;
5079       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5080         || (! is_right_key
5081             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5083       if (is_right_key)
5084         {
5085           if ((NILP (ns_right_alternate_modifier)
5086                || EQ (ns_right_alternate_modifier, Qnone)
5087                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5088               && !fnKeysym)
5089             {   /* accept pre-interp alt comb */
5090               if ([[theEvent characters] length] > 0)
5091                 code = [[theEvent characters] characterAtIndex: 0];
5092               /*HACK: clear lone shift modifier to stop next if from firing */
5093               if (emacs_event->modifiers == shift_modifier)
5094                 emacs_event->modifiers = 0;
5095             }
5096           else
5097             emacs_event->modifiers |= parse_solitary_modifier
5098               (EQ (ns_right_alternate_modifier, Qleft)
5099                ? ns_alternate_modifier
5100                : ns_right_alternate_modifier);
5101         }
5103       if (is_left_key) /* default = meta */
5104         {
5105           if (left_is_none && !fnKeysym)
5106             {   /* accept pre-interp alt comb */
5107               if ([[theEvent characters] length] > 0)
5108                 code = [[theEvent characters] characterAtIndex: 0];
5109               /*HACK: clear lone shift modifier to stop next if from firing */
5110               if (emacs_event->modifiers == shift_modifier)
5111                 emacs_event->modifiers = 0;
5112             }
5113           else
5114               emacs_event->modifiers |=
5115                 parse_solitary_modifier (ns_alternate_modifier);
5116         }
5118   if (NS_KEYLOG)
5119     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5120              code, fnKeysym, flags, emacs_event->modifiers);
5122       /* if it was a function key or had modifiers, pass it directly to emacs */
5123       if (fnKeysym || (emacs_event->modifiers
5124                        && (emacs_event->modifiers != shift_modifier)
5125                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5126 /*[[theEvent characters] length] */
5127         {
5128           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5129           if (code < 0x20)
5130             code |= (1<<28)|(3<<16);
5131           else if (code == 0x7f)
5132             code |= (1<<28)|(3<<16);
5133           else if (!fnKeysym)
5134             emacs_event->kind = code > 0xFF
5135               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5137           emacs_event->code = code;
5138           EV_TRAILER (theEvent);
5139           processingCompose = NO;
5140           return;
5141         }
5142     }
5145 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5146   /* if we get here we should send the key for input manager processing */
5147   /* Disable warning, there is nothing a user can do about it anyway, and
5148      it does not seem to matter.  */
5149 #if 0
5150   if (firstTime && [[NSInputManager currentInputManager]
5151                      wantsToDelayTextChangeNotifications] == NO)
5152     fprintf (stderr,
5153           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5154 #endif
5155   firstTime = NO;
5156 #endif
5157   if (NS_KEYLOG && !processingCompose)
5158     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5160   processingCompose = YES;
5161   [nsEvArray addObject: theEvent];
5162   [self interpretKeyEvents: nsEvArray];
5163   [nsEvArray removeObject: theEvent];
5167 #ifdef NS_IMPL_COCOA
5168 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5169    decided not to send key-down for.
5170    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5171    This only applies on Tiger and earlier.
5172    If it matches one of these, send it on to keyDown. */
5173 -(void)keyUp: (NSEvent *)theEvent
5175   int flags = [theEvent modifierFlags];
5176   int code = [theEvent keyCode];
5177   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5178       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5179     {
5180       if (NS_KEYLOG)
5181         fprintf (stderr, "keyUp: passed test");
5182       ns_fake_keydown = YES;
5183       [self keyDown: theEvent];
5184     }
5186 #endif
5189 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5192 /* <NSTextInput>: called when done composing;
5193    NOTE: also called when we delete over working text, followed immed.
5194          by doCommandBySelector: deleteBackward: */
5195 - (void)insertText: (id)aString
5197   int code;
5198   int len = [(NSString *)aString length];
5199   int i;
5201   if (NS_KEYLOG)
5202     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5203   processingCompose = NO;
5205   if (!emacs_event)
5206     return;
5208   /* first, clear any working text */
5209   if (workingText != nil)
5210     [self deleteWorkingText];
5212   /* now insert the string as keystrokes */
5213   for (i =0; i<len; i++)
5214     {
5215       code = [aString characterAtIndex: i];
5216       /* TODO: still need this? */
5217       if (code == 0x2DC)
5218         code = '~'; /* 0x7E */
5219       if (code != 32) /* Space */
5220         emacs_event->modifiers = 0;
5221       emacs_event->kind
5222         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5223       emacs_event->code = code;
5224       EV_TRAILER ((id)nil);
5225     }
5229 /* <NSTextInput>: inserts display of composing characters */
5230 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5232   NSString *str = [aString respondsToSelector: @selector (string)] ?
5233     [aString string] : aString;
5234   if (NS_KEYLOG)
5235     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
5236            selRange.length, selRange.location);
5238   if (workingText != nil)
5239     [self deleteWorkingText];
5240   if ([str length] == 0)
5241     return;
5243   if (!emacs_event)
5244     return;
5246   processingCompose = YES;
5247   workingText = [str copy];
5248   ns_working_text = build_string ([workingText UTF8String]);
5250   emacs_event->kind = NS_TEXT_EVENT;
5251   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5252   EV_TRAILER ((id)nil);
5256 /* delete display of composing characters [not in <NSTextInput>] */
5257 - (void)deleteWorkingText
5259   if (workingText == nil)
5260     return;
5261   if (NS_KEYLOG)
5262     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
5263   [workingText release];
5264   workingText = nil;
5265   processingCompose = NO;
5267   if (!emacs_event)
5268     return;
5270   emacs_event->kind = NS_TEXT_EVENT;
5271   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5272   EV_TRAILER ((id)nil);
5276 - (BOOL)hasMarkedText
5278   return workingText != nil;
5282 - (NSRange)markedRange
5284   NSRange rng = workingText != nil
5285     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5286   if (NS_KEYLOG)
5287     NSLog (@"markedRange request");
5288   return rng;
5292 - (void)unmarkText
5294   if (NS_KEYLOG)
5295     NSLog (@"unmark (accept) text");
5296   [self deleteWorkingText];
5297   processingCompose = NO;
5301 /* used to position char selection windows, etc. */
5302 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5304   NSRect rect;
5305   NSPoint pt;
5306   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5307   if (NS_KEYLOG)
5308     NSLog (@"firstRectForCharRange request");
5310   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5311   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5312   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5313   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5314                                        +FRAME_LINE_HEIGHT (emacsframe));
5316   pt = [self convertPoint: pt toView: nil];
5317   pt = [[self window] convertBaseToScreen: pt];
5318   rect.origin = pt;
5319   return rect;
5323 - (NSInteger)conversationIdentifier
5325   return (NSInteger)self;
5329 - (void)doCommandBySelector: (SEL)aSelector
5331   if (NS_KEYLOG)
5332     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5334   processingCompose = NO;
5335   if (aSelector == @selector (deleteBackward:))
5336     {
5337       /* happens when user backspaces over an ongoing composition:
5338          throw a 'delete' into the event queue */
5339       if (!emacs_event)
5340         return;
5341       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5342       emacs_event->code = 0xFF08;
5343       EV_TRAILER ((id)nil);
5344     }
5347 - (NSArray *)validAttributesForMarkedText
5349   static NSArray *arr = nil;
5350   if (arr == nil) arr = [NSArray new];
5351  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5352   return arr;
5355 - (NSRange)selectedRange
5357   if (NS_KEYLOG)
5358     NSLog (@"selectedRange request");
5359   return NSMakeRange (NSNotFound, 0);
5362 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5363     GNUSTEP_GUI_MINOR_VERSION > 22
5364 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5365 #else
5366 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5367 #endif
5369   if (NS_KEYLOG)
5370     NSLog (@"characterIndexForPoint request");
5371   return 0;
5374 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5376   static NSAttributedString *str = nil;
5377   if (str == nil) str = [NSAttributedString new];
5378   if (NS_KEYLOG)
5379     NSLog (@"attributedSubstringFromRange request");
5380   return str;
5383 /* End <NSTextInput> impl. */
5384 /*****************************************************************************/
5387 /* This is what happens when the user presses a mouse button.  */
5388 - (void)mouseDown: (NSEvent *)theEvent
5390   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5392   NSTRACE (mouseDown);
5394   [self deleteWorkingText];
5396   if (!emacs_event)
5397     return;
5399   last_mouse_frame = emacsframe;
5400   /* appears to be needed to prevent spurious movement events generated on
5401      button clicks */
5402   last_mouse_frame->mouse_moved = 0;
5404   if ([theEvent type] == NSScrollWheel)
5405     {
5406       CGFloat delta = [theEvent deltaY];
5407       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5408       if (delta == 0)
5409         return;
5410       emacs_event->kind = WHEEL_EVENT;
5411       emacs_event->code = 0;
5412       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5413         ((delta > 0) ? up_modifier : down_modifier);
5414     }
5415   else
5416     {
5417       emacs_event->kind = MOUSE_CLICK_EVENT;
5418       emacs_event->code = EV_BUTTON (theEvent);
5419       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5420                              | EV_UDMODIFIERS (theEvent);
5421     }
5422   XSETINT (emacs_event->x, lrint (p.x));
5423   XSETINT (emacs_event->y, lrint (p.y));
5424   EV_TRAILER (theEvent);
5428 - (void)rightMouseDown: (NSEvent *)theEvent
5430   NSTRACE (rightMouseDown);
5431   [self mouseDown: theEvent];
5435 - (void)otherMouseDown: (NSEvent *)theEvent
5437   NSTRACE (otherMouseDown);
5438   [self mouseDown: theEvent];
5442 - (void)mouseUp: (NSEvent *)theEvent
5444   NSTRACE (mouseUp);
5445   [self mouseDown: theEvent];
5449 - (void)rightMouseUp: (NSEvent *)theEvent
5451   NSTRACE (rightMouseUp);
5452   [self mouseDown: theEvent];
5456 - (void)otherMouseUp: (NSEvent *)theEvent
5458   NSTRACE (otherMouseUp);
5459   [self mouseDown: theEvent];
5463 - (void) scrollWheel: (NSEvent *)theEvent
5465   NSTRACE (scrollWheel);
5466   [self mouseDown: theEvent];
5470 /* Tell emacs the mouse has moved. */
5471 - (void)mouseMoved: (NSEvent *)e
5473   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5474   Lisp_Object frame;
5476 //  NSTRACE (mouseMoved);
5478   last_mouse_movement_time = EV_TIMESTAMP (e);
5479   last_mouse_motion_position
5480     = [self convertPoint: [e locationInWindow] fromView: nil];
5482   /* update any mouse face */
5483   if (hlinfo->mouse_face_hidden)
5484     {
5485       hlinfo->mouse_face_hidden = 0;
5486       clear_mouse_face (hlinfo);
5487     }
5489   /* tooltip handling */
5490   previous_help_echo_string = help_echo_string;
5491   help_echo_string = Qnil;
5493   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5494                             last_mouse_motion_position.y))
5495     help_echo_string = previous_help_echo_string;
5497   XSETFRAME (frame, emacsframe);
5498   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5499     {
5500       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5501          (note_mouse_highlight), which is called through the
5502          note_mouse_movement () call above */
5503       gen_help_event (help_echo_string, frame, help_echo_window,
5504                       help_echo_object, help_echo_pos);
5505     }
5506   else
5507     {
5508       help_echo_string = Qnil;
5509       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5510     }
5512   if (emacsframe->mouse_moved && send_appdefined)
5513     ns_send_appdefined (-1);
5517 - (void)mouseDragged: (NSEvent *)e
5519   NSTRACE (mouseDragged);
5520   [self mouseMoved: e];
5524 - (void)rightMouseDragged: (NSEvent *)e
5526   NSTRACE (rightMouseDragged);
5527   [self mouseMoved: e];
5531 - (void)otherMouseDragged: (NSEvent *)e
5533   NSTRACE (otherMouseDragged);
5534   [self mouseMoved: e];
5538 - (BOOL)windowShouldClose: (id)sender
5540   NSEvent *e =[[self window] currentEvent];
5542   NSTRACE (windowShouldClose);
5543   windowClosing = YES;
5544   if (!emacs_event)
5545     return NO;
5546   emacs_event->kind = DELETE_WINDOW_EVENT;
5547   emacs_event->modifiers = 0;
5548   emacs_event->code = 0;
5549   EV_TRAILER (e);
5550   /* Don't close this window, let this be done from lisp code.  */
5551   return NO;
5554 - (void) updateFrameSize: (BOOL) delay;
5556   NSWindow *window = [self window];
5557   NSRect wr = [window frame];
5558   int extra = 0;
5559   int gsextra = 0;
5560 #ifdef NS_IMPL_GNUSTEP
5561   gsextra = 3;
5562 #endif
5564   int oldc = cols, oldr = rows;
5565   int oldw = FRAME_PIXEL_WIDTH (emacsframe),
5566     oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5567   int neww, newh;
5569   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, wr.size.width + gsextra);
5571   if (cols < MINWIDTH)
5572     cols = MINWIDTH;
5574   if (! [self isFullscreen])
5575     {
5576       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5577         + FRAME_TOOLBAR_HEIGHT (emacsframe) - gsextra;
5578     }
5580   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, wr.size.height - extra);
5582   if (rows < MINHEIGHT)
5583     rows = MINHEIGHT;
5585   neww = (int)wr.size.width - emacsframe->border_width;
5586   newh = (int)wr.size.height - extra;
5588   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5589     {
5590       NSView *view = FRAME_NS_VIEW (emacsframe);
5591       NSWindow *win = [view window];
5592       NSSize sz = [win resizeIncrements];
5594       FRAME_PIXEL_WIDTH (emacsframe) = neww;
5595       FRAME_PIXEL_HEIGHT (emacsframe) = newh;
5596       change_frame_size (emacsframe, rows, cols, 0, delay, 0);
5597       SET_FRAME_GARBAGED (emacsframe);
5598       cancel_mouse_face (emacsframe);
5600       // Did resize increments change because of a font change?
5601       if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5602           sz.height != FRAME_LINE_HEIGHT (emacsframe))
5603         {
5604           sz.width = FRAME_COLUMN_WIDTH (emacsframe);
5605           sz.height = FRAME_LINE_HEIGHT (emacsframe);
5606           [win setResizeIncrements: sz];
5607         }
5609       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5610       [self windowDidMove:nil];   // Update top/left.
5611     }
5614 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5615 /* normalize frame to gridded text size */
5617   int extra = 0;
5618   int gsextra = 0;
5619 #ifdef NS_IMPL_GNUSTEP
5620   gsextra = 3;
5621 #endif
5623   NSTRACE (windowWillResize);
5624 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5626   if (fs_state == FULLSCREEN_MAXIMIZED
5627       && (maximized_width != (int)frameSize.width
5628           || maximized_height != (int)frameSize.height))
5629     [self setFSValue: FULLSCREEN_NONE];
5630   else if (fs_state == FULLSCREEN_WIDTH
5631            && maximized_width != (int)frameSize.width)
5632     [self setFSValue: FULLSCREEN_NONE];
5633   else if (fs_state == FULLSCREEN_HEIGHT
5634            && maximized_height != (int)frameSize.height)
5635     [self setFSValue: FULLSCREEN_NONE];
5636   if (fs_state == FULLSCREEN_NONE)
5637     maximized_width = maximized_height = -1;
5639   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5640                                          frameSize.width + gsextra);
5641   if (cols < MINWIDTH)
5642     cols = MINWIDTH;
5644   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5645                                            frameSize.height - extra);
5646   if (rows < MINHEIGHT)
5647     rows = MINHEIGHT;
5648 #ifdef NS_IMPL_COCOA
5649   {
5650     /* this sets window title to have size in it; the wm does this under GS */
5651     NSRect r = [[self window] frame];
5652     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5653       {
5654         if (old_title != 0)
5655           {
5656             xfree (old_title);
5657             old_title = 0;
5658           }
5659       }
5660     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5661       {
5662         char *size_title;
5663         NSWindow *window = [self window];
5664         if (old_title == 0)
5665           {
5666             char *t = strdup ([[[self window] title] UTF8String]);
5667             char *pos = strstr (t, "  â€”  ");
5668             if (pos)
5669               *pos = '\0';
5670             old_title = t;
5671           }
5672         size_title = xmalloc (strlen (old_title) + 40);
5673         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5674         [window setTitle: [NSString stringWithUTF8String: size_title]];
5675         [window display];
5676         xfree (size_title);
5677       }
5678   }
5679 #endif /* NS_IMPL_COCOA */
5680 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5682   return frameSize;
5686 - (void)windowDidResize: (NSNotification *)notification
5688   if (! [self fsIsNative])
5689     {
5690       NSWindow *theWindow = [notification object];
5691       /* We can get notification on the non-FS window when in
5692          fullscreen mode.  */
5693       if ([self window] != theWindow) return;
5694     }
5696 #ifdef NS_IMPL_GNUSTEP
5697   NSWindow *theWindow = [notification object];
5699    /* In GNUstep, at least currently, it's possible to get a didResize
5700       without getting a willResize.. therefore we need to act as if we got
5701       the willResize now */
5702   NSSize sz = [theWindow frame].size;
5703   sz = [self windowWillResize: theWindow toSize: sz];
5704 #endif /* NS_IMPL_GNUSTEP */
5706   NSTRACE (windowDidResize);
5707 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5709 if (cols > 0 && rows > 0)
5710     {
5711       [self updateFrameSize: YES];
5712     }
5714   ns_send_appdefined (-1);
5717 #ifdef NS_IMPL_COCOA
5718 - (void)viewDidEndLiveResize
5720   [super viewDidEndLiveResize];
5721   if (old_title != 0)
5722     {
5723       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
5724       xfree (old_title);
5725       old_title = 0;
5726     }
5727   maximizing_resize = NO;
5729 #endif /* NS_IMPL_COCOA */
5732 - (void)windowDidBecomeKey: (NSNotification *)notification
5733 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5735   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5736   struct frame *old_focus = dpyinfo->x_focus_frame;
5738   NSTRACE (windowDidBecomeKey);
5740   if (emacsframe != old_focus)
5741     dpyinfo->x_focus_frame = emacsframe;
5743   ns_frame_rehighlight (emacsframe);
5745   if (emacs_event)
5746     {
5747       emacs_event->kind = FOCUS_IN_EVENT;
5748       EV_TRAILER ((id)nil);
5749     }
5753 - (void)windowDidResignKey: (NSNotification *)notification
5754 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5756   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5757   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
5758   NSTRACE (windowDidResignKey);
5760   if (is_focus_frame)
5761     dpyinfo->x_focus_frame = 0;
5763   ns_frame_rehighlight (emacsframe);
5765   /* FIXME: for some reason needed on second and subsequent clicks away
5766             from sole-frame Emacs to get hollow box to show */
5767   if (!windowClosing && [[self window] isVisible] == YES)
5768     {
5769       x_update_cursor (emacsframe, 1);
5770       x_set_frame_alpha (emacsframe);
5771     }
5773   if (emacs_event && is_focus_frame)
5774     {
5775       [self deleteWorkingText];
5776       emacs_event->kind = FOCUS_OUT_EVENT;
5777       EV_TRAILER ((id)nil);
5778     }
5782 - (void)windowWillMiniaturize: sender
5784   NSTRACE (windowWillMiniaturize);
5788 - (BOOL)isFlipped
5790   return YES;
5794 - (BOOL)isOpaque
5796   return NO;
5800 - initFrameFromEmacs: (struct frame *)f
5802   NSRect r, wr;
5803   Lisp_Object tem;
5804   NSWindow *win;
5805   NSSize sz;
5806   NSColor *col;
5807   NSString *name;
5809   NSTRACE (initFrameFromEmacs);
5811   windowClosing = NO;
5812   processingCompose = NO;
5813   scrollbarsNeedingUpdate = 0;
5814   fs_state = FULLSCREEN_NONE;
5815   fs_before_fs = next_maximized = -1;
5816 #ifdef HAVE_NATIVE_FS
5817   fs_is_native = ns_use_native_fullscreen;
5818 #else
5819   fs_is_native = NO;
5820 #endif
5821   maximized_width = maximized_height = -1;
5822   nonfs_window = nil;
5824 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5826   ns_userRect = NSMakeRect (0, 0, 0, 0);
5827   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5828                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5829   [self initWithFrame: r];
5830   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5832   FRAME_NS_VIEW (f) = self;
5833   emacsframe = f;
5834 #ifdef NS_IMPL_COCOA
5835   old_title = 0;
5836   maximizing_resize = NO;
5837 #endif
5839   win = [[EmacsWindow alloc]
5840             initWithContentRect: r
5841                       styleMask: (NSResizableWindowMask |
5842 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5843                                   NSTitledWindowMask |
5844 #endif
5845                                   NSMiniaturizableWindowMask |
5846                                   NSClosableWindowMask)
5847                         backing: NSBackingStoreBuffered
5848                           defer: YES];
5850 #ifdef HAVE_NATIVE_FS
5851     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
5852 #endif
5854   wr = [win frame];
5855   bwidth = f->border_width = wr.size.width - r.size.width;
5856   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5858   [win setAcceptsMouseMovedEvents: YES];
5859   [win setDelegate: self];
5860   [win useOptimizedDrawing: YES];
5862   sz.width = FRAME_COLUMN_WIDTH (f);
5863   sz.height = FRAME_LINE_HEIGHT (f);
5864   [win setResizeIncrements: sz];
5866   [[win contentView] addSubview: self];
5868   if (ns_drag_types)
5869     [self registerForDraggedTypes: ns_drag_types];
5871   tem = f->name;
5872   name = [NSString stringWithUTF8String:
5873                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5874   [win setTitle: name];
5876   /* toolbar support */
5877   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5878                          [NSString stringWithFormat: @"Emacs Frame %d",
5879                                    ns_window_num]];
5880   [win setToolbar: toolbar];
5881   [toolbar setVisible: NO];
5882 #ifdef NS_IMPL_COCOA
5883   {
5884     NSButton *toggleButton;
5885   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5886   [toggleButton setTarget: self];
5887   [toggleButton setAction: @selector (toggleToolbar: )];
5888   }
5889 #endif
5890   FRAME_TOOLBAR_HEIGHT (f) = 0;
5892   tem = f->icon_name;
5893   if (!NILP (tem))
5894     [win setMiniwindowTitle:
5895            [NSString stringWithUTF8String: SSDATA (tem)]];
5897   {
5898     NSScreen *screen = [win screen];
5900     if (screen != 0)
5901       [win setFrameTopLeftPoint: NSMakePoint
5902            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5903             IN_BOUND (-SCREENMAX,
5904                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5905   }
5907   [win makeFirstResponder: self];
5909   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5910                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5911   [win setBackgroundColor: col];
5912   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
5913     [win setOpaque: NO];
5915   [self allocateGState];
5917   [NSApp registerServicesMenuSendTypes: ns_send_types
5918                            returnTypes: nil];
5920   ns_window_num++;
5921   return self;
5925 - (void)windowDidMove: sender
5927   NSWindow *win = [self window];
5928   NSRect r = [win frame];
5929   NSArray *screens = [NSScreen screens];
5930   NSScreen *screen = [screens objectAtIndex: 0];
5932   NSTRACE (windowDidMove);
5934   if (!emacsframe->output_data.ns)
5935     return;
5936   if (screen != nil)
5937     {
5938       emacsframe->left_pos = r.origin.x;
5939       emacsframe->top_pos =
5940         [screen frame].size.height - (r.origin.y + r.size.height);
5941     }
5945 /* Called AFTER method below, but before our windowWillResize call there leads
5946    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5947    location so set_window_size moves the frame. */
5948 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5950   emacsframe->output_data.ns->zooming = 1;
5951   return YES;
5955 /* Override to do something slightly nonstandard, but nice.  First click on
5956    zoom button will zoom vertically.  Second will zoom completely.  Third
5957    returns to original. */
5958 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5959                         defaultFrame:(NSRect)defaultFrame
5961   NSRect result = [sender frame];
5963   NSTRACE (windowWillUseStandardFrame);
5965   if (fs_before_fs != -1) /* Entering fullscreen */
5966       {
5967         result = defaultFrame;
5968       }
5969   else if (next_maximized == FULLSCREEN_HEIGHT
5970       || (next_maximized == -1
5971           && abs (defaultFrame.size.height - result.size.height)
5972           > FRAME_LINE_HEIGHT (emacsframe)))
5973     {
5974       /* first click */
5975       ns_userRect = result;
5976       maximized_height = result.size.height = defaultFrame.size.height;
5977       maximized_width = -1;
5978       result.origin.y = defaultFrame.origin.y;
5979       [self setFSValue: FULLSCREEN_HEIGHT];
5980 #ifdef NS_IMPL_COCOA
5981       maximizing_resize = YES;
5982 #endif
5983     }
5984   else if (next_maximized == FULLSCREEN_WIDTH)
5985     {
5986       ns_userRect = result;
5987       maximized_width = result.size.width = defaultFrame.size.width;
5988       maximized_height = -1;
5989       result.origin.x = defaultFrame.origin.x;
5990       [self setFSValue: FULLSCREEN_WIDTH];
5991     }
5992   else if (next_maximized == FULLSCREEN_MAXIMIZED
5993            || (next_maximized == -1
5994                && abs (defaultFrame.size.width - result.size.width)
5995                > FRAME_COLUMN_WIDTH (emacsframe)))
5996     {
5997       result = defaultFrame;  /* second click */
5998       maximized_width = result.size.width;
5999       maximized_height = result.size.height;
6000       [self setFSValue: FULLSCREEN_MAXIMIZED];
6001 #ifdef NS_IMPL_COCOA
6002       maximizing_resize = YES;
6003 #endif
6004     }
6005   else
6006     {
6007       /* restore */
6008       result = ns_userRect.size.height ? ns_userRect : result;
6009       ns_userRect = NSMakeRect (0, 0, 0, 0);
6010 #ifdef NS_IMPL_COCOA
6011       maximizing_resize = fs_state != FULLSCREEN_NONE;
6012 #endif
6013       [self setFSValue: FULLSCREEN_NONE];
6014       maximized_width = maximized_height = -1;
6015     }
6017   if (fs_before_fs == -1) next_maximized = -1;
6018   [self windowWillResize: sender toSize: result.size];
6019   return result;
6023 - (void)windowDidDeminiaturize: sender
6025   NSTRACE (windowDidDeminiaturize);
6026   if (!emacsframe->output_data.ns)
6027     return;
6029   SET_FRAME_ICONIFIED (emacsframe, 0);
6030   SET_FRAME_VISIBLE (emacsframe, 1);
6031   windows_or_buffers_changed++;
6033   if (emacs_event)
6034     {
6035       emacs_event->kind = DEICONIFY_EVENT;
6036       EV_TRAILER ((id)nil);
6037     }
6041 - (void)windowDidExpose: sender
6043   NSTRACE (windowDidExpose);
6044   if (!emacsframe->output_data.ns)
6045     return;
6047   SET_FRAME_VISIBLE (emacsframe, 1);
6048   SET_FRAME_GARBAGED (emacsframe);
6050   if (send_appdefined)
6051     ns_send_appdefined (-1);
6055 - (void)windowDidMiniaturize: sender
6057   NSTRACE (windowDidMiniaturize);
6058   if (!emacsframe->output_data.ns)
6059     return;
6061   SET_FRAME_ICONIFIED (emacsframe, 1);
6062   SET_FRAME_VISIBLE (emacsframe, 0);
6064   if (emacs_event)
6065     {
6066       emacs_event->kind = ICONIFY_EVENT;
6067       EV_TRAILER ((id)nil);
6068     }
6071 #ifdef HAVE_NATIVE_FS
6072 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6073       willUseFullScreenPresentationOptions:
6074   (NSApplicationPresentationOptions)proposedOptions
6076   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6078 #endif
6080 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6082   fs_before_fs = fs_state;
6085 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6087   [self setFSValue: FULLSCREEN_BOTH];
6088   if (! [self fsIsNative])
6089     {
6090       [self windowDidBecomeKey:notification];
6091       [nonfs_window orderOut:self];
6092     }
6093   else if (! FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6094     [toolbar setVisible:NO];
6097 - (void)windowWillExitFullScreen:(NSNotification *)notification
6099   if (next_maximized != -1)
6100     fs_before_fs = next_maximized;
6103 - (void)windowDidExitFullScreen:(NSNotification *)notification
6105   [self setFSValue: fs_before_fs];
6106   fs_before_fs = -1;
6107 #ifdef NS_IMPL_COCOA
6108   [self updateCollectionBehaviour];
6109 #endif
6110   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6111     {
6112       [toolbar setVisible:YES];
6113       update_frame_tool_bar (emacsframe);
6114       [self updateFrameSize:YES];
6115       [[self window] display];
6116     }
6117   else
6118     [toolbar setVisible:NO];
6120   if (next_maximized != -1)
6121     [[self window] performZoom:self];
6124 - (BOOL)fsIsNative
6126   return fs_is_native;
6129 - (BOOL)isFullscreen
6131   if (! fs_is_native) return nonfs_window != nil;
6132 #ifdef HAVE_NATIVE_FS
6133   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6134 #else
6135   return NO;
6136 #endif
6139 #ifdef HAVE_NATIVE_FS
6140 - (void)updateCollectionBehaviour
6142   if (! [self isFullscreen])
6143     {
6144       NSWindow *win = [self window];
6145       NSWindowCollectionBehavior b = [win collectionBehavior];
6146       if (ns_use_native_fullscreen)
6147         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6148       else
6149         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6151       [win setCollectionBehavior: b];
6152       fs_is_native = ns_use_native_fullscreen;
6153     }
6155 #endif
6157 - (void)toggleFullScreen: (id)sender
6159   NSWindow *w, *fw;
6160   BOOL onFirstScreen;
6161   struct frame *f;
6162   NSSize sz;
6163   NSRect r, wr;
6164   NSColor *col;
6166   if (fs_is_native)
6167     {
6168 #ifdef NS_IMPL_COCOA
6169       [[self window] toggleFullScreen:sender];
6170 #endif
6171       return;
6172     }
6174   w = [self window];
6175   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6176   f = emacsframe;
6177   wr = [w frame];
6178   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6179                                  (FRAME_DEFAULT_FACE (f)),
6180                                  f);
6182   sz.width = FRAME_COLUMN_WIDTH (f);
6183   sz.height = FRAME_LINE_HEIGHT (f);
6185   if (fs_state != FULLSCREEN_BOTH)
6186     {
6187       /* Hide dock and menubar if we are on the primary screen.  */
6188       if (onFirstScreen)
6189         {
6190 #if defined (NS_IMPL_COCOA) && \
6191   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6192           NSApplicationPresentationOptions options
6193             = NSApplicationPresentationAutoHideDock
6194             | NSApplicationPresentationAutoHideMenuBar;
6196           [NSApp setPresentationOptions: options];
6197 #else
6198           [NSMenu setMenuBarVisible:NO];
6199 #endif
6200         }
6202       fw = [[EmacsFSWindow alloc]
6203                        initWithContentRect:[w contentRectForFrameRect:wr]
6204                                  styleMask:NSBorderlessWindowMask
6205                                    backing:NSBackingStoreBuffered
6206                                      defer:YES
6207                                     screen:[w screen]];
6209       [fw setContentView:[w contentView]];
6210       [fw setTitle:[w title]];
6211       [fw setDelegate:self];
6212       [fw setAcceptsMouseMovedEvents: YES];
6213       [fw useOptimizedDrawing: YES];
6214       [fw setResizeIncrements: sz];
6215       [fw setBackgroundColor: col];
6216       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6217         [fw setOpaque: NO];
6219       f->border_width = 0;
6220       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6221       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6222       FRAME_TOOLBAR_HEIGHT (f) = 0;
6224       nonfs_window = w;
6226       [self windowWillEnterFullScreen:nil];
6227       [fw makeKeyAndOrderFront:NSApp];
6228       [fw makeFirstResponder:self];
6229       [w orderOut:self];
6230       r = [fw frameRectForContentRect:[[fw screen] frame]];
6231       [fw setFrame: r display:YES animate:YES];
6232       [self windowDidEnterFullScreen:nil];
6233       [fw display];
6234     }
6235   else
6236     {
6237       fw = w;
6238       w = nonfs_window;
6239       nonfs_window = nil;
6241       if (onFirstScreen)
6242         {
6243 #if defined (NS_IMPL_COCOA) && \
6244   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6245           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6246 #else
6247           [NSMenu setMenuBarVisible:YES];
6248 #endif
6249         }
6251       [w setContentView:[fw contentView]];
6252       [w setResizeIncrements: sz];
6253       [w setBackgroundColor: col];
6254       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6255         [w setOpaque: NO];
6257       f->border_width = bwidth;
6258       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6259       if (FRAME_EXTERNAL_TOOL_BAR (f))
6260         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6262       [self windowWillExitFullScreen:nil];
6263       [fw setFrame: [w frame] display:YES animate:YES];
6264       [fw close];
6265       [w makeKeyAndOrderFront:NSApp];
6266       [self windowDidExitFullScreen:nil];
6267       [self updateFrameSize:YES];
6268     }
6271 - (void)handleFS
6273   if (fs_state != emacsframe->want_fullscreen)
6274     {
6275       if (fs_state == FULLSCREEN_BOTH)
6276         {
6277           [self toggleFullScreen:self];
6278         }
6280       switch (emacsframe->want_fullscreen)
6281         {
6282         case FULLSCREEN_BOTH:
6283           [self toggleFullScreen:self];
6284           break;
6285         case FULLSCREEN_WIDTH:
6286           next_maximized = FULLSCREEN_WIDTH;
6287           if (fs_state != FULLSCREEN_BOTH)
6288             [[self window] performZoom:self];
6289           break;
6290         case FULLSCREEN_HEIGHT:
6291           next_maximized = FULLSCREEN_HEIGHT;
6292           if (fs_state != FULLSCREEN_BOTH)
6293             [[self window] performZoom:self];
6294           break;
6295         case FULLSCREEN_MAXIMIZED:
6296           next_maximized = FULLSCREEN_MAXIMIZED;
6297           if (fs_state != FULLSCREEN_BOTH)
6298             [[self window] performZoom:self];
6299           break;
6300         case FULLSCREEN_NONE:
6301           if (fs_state != FULLSCREEN_BOTH)
6302             {
6303               next_maximized = FULLSCREEN_NONE;
6304               [[self window] performZoom:self];
6305             }
6306           break;
6307         }
6309       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6310     }
6314 - (void) setFSValue: (int)value
6316   Lisp_Object lval = Qnil;
6317   switch (value)
6318     {
6319     case FULLSCREEN_BOTH:
6320       lval = Qfullboth;
6321       break;
6322     case FULLSCREEN_WIDTH:
6323       lval = Qfullwidth;
6324       break;
6325     case FULLSCREEN_HEIGHT:
6326       lval = Qfullheight;
6327       break;
6328     case FULLSCREEN_MAXIMIZED:
6329       lval = Qmaximized;
6330       break;
6331     }
6332   store_frame_param (emacsframe, Qfullscreen, lval);
6333   fs_state = value;
6336 - (void)mouseEntered: (NSEvent *)theEvent
6338   NSTRACE (mouseEntered);
6339   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6343 - (void)mouseExited: (NSEvent *)theEvent
6345   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6347   NSTRACE (mouseExited);
6349   if (!hlinfo)
6350     return;
6352   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6354   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6355     {
6356       clear_mouse_face (hlinfo);
6357       hlinfo->mouse_face_mouse_frame = 0;
6358     }
6362 - menuDown: sender
6364   NSTRACE (menuDown);
6365   if (context_menu_value == -1)
6366     context_menu_value = [sender tag];
6367   else
6368     {
6369       NSInteger tag = [sender tag];
6370       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6371                                     emacsframe->menu_bar_vector,
6372                                     (void *)tag);
6373     }
6375   ns_send_appdefined (-1);
6376   return self;
6380 - (EmacsToolbar *)toolbar
6382   return toolbar;
6386 /* this gets called on toolbar button click */
6387 - toolbarClicked: (id)item
6389   NSEvent *theEvent;
6390   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6392   NSTRACE (toolbarClicked);
6394   if (!emacs_event)
6395     return self;
6397   /* send first event (for some reason two needed) */
6398   theEvent = [[self window] currentEvent];
6399   emacs_event->kind = TOOL_BAR_EVENT;
6400   XSETFRAME (emacs_event->arg, emacsframe);
6401   EV_TRAILER (theEvent);
6403   emacs_event->kind = TOOL_BAR_EVENT;
6404 /*   XSETINT (emacs_event->code, 0); */
6405   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6406                            idx + TOOL_BAR_ITEM_KEY);
6407   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6408   EV_TRAILER (theEvent);
6409   return self;
6413 - toggleToolbar: (id)sender
6415   if (!emacs_event)
6416     return self;
6418   emacs_event->kind = NS_NONKEY_EVENT;
6419   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6420   EV_TRAILER ((id)nil);
6421   return self;
6425 - (void)drawRect: (NSRect)rect
6427   int x = NSMinX (rect), y = NSMinY (rect);
6428   int width = NSWidth (rect), height = NSHeight (rect);
6430   NSTRACE (drawRect);
6432   if (!emacsframe || !emacsframe->output_data.ns)
6433     return;
6435   ns_clear_frame_area (emacsframe, x, y, width, height);
6436   expose_frame (emacsframe, x, y, width, height);
6438   /*
6439     drawRect: may be called (at least in OS X 10.5) for invisible
6440     views as well for some reason.  Thus, do not infer visibility
6441     here.
6443     emacsframe->async_visible = 1;
6444     emacsframe->async_iconified = 0;
6445   */
6449 /* NSDraggingDestination protocol methods.  Actually this is not really a
6450    protocol, but a category of Object.  O well...  */
6452 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6454   NSTRACE (draggingEntered);
6455   return NSDragOperationGeneric;
6459 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6461   return YES;
6465 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6467   id pb;
6468   int x, y;
6469   NSString *type;
6470   NSEvent *theEvent = [[self window] currentEvent];
6471   NSPoint position;
6473   NSTRACE (performDragOperation);
6475   if (!emacs_event)
6476     return NO;
6478   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6479   x = lrint (position.x);  y = lrint (position.y);
6481   pb = [sender draggingPasteboard];
6482   type = [pb availableTypeFromArray: ns_drag_types];
6483   if (type == 0)
6484     {
6485       return NO;
6486     }
6487   else if ([type isEqualToString: NSFilenamesPboardType])
6488     {
6489       NSArray *files;
6490       NSEnumerator *fenum;
6491       NSString *file;
6493       if (!(files = [pb propertyListForType: type]))
6494         return NO;
6496       fenum = [files objectEnumerator];
6497       while ( (file = [fenum nextObject]) )
6498         {
6499           emacs_event->kind = NS_NONKEY_EVENT;
6500           emacs_event->code = KEY_NS_DRAG_FILE;
6501           XSETINT (emacs_event->x, x);
6502           XSETINT (emacs_event->y, y);
6503           ns_input_file = append2 (ns_input_file,
6504                                    build_string ([file UTF8String]));
6505           emacs_event->modifiers = EV_MODIFIERS (theEvent);
6506           EV_TRAILER (theEvent);
6507         }
6508       return YES;
6509     }
6510   else if ([type isEqualToString: NSURLPboardType])
6511     {
6512       NSString *file;
6513       NSURL *fileURL;
6515       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6516           [fileURL isFileURL] == NO)
6517         return NO;
6519       file = [fileURL path];
6520       emacs_event->kind = NS_NONKEY_EVENT;
6521       emacs_event->code = KEY_NS_DRAG_FILE;
6522       XSETINT (emacs_event->x, x);
6523       XSETINT (emacs_event->y, y);
6524       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6525       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6526       EV_TRAILER (theEvent);
6527       return YES;
6528     }
6529   else if ([type isEqualToString: NSStringPboardType]
6530            || [type isEqualToString: NSTabularTextPboardType])
6531     {
6532       NSString *data;
6534       if (! (data = [pb stringForType: type]))
6535         return NO;
6537       emacs_event->kind = NS_NONKEY_EVENT;
6538       emacs_event->code = KEY_NS_DRAG_TEXT;
6539       XSETINT (emacs_event->x, x);
6540       XSETINT (emacs_event->y, y);
6541       ns_input_text = build_string ([data UTF8String]);
6542       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6543       EV_TRAILER (theEvent);
6544       return YES;
6545     }
6546   else if ([type isEqualToString: NSColorPboardType])
6547     {
6548       NSColor *c = [NSColor colorFromPasteboard: pb];
6549       emacs_event->kind = NS_NONKEY_EVENT;
6550       emacs_event->code = KEY_NS_DRAG_COLOR;
6551       XSETINT (emacs_event->x, x);
6552       XSETINT (emacs_event->y, y);
6553       ns_input_color = ns_color_to_lisp (c);
6554       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6555       EV_TRAILER (theEvent);
6556       return YES;
6557     }
6558   else if ([type isEqualToString: NSFontPboardType])
6559     {
6560       /* impl based on GNUstep NSTextView.m */
6561       NSData *data = [pb dataForType: NSFontPboardType];
6562       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6563       NSFont *font = [dict objectForKey: NSFontAttributeName];
6564       char fontSize[10];
6566       if (font == nil)
6567         return NO;
6569       emacs_event->kind = NS_NONKEY_EVENT;
6570       emacs_event->code = KEY_NS_CHANGE_FONT;
6571       XSETINT (emacs_event->x, x);
6572       XSETINT (emacs_event->y, y);
6573       ns_input_font = build_string ([[font fontName] UTF8String]);
6574       snprintf (fontSize, 10, "%f", [font pointSize]);
6575       ns_input_fontsize = build_string (fontSize);
6576       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6577       EV_TRAILER (theEvent);
6578       return YES;
6579     }
6580   else
6581     {
6582       error ("Invalid data type in dragging pasteboard.");
6583       return NO;
6584     }
6588 - (id) validRequestorForSendType: (NSString *)typeSent
6589                       returnType: (NSString *)typeReturned
6591   NSTRACE (validRequestorForSendType);
6592   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6593       && typeReturned == nil)
6594     {
6595       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6596         return self;
6597     }
6599   return [super validRequestorForSendType: typeSent
6600                                returnType: typeReturned];
6604 /* The next two methods are part of NSServicesRequests informal protocol,
6605    supposedly called when a services menu item is chosen from this app.
6606    But this should not happen because we override the services menu with our
6607    own entries which call ns-perform-service.
6608    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6609    So let's at least stub them out until further investigation can be done. */
6611 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6613   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6614      be written into the buffer in place of the existing selection..
6615      ordinary service calls go through functions defined in ns-win.el */
6616   return NO;
6619 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6621   NSArray *typesDeclared;
6622   Lisp_Object val;
6624   /* We only support NSStringPboardType */
6625   if ([types containsObject:NSStringPboardType] == NO) {
6626     return NO;
6627   }
6629   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6630   if (CONSP (val) && SYMBOLP (XCAR (val)))
6631     {
6632       val = XCDR (val);
6633       if (CONSP (val) && NILP (XCDR (val)))
6634         val = XCAR (val);
6635     }
6636   if (! STRINGP (val))
6637     return NO;
6639   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6640   [pb declareTypes:typesDeclared owner:nil];
6641   ns_string_to_pasteboard (pb, val);
6642   return YES;
6646 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6647    (gives a miniaturized version of the window); currently we use the latter for
6648    frames whose active buffer doesn't correspond to any file
6649    (e.g., '*scratch*') */
6650 - setMiniwindowImage: (BOOL) setMini
6652   id image = [[self window] miniwindowImage];
6653   NSTRACE (setMiniwindowImage);
6655   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6656      about "AppleDockIconEnabled" notwithstanding, however the set message
6657      below has its effect nonetheless. */
6658   if (image != emacsframe->output_data.ns->miniimage)
6659     {
6660       if (image && [image isKindOfClass: [EmacsImage class]])
6661         [image release];
6662       [[self window] setMiniwindowImage:
6663                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6664     }
6666   return self;
6670 - (void) setRows: (int) r andColumns: (int) c
6672   rows = r;
6673   cols = c;
6676 @end  /* EmacsView */
6680 /* ==========================================================================
6682     EmacsWindow implementation
6684    ========================================================================== */
6686 @implementation EmacsWindow
6688 #ifdef NS_IMPL_COCOA
6689 - (id)accessibilityAttributeValue:(NSString *)attribute
6691   Lisp_Object str = Qnil;
6692   struct frame *f = SELECTED_FRAME ();
6693   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
6695   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6696     return NSAccessibilityTextFieldRole;
6698   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6699       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6700     {
6701       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6702     }
6703   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6704     {
6705       if (! NILP (BVAR (curbuf, mark_active)))
6706           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6708       if (NILP (str))
6709         {
6710           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6711           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6712           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6714           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6715             str = make_uninit_multibyte_string (range, byte_range);
6716           else
6717             str = make_uninit_string (range);
6718           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6719              Is this a problem?  */
6720           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6721         }
6722     }
6725   if (! NILP (str))
6726     {
6727       if (CONSP (str) && SYMBOLP (XCAR (str)))
6728         {
6729           str = XCDR (str);
6730           if (CONSP (str) && NILP (XCDR (str)))
6731             str = XCAR (str);
6732         }
6733       if (STRINGP (str))
6734         {
6735           const char *utfStr = SSDATA (str);
6736           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6737           return nsStr;
6738         }
6739     }
6741   return [super accessibilityAttributeValue:attribute];
6743 #endif /* NS_IMPL_COCOA */
6745 /* If we have multiple monitors, one above the other, we don't want to
6746    restrict the height to just one monitor.  So we override this.  */
6747 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6749   /* When making the frame visible for the first time or if there is just
6750      one screen, we want to constrain.  Other times not.  */
6751   NSUInteger nr_screens = [[NSScreen screens] count];
6752   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6753   NSTRACE (constrainFrameRect);
6755   if (nr_screens == 1)
6756     {
6757       NSRect r = [super constrainFrameRect:frameRect toScreen:screen];
6758       return r;
6759     }
6761   if (f->output_data.ns->dont_constrain
6762       || ns_menu_bar_should_be_hidden ())
6763     return frameRect;
6765   f->output_data.ns->dont_constrain = 1;
6766   return [super constrainFrameRect:frameRect toScreen:screen];
6769 @end /* EmacsWindow */
6772 @implementation EmacsFSWindow
6774 - (BOOL)canBecomeKeyWindow
6776   return YES;
6779 - (BOOL)canBecomeMainWindow
6781   return YES;
6784 @end
6786 /* ==========================================================================
6788     EmacsScroller implementation
6790    ========================================================================== */
6793 @implementation EmacsScroller
6795 /* for repeat button push */
6796 #define SCROLL_BAR_FIRST_DELAY 0.5
6797 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6799 + (CGFloat) scrollerWidth
6801   /* TODO: if we want to allow variable widths, this is the place to do it,
6802            however neither GNUstep nor Cocoa support it very well */
6803   return [NSScroller scrollerWidth];
6807 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6809   NSTRACE (EmacsScroller_initFrame);
6811   r.size.width = [EmacsScroller scrollerWidth];
6812   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6813   [self setContinuous: YES];
6814   [self setEnabled: YES];
6816   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6817      locked against the top and bottom edges, and right edge on OS X, where
6818      scrollers are on right. */
6819 #ifdef NS_IMPL_GNUSTEP
6820   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6821 #else
6822   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6823 #endif
6825   win = nwin;
6826   condemned = NO;
6827   pixel_height = NSHeight (r);
6828   if (pixel_height == 0) pixel_height = 1;
6829   min_portion = 20 / pixel_height;
6831   frame = XFRAME (XWINDOW (win)->frame);
6832   if (FRAME_LIVE_P (frame))
6833     {
6834       int i;
6835       EmacsView *view = FRAME_NS_VIEW (frame);
6836       NSView *sview = [[view window] contentView];
6837       NSArray *subs = [sview subviews];
6839       /* disable optimization stopping redraw of other scrollbars */
6840       view->scrollbarsNeedingUpdate = 0;
6841       for (i =[subs count]-1; i >= 0; i--)
6842         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6843           view->scrollbarsNeedingUpdate++;
6844       [sview addSubview: self];
6845     }
6847 /*  [self setFrame: r]; */
6849   return self;
6853 - (void)setFrame: (NSRect)newRect
6855   NSTRACE (EmacsScroller_setFrame);
6856 /*  block_input (); */
6857   pixel_height = NSHeight (newRect);
6858   if (pixel_height == 0) pixel_height = 1;
6859   min_portion = 20 / pixel_height;
6860   [super setFrame: newRect];
6861   [self display];
6862 /*  unblock_input (); */
6866 - (void)dealloc
6868   NSTRACE (EmacsScroller_dealloc);
6869   if (!NILP (win))
6870     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
6871   [super dealloc];
6875 - condemn
6877   NSTRACE (condemn);
6878   condemned =YES;
6879   return self;
6883 - reprieve
6885   NSTRACE (reprieve);
6886   condemned =NO;
6887   return self;
6891 - judge
6893   NSTRACE (judge);
6894   if (condemned)
6895     {
6896       EmacsView *view;
6897       block_input ();
6898       /* ensure other scrollbar updates after deletion */
6899       view = (EmacsView *)FRAME_NS_VIEW (frame);
6900       if (view != nil)
6901         view->scrollbarsNeedingUpdate++;
6902       [self removeFromSuperview];
6903       [self release];
6904       unblock_input ();
6905     }
6906   return self;
6910 - (void)resetCursorRects
6912   NSRect visible = [self visibleRect];
6913   NSTRACE (resetCursorRects);
6915   if (!NSIsEmptyRect (visible))
6916     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6917   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6921 - (int) checkSamePosition: (int) position portion: (int) portion
6922                     whole: (int) whole
6924   return em_position ==position && em_portion ==portion && em_whole ==whole
6925     && portion != whole; /* needed for resize empty buf */
6929 - setPosition: (int)position portion: (int)portion whole: (int)whole
6931   NSTRACE (setPosition);
6933   em_position = position;
6934   em_portion = portion;
6935   em_whole = whole;
6937   if (portion >= whole)
6938     {
6939 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6940       [self setKnobProportion: 1.0];
6941       [self setDoubleValue: 1.0];
6942 #else
6943       [self setFloatValue: 0.0 knobProportion: 1.0];
6944 #endif
6945     }
6946   else
6947     {
6948       float pos;
6949       CGFloat por;
6950       portion = max ((float)whole*min_portion/pixel_height, portion);
6951       pos = (float)position / (whole - portion);
6952       por = (CGFloat)portion/whole;
6953 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6954       [self setKnobProportion: por];
6955       [self setDoubleValue: pos];
6956 #else
6957       [self setFloatValue: pos knobProportion: por];
6958 #endif
6959     }
6961   /* Events may come here even if the event loop is not running.
6962      If we don't enter the event loop, the scroll bar will not update.
6963      So send SIGIO to ourselves.  */
6964   if (apploopnr == 0) raise (SIGIO);
6966   return self;
6969 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6970      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6971 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6972                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6974   *part = last_hit_part;
6975   *window = win;
6976   XSETINT (*y, pixel_height);
6977   if ([self floatValue] > 0.999F)
6978     XSETINT (*x, pixel_height);
6979   else
6980     XSETINT (*x, pixel_height * [self floatValue]);
6984 /* set up emacs_event */
6985 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6987   if (!emacs_event)
6988     return;
6990   emacs_event->part = last_hit_part;
6991   emacs_event->code = 0;
6992   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6993   emacs_event->frame_or_window = win;
6994   emacs_event->timestamp = EV_TIMESTAMP (e);
6995   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6996   emacs_event->arg = Qnil;
6997   XSETINT (emacs_event->x, loc * pixel_height);
6998   XSETINT (emacs_event->y, pixel_height-20);
7000   if (q_event_ptr)
7001     {
7002       n_emacs_events_pending++;
7003       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7004     }
7005   else
7006     hold_event (emacs_event);
7007   EVENT_INIT (*emacs_event);
7008   ns_send_appdefined (-1);
7012 /* called manually thru timer to implement repeated button action w/hold-down */
7013 - repeatScroll: (NSTimer *)scrollEntry
7015   NSEvent *e = [[self window] currentEvent];
7016   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
7017   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7019   /* clear timer if need be */
7020   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7021     {
7022         [scroll_repeat_entry invalidate];
7023         [scroll_repeat_entry release];
7024         scroll_repeat_entry = nil;
7026         if (inKnob)
7027           return self;
7029         scroll_repeat_entry
7030           = [[NSTimer scheduledTimerWithTimeInterval:
7031                         SCROLL_BAR_CONTINUOUS_DELAY
7032                                             target: self
7033                                           selector: @selector (repeatScroll:)
7034                                           userInfo: 0
7035                                            repeats: YES]
7036               retain];
7037     }
7039   [self sendScrollEventAtLoc: 0 fromEvent: e];
7040   return self;
7044 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
7045    mouseDragged events without going into a modal loop. */
7046 - (void)mouseDown: (NSEvent *)e
7048   NSRect sr, kr;
7049   /* hitPart is only updated AFTER event is passed on */
7050   NSScrollerPart part = [self testPart: [e locationInWindow]];
7051   CGFloat inc = 0.0, loc, kloc, pos;
7052   int edge = 0;
7054   NSTRACE (EmacsScroller_mouseDown);
7056   switch (part)
7057     {
7058     case NSScrollerDecrementPage:
7059         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7060     case NSScrollerIncrementPage:
7061         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7062     case NSScrollerDecrementLine:
7063       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7064     case NSScrollerIncrementLine:
7065       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7066     case NSScrollerKnob:
7067       last_hit_part = scroll_bar_handle; break;
7068     case NSScrollerKnobSlot:  /* GNUstep-only */
7069       last_hit_part = scroll_bar_move_ratio; break;
7070     default:  /* NSScrollerNoPart? */
7071       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7072                (long) part);
7073       return;
7074     }
7076   if (inc != 0.0)
7077     {
7078       pos = 0;      /* ignored */
7080       /* set a timer to repeat, as we can't let superclass do this modally */
7081       scroll_repeat_entry
7082         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7083                                             target: self
7084                                           selector: @selector (repeatScroll:)
7085                                           userInfo: 0
7086                                            repeats: YES]
7087             retain];
7088     }
7089   else
7090     {
7091       /* handle, or on GNUstep possibly slot */
7092       NSEvent *fake_event;
7094       /* compute float loc in slot and mouse offset on knob */
7095       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7096                       toView: nil];
7097       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7098       if (loc <= 0.0)
7099         {
7100           loc = 0.0;
7101           edge = -1;
7102         }
7103       else if (loc >= NSHeight (sr))
7104         {
7105           loc = NSHeight (sr);
7106           edge = 1;
7107         }
7109       if (edge)
7110         kloc = 0.5 * edge;
7111       else
7112         {
7113           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7114                           toView: nil];
7115           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7116         }
7117       last_mouse_offset = kloc;
7119       /* if knob, tell emacs a location offset by knob pos
7120          (to indicate top of handle) */
7121       if (part == NSScrollerKnob)
7122           pos = (loc - last_mouse_offset) / NSHeight (sr);
7123       else
7124         /* else this is a slot click on GNUstep: go straight there */
7125         pos = loc / NSHeight (sr);
7127       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7128       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7129                                       location: [e locationInWindow]
7130                                  modifierFlags: [e modifierFlags]
7131                                      timestamp: [e timestamp]
7132                                   windowNumber: [e windowNumber]
7133                                        context: [e context]
7134                                    eventNumber: [e eventNumber]
7135                                     clickCount: [e clickCount]
7136                                       pressure: [e pressure]];
7137       [super mouseUp: fake_event];
7138     }
7140   if (part != NSScrollerKnob)
7141     [self sendScrollEventAtLoc: pos fromEvent: e];
7145 /* Called as we manually track scroller drags, rather than superclass. */
7146 - (void)mouseDragged: (NSEvent *)e
7148     NSRect sr;
7149     double loc, pos;
7151     NSTRACE (EmacsScroller_mouseDragged);
7153       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7154                       toView: nil];
7155       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7157       if (loc <= 0.0)
7158         {
7159           loc = 0.0;
7160         }
7161       else if (loc >= NSHeight (sr) + last_mouse_offset)
7162         {
7163           loc = NSHeight (sr) + last_mouse_offset;
7164         }
7166       pos = (loc - last_mouse_offset) / NSHeight (sr);
7167       [self sendScrollEventAtLoc: pos fromEvent: e];
7171 - (void)mouseUp: (NSEvent *)e
7173   if (scroll_repeat_entry)
7174     {
7175       [scroll_repeat_entry invalidate];
7176       [scroll_repeat_entry release];
7177       scroll_repeat_entry = nil;
7178     }
7179   last_hit_part = 0;
7183 /* treat scrollwheel events in the bar as though they were in the main window */
7184 - (void) scrollWheel: (NSEvent *)theEvent
7186   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7187   [view mouseDown: theEvent];
7190 @end  /* EmacsScroller */
7193 #ifdef NS_IMPL_GNUSTEP
7194 /* Dummy class to get rid of startup warnings.  */
7195 @implementation EmacsDocument
7197 @end
7198 #endif
7201 /* ==========================================================================
7203    Font-related functions; these used to be in nsfaces.m
7205    ========================================================================== */
7208 Lisp_Object
7209 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7211   struct font *font = XFONT_OBJECT (font_object);
7213   if (fontset < 0)
7214     fontset = fontset_from_font (font_object);
7215   FRAME_FONTSET (f) = fontset;
7217   if (FRAME_FONT (f) == font)
7218     /* This font is already set in frame F.  There's nothing more to
7219        do.  */
7220     return font_object;
7222   FRAME_FONT (f) = font;
7224   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7225   FRAME_COLUMN_WIDTH (f) = font->average_width;
7226   FRAME_LINE_HEIGHT (f) = font->height;
7228   compute_fringe_widths (f, 1);
7230   /* Compute the scroll bar width in character columns.  */
7231   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7232     {
7233       int wid = FRAME_COLUMN_WIDTH (f);
7234       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7235         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7236     }
7237   else
7238     {
7239       int wid = FRAME_COLUMN_WIDTH (f);
7240       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7241     }
7243   /* Now make the frame display the given font.  */
7244   if (FRAME_NS_WINDOW (f) != 0)
7245         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
7247   return font_object;
7251 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7252 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7253          in 1.43. */
7255 const char *
7256 ns_xlfd_to_fontname (const char *xlfd)
7257 /* --------------------------------------------------------------------------
7258     Convert an X font name (XLFD) to an NS font name.
7259     Only family is used.
7260     The string returned is temporarily allocated.
7261    -------------------------------------------------------------------------- */
7263   char *name = xmalloc (180);
7264   int i, len;
7265   const char *ret;
7267   if (!strncmp (xlfd, "--", 2))
7268     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7269   else
7270     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7272   /* stopgap for malformed XLFD input */
7273   if (strlen (name) == 0)
7274     strcpy (name, "Monaco");
7276   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7277      also uppercase after '-' or ' ' */
7278   name[0] = c_toupper (name[0]);
7279   for (len =strlen (name), i =0; i<len; i++)
7280     {
7281       if (name[i] == '$')
7282         {
7283           name[i] = '-';
7284           if (i+1<len)
7285             name[i+1] = c_toupper (name[i+1]);
7286         }
7287       else if (name[i] == '_')
7288         {
7289           name[i] = ' ';
7290           if (i+1<len)
7291             name[i+1] = c_toupper (name[i+1]);
7292         }
7293     }
7294 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7295   ret = [[NSString stringWithUTF8String: name] UTF8String];
7296   xfree (name);
7297   return ret;
7301 void
7302 syms_of_nsterm (void)
7304   NSTRACE (syms_of_nsterm);
7306   ns_antialias_threshold = 10.0;
7308   /* from 23+ we need to tell emacs what modifiers there are.. */
7309   DEFSYM (Qmodifier_value, "modifier-value");
7310   DEFSYM (Qalt, "alt");
7311   DEFSYM (Qhyper, "hyper");
7312   DEFSYM (Qmeta, "meta");
7313   DEFSYM (Qsuper, "super");
7314   DEFSYM (Qcontrol, "control");
7315   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7317   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7318   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7319   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7320   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7321   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7323   DEFVAR_LISP ("ns-input-file", ns_input_file,
7324               "The file specified in the last NS event.");
7325   ns_input_file =Qnil;
7327   DEFVAR_LISP ("ns-input-text", ns_input_text,
7328               "The data received in the last NS text drag event.");
7329   ns_input_text =Qnil;
7331   DEFVAR_LISP ("ns-working-text", ns_working_text,
7332               "String for visualizing working composition sequence.");
7333   ns_working_text =Qnil;
7335   DEFVAR_LISP ("ns-input-font", ns_input_font,
7336               "The font specified in the last NS event.");
7337   ns_input_font =Qnil;
7339   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7340               "The fontsize specified in the last NS event.");
7341   ns_input_fontsize =Qnil;
7343   DEFVAR_LISP ("ns-input-line", ns_input_line,
7344                "The line specified in the last NS event.");
7345   ns_input_line =Qnil;
7347   DEFVAR_LISP ("ns-input-color", ns_input_color,
7348                "The color specified in the last NS event.");
7349   ns_input_color =Qnil;
7351   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7352                "The service name specified in the last NS event.");
7353   ns_input_spi_name =Qnil;
7355   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7356                "The service argument specified in the last NS event.");
7357   ns_input_spi_arg =Qnil;
7359   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7360                "This variable describes the behavior of the alternate or option key.\n\
7361 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7362 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7363 at all, allowing it to be used at a lower level for accented character entry.");
7364   ns_alternate_modifier = Qmeta;
7366   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7367                "This variable describes the behavior of the right alternate or option key.\n\
7368 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7369 Set to left means be the same key as `ns-alternate-modifier'.\n\
7370 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7371 at all, allowing it to be used at a lower level for accented character entry.");
7372   ns_right_alternate_modifier = Qleft;
7374   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7375                "This variable describes the behavior of the command key.\n\
7376 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7377   ns_command_modifier = Qsuper;
7379   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7380                "This variable describes the behavior of the right command key.\n\
7381 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7382 Set to left means be the same key as `ns-command-modifier'.\n\
7383 Set to none means that the command / option key is not interpreted by Emacs\n\
7384 at all, allowing it to be used at a lower level for accented character entry.");
7385   ns_right_command_modifier = Qleft;
7387   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7388                "This variable describes the behavior of the control key.\n\
7389 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7390   ns_control_modifier = Qcontrol;
7392   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7393                "This variable describes the behavior of the right control key.\n\
7394 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7395 Set to left means be the same key as `ns-control-modifier'.\n\
7396 Set to none means that the control / option key is not interpreted by Emacs\n\
7397 at all, allowing it to be used at a lower level for accented character entry.");
7398   ns_right_control_modifier = Qleft;
7400   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7401                "This variable describes the behavior of the function key (on laptops).\n\
7402 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7403 Set to none means that the function key is not interpreted by Emacs at all,\n\
7404 allowing it to be used at a lower level for accented character entry.");
7405   ns_function_modifier = Qnone;
7407   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7408                "Non-nil (the default) means to render text antialiased.");
7409   ns_antialias_text = Qt;
7411   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7412                "Whether to confirm application quit using dialog.");
7413   ns_confirm_quit = Qnil;
7415   staticpro (&ns_display_name_list);
7416   ns_display_name_list = Qnil;
7418   staticpro (&last_mouse_motion_frame);
7419   last_mouse_motion_frame = Qnil;
7421   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7422                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7423 Only works on OSX 10.6 or later.  */);
7424   ns_auto_hide_menu_bar = Qnil;
7426   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7427      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7428 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7429 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7430 Default is t for OSX >= 10.7, nil otherwise. */);
7431 #ifdef HAVE_NATIVE_FS
7432   ns_use_native_fullscreen = YES;
7433 #else
7434   ns_use_native_fullscreen = NO;
7435 #endif
7436   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7438   /* TODO: move to common code */
7439   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7440                doc: /* Which toolkit scroll bars Emacs uses, if any.
7441 A value of nil means Emacs doesn't use toolkit scroll bars.
7442 With the X Window system, the value is a symbol describing the
7443 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7444 With MS Windows or Nextstep, the value is t.  */);
7445   Vx_toolkit_scroll_bars = Qt;
7447   DEFVAR_BOOL ("x-use-underline-position-properties",
7448                x_use_underline_position_properties,
7449      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7450 A value of nil means ignore them.  If you encounter fonts with bogus
7451 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7452 to 4.1, set this to nil. */);
7453   x_use_underline_position_properties = 0;
7455   DEFVAR_BOOL ("x-underline-at-descent-line",
7456                x_underline_at_descent_line,
7457      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7458 A value of nil means to draw the underline according to the value of the
7459 variable `x-use-underline-position-properties', which is usually at the
7460 baseline level.  The default value is nil.  */);
7461   x_underline_at_descent_line = 0;
7463   /* Tell emacs about this window system. */
7464   Fprovide (intern ("ns"), Qnil);