* progmodes/gud.el (gud-find-file): Silence --without-x compilation.
[emacs.git] / src / nsterm.m
blob6c5f5f54cb93f07a49ff7e0d4d2e9220cbb608ce
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 #ifdef NS_IMPL_COCOA
68 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
69 #include "macfont.h"
70 #endif
71 #endif
73 /* call tracing */
74 #if 0
75 int term_trace_num = 0;
76 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
77                                 __FILE__, __LINE__, ++term_trace_num)
78 #else
79 #define NSTRACE(x)
80 #endif
82 extern NSString *NSMenuDidBeginTrackingNotification;
84 /* ==========================================================================
86     Local declarations
88    ========================================================================== */
90 /* Convert a symbol indexed with an NSxxx value to a value as defined
91    in keyboard.c (lispy_function_key). I hope this is a correct way
92    of doing things... */
93 static unsigned convert_ns_to_X_keysym[] =
95   NSHomeFunctionKey,            0x50,
96   NSLeftArrowFunctionKey,       0x51,
97   NSUpArrowFunctionKey,         0x52,
98   NSRightArrowFunctionKey,      0x53,
99   NSDownArrowFunctionKey,       0x54,
100   NSPageUpFunctionKey,          0x55,
101   NSPageDownFunctionKey,        0x56,
102   NSEndFunctionKey,             0x57,
103   NSBeginFunctionKey,           0x58,
104   NSSelectFunctionKey,          0x60,
105   NSPrintFunctionKey,           0x61,
106   NSClearLineFunctionKey,       0x0B,
107   NSExecuteFunctionKey,         0x62,
108   NSInsertFunctionKey,          0x63,
109   NSUndoFunctionKey,            0x65,
110   NSRedoFunctionKey,            0x66,
111   NSMenuFunctionKey,            0x67,
112   NSFindFunctionKey,            0x68,
113   NSHelpFunctionKey,            0x6A,
114   NSBreakFunctionKey,           0x6B,
116   NSF1FunctionKey,              0xBE,
117   NSF2FunctionKey,              0xBF,
118   NSF3FunctionKey,              0xC0,
119   NSF4FunctionKey,              0xC1,
120   NSF5FunctionKey,              0xC2,
121   NSF6FunctionKey,              0xC3,
122   NSF7FunctionKey,              0xC4,
123   NSF8FunctionKey,              0xC5,
124   NSF9FunctionKey,              0xC6,
125   NSF10FunctionKey,             0xC7,
126   NSF11FunctionKey,             0xC8,
127   NSF12FunctionKey,             0xC9,
128   NSF13FunctionKey,             0xCA,
129   NSF14FunctionKey,             0xCB,
130   NSF15FunctionKey,             0xCC,
131   NSF16FunctionKey,             0xCD,
132   NSF17FunctionKey,             0xCE,
133   NSF18FunctionKey,             0xCF,
134   NSF19FunctionKey,             0xD0,
135   NSF20FunctionKey,             0xD1,
136   NSF21FunctionKey,             0xD2,
137   NSF22FunctionKey,             0xD3,
138   NSF23FunctionKey,             0xD4,
139   NSF24FunctionKey,             0xD5,
141   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
142   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
143   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
145   NSTabCharacter,               0x09,
146   0x19,                         0x09,  /* left tab->regular since pass shift */
147   NSCarriageReturnCharacter,    0x0D,
148   NSNewlineCharacter,           0x0D,
149   NSEnterCharacter,             0x8D,
151   0x41|NSNumericPadKeyMask,     0xAE,  /* KP_Decimal */
152   0x43|NSNumericPadKeyMask,     0xAA,  /* KP_Multiply */
153   0x45|NSNumericPadKeyMask,     0xAB,  /* KP_Add */
154   0x4B|NSNumericPadKeyMask,     0xAF,  /* KP_Divide */
155   0x4E|NSNumericPadKeyMask,     0xAD,  /* KP_Subtract */
156   0x51|NSNumericPadKeyMask,     0xBD,  /* KP_Equal */
157   0x52|NSNumericPadKeyMask,     0xB0,  /* KP_0 */
158   0x53|NSNumericPadKeyMask,     0xB1,  /* KP_1 */
159   0x54|NSNumericPadKeyMask,     0xB2,  /* KP_2 */
160   0x55|NSNumericPadKeyMask,     0xB3,  /* KP_3 */
161   0x56|NSNumericPadKeyMask,     0xB4,  /* KP_4 */
162   0x57|NSNumericPadKeyMask,     0xB5,  /* KP_5 */
163   0x58|NSNumericPadKeyMask,     0xB6,  /* KP_6 */
164   0x59|NSNumericPadKeyMask,     0xB7,  /* KP_7 */
165   0x5B|NSNumericPadKeyMask,     0xB8,  /* KP_8 */
166   0x5C|NSNumericPadKeyMask,     0xB9,  /* KP_9 */
168   0x1B,                         0x1B   /* escape */
171 static Lisp_Object Qmodifier_value;
172 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
173 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
175 static Lisp_Object QUTF8_STRING;
177 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
178    the maximum font size to NOT antialias.  On GNUstep there is currently
179    no way to control this behavior. */
180 float ns_antialias_threshold;
182 /* Used to pick up AppleHighlightColor on OS X */
183 NSString *ns_selection_color;
185 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
186 NSString *ns_app_name = @"Emacs";  /* default changed later */
188 /* Display variables */
189 struct ns_display_info *x_display_list; /* Chain of existing displays */
190 Lisp_Object ns_display_name_list;
191 long context_menu_value = 0;
193 /* display update */
194 NSPoint last_mouse_motion_position;
195 static NSRect last_mouse_glyph;
196 static Time last_mouse_movement_time = 0;
197 static Lisp_Object last_mouse_motion_frame;
198 static EmacsScroller *last_mouse_scroll_bar = nil;
199 static struct frame *ns_updating_frame;
200 static NSView *focus_view = NULL;
201 static int ns_window_num = 0;
202 #ifdef NS_IMPL_GNUSTEP
203 static NSRect uRect;
204 #endif
205 static BOOL gsaved = NO;
206 static BOOL ns_fake_keydown = NO;
207 #ifdef NS_IMPL_COCOA
208 static BOOL ns_menu_bar_is_hidden = NO;
209 #endif
210 /*static int debug_lock = 0; */
212 /* event loop */
213 static BOOL send_appdefined = YES;
214 #define NO_APPDEFINED_DATA (-8)
215 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
216 static NSTimer *timed_entry = 0;
217 static NSTimer *scroll_repeat_entry = nil;
218 static fd_set select_readfds, select_writefds;
219 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
220 static int select_nfds = 0, select_valid = 0;
221 static struct timespec select_timeout = { 0, 0 };
222 static int selfds[2] = { -1, -1 };
223 static pthread_mutex_t select_mutex;
224 static int apploopnr = 0;
225 static NSAutoreleasePool *outerpool;
226 static struct input_event *emacs_event = NULL;
227 static struct input_event *q_event_ptr = NULL;
228 static int n_emacs_events_pending = 0;
229 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
230   *ns_pending_service_args;
231 static BOOL ns_do_open_file = NO;
232 static BOOL ns_last_use_native_fullscreen;
234 static struct {
235   struct input_event *q;
236   int nr, cap;
237 } hold_event_q = {
238   NULL, 0, 0
241 #ifdef NS_IMPL_COCOA
243  * State for pending menu activation:
244  * MENU_NONE     Normal state
245  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
246  *               run lisp to update the menu.
247  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
248  *               will open.
249  */
250 #define MENU_NONE 0
251 #define MENU_PENDING 1
252 #define MENU_OPENING 2
253 static int menu_will_open_state = MENU_NONE;
255 /* Saved position for menu click.  */
256 static CGPoint menu_mouse_point;
257 #endif
259 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
260 #define NS_FUNCTION_KEY_MASK 0x800000
261 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
262 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
263 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
264 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
265 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
266 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
267 #define EV_MODIFIERS(e)                               \
268     ((([e modifierFlags] & NSHelpKeyMask) ?           \
269            hyper_modifier : 0)                        \
270      | (!EQ (ns_right_alternate_modifier, Qleft) && \
271         (([e modifierFlags] & NSRightAlternateKeyMask) \
272          == NSRightAlternateKeyMask) ? \
273            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
274      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
275            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
276      | (([e modifierFlags] & NSShiftKeyMask) ?     \
277            shift_modifier : 0)                        \
278      | (!EQ (ns_right_control_modifier, Qleft) && \
279         (([e modifierFlags] & NSRightControlKeyMask) \
280          == NSRightControlKeyMask) ? \
281            parse_solitary_modifier (ns_right_control_modifier) : 0) \
282      | (([e modifierFlags] & NSControlKeyMask) ?      \
283            parse_solitary_modifier (ns_control_modifier) : 0)     \
284      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
285            parse_solitary_modifier (ns_function_modifier) : 0)    \
286      | (!EQ (ns_right_command_modifier, Qleft) && \
287         (([e modifierFlags] & NSRightCommandKeyMask) \
288          == NSRightCommandKeyMask) ? \
289            parse_solitary_modifier (ns_right_command_modifier) : 0) \
290      | (([e modifierFlags] & NSCommandKeyMask) ?      \
291            parse_solitary_modifier (ns_command_modifier):0))
293 #define EV_UDMODIFIERS(e)                                      \
294     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
295      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
296      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
297      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
298      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
299      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
300      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
301      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
302      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
304 #define EV_BUTTON(e)                                                         \
305     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
306       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
307      [e buttonNumber] - 1)
309 /* Convert the time field to a timestamp in milliseconds. */
310 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
312 /* This is a piece of code which is common to all the event handling
313    methods.  Maybe it should even be a function.  */
314 #define EV_TRAILER(e)                                                   \
315   {                                                                     \
316     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
317     EV_TRAILER2 (e);                                                    \
318   }
320 #define EV_TRAILER2(e)                                                  \
321   {                                                                     \
322       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
323       if (q_event_ptr)                                                  \
324         {                                                               \
325           n_emacs_events_pending++;                                     \
326           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
327         }                                                               \
328       else                                                              \
329         hold_event (emacs_event);                                       \
330       EVENT_INIT (*emacs_event);                                        \
331       ns_send_appdefined (-1);                                          \
332     }
334 /* TODO: get rid of need for these forward declarations */
335 static void ns_condemn_scroll_bars (struct frame *f);
336 static void ns_judge_scroll_bars (struct frame *f);
337 void x_set_frame_alpha (struct frame *f);
340 /* ==========================================================================
342     Utilities
344    ========================================================================== */
346 static void
347 hold_event (struct input_event *event)
349   if (hold_event_q.nr == hold_event_q.cap)
350     {
351       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
352       else hold_event_q.cap *= 2;
353       hold_event_q.q =
354         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
355     }
357   hold_event_q.q[hold_event_q.nr++] = *event;
358   /* Make sure ns_read_socket is called, i.e. we have input.  */
359   raise (SIGIO);
360   send_appdefined = YES;
363 static Lisp_Object
364 append2 (Lisp_Object list, Lisp_Object item)
365 /* --------------------------------------------------------------------------
366    Utility to append to a list
367    -------------------------------------------------------------------------- */
369   Lisp_Object array[2];
370   array[0] = list;
371   array[1] = list1 (item);
372   return Fnconc (2, &array[0]);
376 const char *
377 ns_etc_directory (void)
378 /* If running as a self-contained app bundle, return as a string the
379    filename of the etc directory, if present; else nil.  */
381   NSBundle *bundle = [NSBundle mainBundle];
382   NSString *resourceDir = [bundle resourcePath];
383   NSString *resourcePath;
384   NSFileManager *fileManager = [NSFileManager defaultManager];
385   BOOL isDir;
387   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
388   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
389     {
390       if (isDir) return [resourcePath UTF8String];
391     }
392   return NULL;
396 const char *
397 ns_exec_path (void)
398 /* If running as a self-contained app bundle, return as a path string
399    the filenames of the libexec and bin directories, ie libexec:bin.
400    Otherwise, return nil.
401    Normally, Emacs does not add its own bin/ directory to the PATH.
402    However, a self-contained NS build has a different layout, with
403    bin/ and libexec/ subdirectories in the directory that contains
404    Emacs.app itself.
405    We put libexec first, because init_callproc_1 uses the first
406    element to initialize exec-directory.  An alternative would be
407    for init_callproc to check for invocation-directory/libexec.
410   NSBundle *bundle = [NSBundle mainBundle];
411   NSString *resourceDir = [bundle resourcePath];
412   NSString *binDir = [bundle bundlePath];
413   NSString *resourcePath, *resourcePaths;
414   NSRange range;
415   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
416   NSFileManager *fileManager = [NSFileManager defaultManager];
417   NSArray *paths;
418   NSEnumerator *pathEnum;
419   BOOL isDir;
421   range = [resourceDir rangeOfString: @"Contents"];
422   if (range.location != NSNotFound)
423     {
424       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
425 #ifdef NS_IMPL_COCOA
426       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
427 #endif
428     }
430   paths = [binDir stringsByAppendingPaths:
431                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
432   pathEnum = [paths objectEnumerator];
433   resourcePaths = @"";
435   while ((resourcePath = [pathEnum nextObject]))
436     {
437       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
438         if (isDir)
439           {
440             if ([resourcePaths length] > 0)
441               resourcePaths
442                 = [resourcePaths stringByAppendingString: pathSeparator];
443             resourcePaths
444               = [resourcePaths stringByAppendingString: resourcePath];
445           }
446     }
447   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
449   return NULL;
453 const char *
454 ns_load_path (void)
455 /* If running as a self-contained app bundle, return as a path string
456    the filenames of the site-lisp, lisp and leim directories.
457    Ie, site-lisp:lisp:leim.  Otherwise, return nil.  */
459   NSBundle *bundle = [NSBundle mainBundle];
460   NSString *resourceDir = [bundle resourcePath];
461   NSString *resourcePath, *resourcePaths;
462   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
463   NSFileManager *fileManager = [NSFileManager defaultManager];
464   BOOL isDir;
465   NSArray *paths = [resourceDir stringsByAppendingPaths:
466                               [NSArray arrayWithObjects:
467                                          @"site-lisp", @"lisp", @"leim", nil]];
468   NSEnumerator *pathEnum = [paths objectEnumerator];
469   resourcePaths = @"";
471   /* Hack to skip site-lisp.  */
472   if (no_site_lisp) resourcePath = [pathEnum nextObject];
474   while ((resourcePath = [pathEnum nextObject]))
475     {
476       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
477         if (isDir)
478           {
479             if ([resourcePaths length] > 0)
480               resourcePaths
481                 = [resourcePaths stringByAppendingString: pathSeparator];
482             resourcePaths
483               = [resourcePaths stringByAppendingString: resourcePath];
484           }
485     }
486   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
488   return NULL;
491 static void
492 ns_timeout (int usecs)
493 /* --------------------------------------------------------------------------
494      Blocking timer utility used by ns_ring_bell
495    -------------------------------------------------------------------------- */
497   struct timespec wakeup = timespec_add (current_timespec (),
498                                          make_timespec (0, usecs * 1000));
500   /* Keep waiting until past the time wakeup.  */
501   while (1)
502     {
503       struct timespec timeout, now = current_timespec ();
504       if (timespec_cmp (wakeup, now) <= 0)
505         break;
506       timeout = timespec_sub (wakeup, now);
508       /* Try to wait that long--but we might wake up sooner.  */
509       pselect (0, NULL, NULL, NULL, &timeout, NULL);
510     }
514 void
515 ns_release_object (void *obj)
516 /* --------------------------------------------------------------------------
517     Release an object (callable from C)
518    -------------------------------------------------------------------------- */
520     [(id)obj release];
524 void
525 ns_retain_object (void *obj)
526 /* --------------------------------------------------------------------------
527     Retain an object (callable from C)
528    -------------------------------------------------------------------------- */
530     [(id)obj retain];
534 void *
535 ns_alloc_autorelease_pool (void)
536 /* --------------------------------------------------------------------------
537      Allocate a pool for temporary objects (callable from C)
538    -------------------------------------------------------------------------- */
540   return [[NSAutoreleasePool alloc] init];
544 void
545 ns_release_autorelease_pool (void *pool)
546 /* --------------------------------------------------------------------------
547      Free a pool and temporary objects it refers to (callable from C)
548    -------------------------------------------------------------------------- */
550   ns_release_object (pool);
555 /* ==========================================================================
557     Focus (clipping) and screen update
559    ========================================================================== */
562 // Window constraining
563 // -------------------
565 // To ensure that the windows are not placed under the menu bar, they
566 // are typically moved by the call-back constrainFrameRect. However,
567 // by overriding it, it's possible to inhibit this, leaving the window
568 // in it's original position.
570 // It's possible to hide the menu bar. However, technically, it's only
571 // possible to hide it when the application is active. To ensure that
572 // this work properly, the menu bar and window constraining are
573 // deferred until the application becomes active.
575 // Even though it's not possible to manually move a window above the
576 // top of the screen, it is allowed if it's done programmatically,
577 // when the menu is hidden. This allows the editable area to cover the
578 // full screen height.
580 // Test cases
581 // ----------
583 // Use the following extra files:
585 //    init.el:
586 //       ;; Hide menu and place frame slightly above the top of the screen.
587 //       (setq ns-auto-hide-menu-bar t)
588 //       (set-frame-position (selected-frame) 0 -20)
590 // Test 1:
592 //    emacs -Q -l init.el
594 //    Result: No menu bar, and the title bar should be above the screen.
596 // Test 2:
598 //    emacs -Q
600 //    Result: Menu bar visible, frame placed immediately below the menu.
603 static void
604 ns_constrain_all_frames (void)
606   Lisp_Object tail, frame;
608   FOR_EACH_FRAME (tail, frame)
609     {
610       struct frame *f = XFRAME (frame);
611       if (FRAME_NS_P (f))
612         {
613           NSView *view = FRAME_NS_VIEW (f);
614           /* This no-op will trigger the default window placing
615            * constraint system. */
616           f->output_data.ns->dont_constrain = 0;
617           [[view window] setFrameOrigin:[[view window] frame].origin];
618         }
619     }
623 /* True, if the menu bar should be hidden.  */
625 static BOOL
626 ns_menu_bar_should_be_hidden (void)
628   return !NILP (ns_auto_hide_menu_bar)
629     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
633 /* Show or hide the menu bar, based on user setting.  */
635 static void
636 ns_update_auto_hide_menu_bar (void)
638 #ifdef NS_IMPL_COCOA
639 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
640   block_input ();
642   NSTRACE (ns_update_auto_hide_menu_bar);
644   if (NSApp != nil
645       && [NSApp isActive]
646       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
647     {
648       // Note, "setPresentationOptions" triggers an error unless the
649       // application is active.
650       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
652       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
653         {
654           NSApplicationPresentationOptions options
655             = NSApplicationPresentationAutoHideDock;
657           if (menu_bar_should_be_hidden)
658             options |= NSApplicationPresentationAutoHideMenuBar;
660           [NSApp setPresentationOptions: options];
662           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
664           if (!ns_menu_bar_is_hidden)
665             {
666               ns_constrain_all_frames ();
667             }
668         }
669     }
671   unblock_input ();
672 #endif
673 #endif
677 static void
678 ns_update_begin (struct frame *f)
679 /* --------------------------------------------------------------------------
680    Prepare for a grouped sequence of drawing calls
681    external (RIF) call; whole frame, called before update_window_begin
682    -------------------------------------------------------------------------- */
684   NSView *view = FRAME_NS_VIEW (f);
685   NSTRACE (ns_update_begin);
687   ns_update_auto_hide_menu_bar ();
689   ns_updating_frame = f;
690   [view lockFocus];
692   /* drawRect may have been called for say the minibuffer, and then clip path
693      is for the minibuffer.  But the display engine may draw more because
694      we have set the frame as garbaged.  So reset clip path to the whole
695      view.  */
696 #ifdef NS_IMPL_COCOA
697   {
698     NSBezierPath *bp;
699     NSRect r = [view frame];
700     NSRect cr = [[view window] frame];
701     /* If a large frame size is set, r may be larger than the window frame
702        before constrained.  In that case don't change the clip path, as we
703        will clear in to the tool bar and title bar.  */
704     if (r.size.height
705         + FRAME_NS_TITLEBAR_HEIGHT (f)
706         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
707       {
708         bp = [[NSBezierPath bezierPathWithRect: r] retain];
709         [bp setClip];
710         [bp release];
711       }
712   }
713 #endif
715 #ifdef NS_IMPL_GNUSTEP
716   uRect = NSMakeRect (0, 0, 0, 0);
717 #endif
721 static void
722 ns_update_window_begin (struct window *w)
723 /* --------------------------------------------------------------------------
724    Prepare for a grouped sequence of drawing calls
725    external (RIF) call; for one window, called after update_begin
726    -------------------------------------------------------------------------- */
728   struct frame *f = XFRAME (WINDOW_FRAME (w));
729   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
731   NSTRACE (ns_update_window_begin);
732   w->output_cursor = w->cursor;
734   block_input ();
736   if (f == hlinfo->mouse_face_mouse_frame)
737     {
738       /* Don't do highlighting for mouse motion during the update.  */
739       hlinfo->mouse_face_defer = 1;
741         /* If the frame needs to be redrawn,
742            simply forget about any prior mouse highlighting.  */
743       if (FRAME_GARBAGED_P (f))
744         hlinfo->mouse_face_window = Qnil;
746       /* (further code for mouse faces ifdef'd out in other terms elided) */
747     }
749   unblock_input ();
753 static void
754 ns_update_window_end (struct window *w, bool cursor_on_p,
755                       bool mouse_face_overwritten_p)
756 /* --------------------------------------------------------------------------
757    Finished a grouped sequence of drawing calls
758    external (RIF) call; for one window called before update_end
759    -------------------------------------------------------------------------- */
761   /* note: this fn is nearly identical in all terms */
762   if (!w->pseudo_window_p)
763     {
764       block_input ();
766       if (cursor_on_p)
767         display_and_set_cursor (w, 1,
768                                 w->output_cursor.hpos, w->output_cursor.vpos,
769                                 w->output_cursor.x, w->output_cursor.y);
771       if (draw_window_fringes (w, 1))
772         x_draw_vertical_border (w);
774       unblock_input ();
775     }
777   /* If a row with mouse-face was overwritten, arrange for
778      frame_up_to_date to redisplay the mouse highlight.  */
779   if (mouse_face_overwritten_p)
780     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
782   NSTRACE (update_window_end);
786 static void
787 ns_update_end (struct frame *f)
788 /* --------------------------------------------------------------------------
789    Finished a grouped sequence of drawing calls
790    external (RIF) call; for whole frame, called after update_window_end
791    -------------------------------------------------------------------------- */
793   EmacsView *view = FRAME_NS_VIEW (f);
795 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
796   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
798   block_input ();
800   [view unlockFocus];
801   [[view window] flushWindow];
803   unblock_input ();
804   ns_updating_frame = NULL;
805   NSTRACE (ns_update_end);
808 static void
809 ns_focus (struct frame *f, NSRect *r, int n)
810 /* --------------------------------------------------------------------------
811    Internal: Focus on given frame.  During small local updates this is used to
812      draw, however during large updates, ns_update_begin and ns_update_end are
813      called to wrap the whole thing, in which case these calls are stubbed out.
814      Except, on GNUstep, we accumulate the rectangle being drawn into, because
815      the back end won't do this automatically, and will just end up flushing
816      the entire window.
817    -------------------------------------------------------------------------- */
819 //  NSTRACE (ns_focus);
820 /* static int c =0;
821    fprintf (stderr, "focus: %d", c++);
822    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
823    fprintf (stderr, "\n"); */
825   if (f != ns_updating_frame)
826     {
827       NSView *view = FRAME_NS_VIEW (f);
828       if (view != focus_view)
829         {
830           if (focus_view != NULL)
831             {
832               [focus_view unlockFocus];
833               [[focus_view window] flushWindow];
834 /*debug_lock--; */
835             }
837           if (view)
838             [view lockFocus];
839           focus_view = view;
840 /*if (view) debug_lock++; */
841         }
842     }
844   /* clipping */
845   if (r)
846     {
847       [[NSGraphicsContext currentContext] saveGraphicsState];
848       if (n == 2)
849         NSRectClipList (r, 2);
850       else
851         NSRectClip (*r);
852       gsaved = YES;
853     }
857 static void
858 ns_unfocus (struct frame *f)
859 /* --------------------------------------------------------------------------
860      Internal: Remove focus on given frame
861    -------------------------------------------------------------------------- */
863 //  NSTRACE (ns_unfocus);
865   if (gsaved)
866     {
867       [[NSGraphicsContext currentContext] restoreGraphicsState];
868       gsaved = NO;
869     }
871   if (f != ns_updating_frame)
872     {
873       if (focus_view != NULL)
874         {
875           [focus_view unlockFocus];
876           [[focus_view window] flushWindow];
877           focus_view = NULL;
878 /*debug_lock--; */
879         }
880     }
884 static void
885 ns_clip_to_row (struct window *w, struct glyph_row *row,
886                 enum glyph_row_area area, BOOL gc)
887 /* --------------------------------------------------------------------------
888      Internal (but parallels other terms): Focus drawing on given row
889    -------------------------------------------------------------------------- */
891   struct frame *f = XFRAME (WINDOW_FRAME (w));
892   NSRect clip_rect;
893   int window_x, window_y, window_width;
895   window_box (w, area, &window_x, &window_y, &window_width, 0);
897   clip_rect.origin.x = window_x;
898   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
899   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
900   clip_rect.size.width = window_width;
901   clip_rect.size.height = row->visible_height;
903   ns_focus (f, &clip_rect, 1);
907 static void
908 ns_ring_bell (struct frame *f)
909 /* --------------------------------------------------------------------------
910      "Beep" routine
911    -------------------------------------------------------------------------- */
913   NSTRACE (ns_ring_bell);
914   if (visible_bell)
915     {
916       NSAutoreleasePool *pool;
917       struct frame *frame = SELECTED_FRAME ();
918       NSView *view;
920       block_input ();
921       pool = [[NSAutoreleasePool alloc] init];
923       view = FRAME_NS_VIEW (frame);
924       if (view != nil)
925         {
926           NSRect r, surr;
927           NSPoint dim = NSMakePoint (128, 128);
929           r = [view bounds];
930           r.origin.x += (r.size.width - dim.x) / 2;
931           r.origin.y += (r.size.height - dim.y) / 2;
932           r.size.width = dim.x;
933           r.size.height = dim.y;
934           surr = NSInsetRect (r, -2, -2);
935           ns_focus (frame, &surr, 1);
936           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
937           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
938                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
939           NSRectFill (r);
940           [[view window] flushWindow];
941           ns_timeout (150000);
942           [[view window] restoreCachedImage];
943           [[view window] flushWindow];
944           ns_unfocus (frame);
945         }
946       [pool release];
947       unblock_input ();
948     }
949   else
950     {
951       NSBeep ();
952     }
955 /* ==========================================================================
957     Frame / window manager related functions
959    ========================================================================== */
962 static void
963 ns_raise_frame (struct frame *f)
964 /* --------------------------------------------------------------------------
965      Bring window to foreground and make it active
966    -------------------------------------------------------------------------- */
968   NSView *view;
969   check_window_system (f);
970   view = FRAME_NS_VIEW (f);
971   block_input ();
972   if (FRAME_VISIBLE_P (f))
973     [[view window] makeKeyAndOrderFront: NSApp];
974   unblock_input ();
978 static void
979 ns_lower_frame (struct frame *f)
980 /* --------------------------------------------------------------------------
981      Send window to back
982    -------------------------------------------------------------------------- */
984   NSView *view;
985   check_window_system (f);
986   view = FRAME_NS_VIEW (f);
987   block_input ();
988   [[view window] orderBack: NSApp];
989   unblock_input ();
993 static void
994 ns_frame_raise_lower (struct frame *f, int raise)
995 /* --------------------------------------------------------------------------
996      External (hook)
997    -------------------------------------------------------------------------- */
999   NSTRACE (ns_frame_raise_lower);
1001   if (raise)
1002     ns_raise_frame (f);
1003   else
1004     ns_lower_frame (f);
1008 static void
1009 ns_frame_rehighlight (struct frame *frame)
1010 /* --------------------------------------------------------------------------
1011      External (hook): called on things like window switching within frame
1012    -------------------------------------------------------------------------- */
1014   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1015   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1017   NSTRACE (ns_frame_rehighlight);
1018   if (dpyinfo->x_focus_frame)
1019     {
1020       dpyinfo->x_highlight_frame
1021         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1022            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1023            : dpyinfo->x_focus_frame);
1024       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1025         {
1026           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1027           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1028         }
1029     }
1030   else
1031       dpyinfo->x_highlight_frame = 0;
1033   if (dpyinfo->x_highlight_frame &&
1034          dpyinfo->x_highlight_frame != old_highlight)
1035     {
1036       if (old_highlight)
1037         {
1038           x_update_cursor (old_highlight, 1);
1039           x_set_frame_alpha (old_highlight);
1040         }
1041       if (dpyinfo->x_highlight_frame)
1042         {
1043           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1044           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1045         }
1046     }
1050 void
1051 x_make_frame_visible (struct frame *f)
1052 /* --------------------------------------------------------------------------
1053      External: Show the window (X11 semantics)
1054    -------------------------------------------------------------------------- */
1056   NSTRACE (x_make_frame_visible);
1057   /* XXX: at some points in past this was not needed, as the only place that
1058      called this (frame.c:Fraise_frame ()) also called raise_lower;
1059      if this ends up the case again, comment this out again. */
1060   if (!FRAME_VISIBLE_P (f))
1061     {
1062       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1064       SET_FRAME_VISIBLE (f, 1);
1065       ns_raise_frame (f);
1067       /* Making a new frame from a fullscreen frame will make the new frame
1068          fullscreen also.  So skip handleFS as this will print an error.  */
1069       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1070           && [view isFullscreen])
1071         return;
1073       if (f->want_fullscreen != FULLSCREEN_NONE)
1074         {
1075           block_input ();
1076           [view handleFS];
1077           unblock_input ();
1078         }
1079     }
1083 void
1084 x_make_frame_invisible (struct frame *f)
1085 /* --------------------------------------------------------------------------
1086      External: Hide the window (X11 semantics)
1087    -------------------------------------------------------------------------- */
1089   NSView *view;
1090   NSTRACE (x_make_frame_invisible);
1091   check_window_system (f);
1092   view = FRAME_NS_VIEW (f);
1093   [[view window] orderOut: NSApp];
1094   SET_FRAME_VISIBLE (f, 0);
1095   SET_FRAME_ICONIFIED (f, 0);
1099 void
1100 x_iconify_frame (struct frame *f)
1101 /* --------------------------------------------------------------------------
1102      External: Iconify window
1103    -------------------------------------------------------------------------- */
1105   NSView *view;
1106   struct ns_display_info *dpyinfo;
1108   NSTRACE (x_iconify_frame);
1109   check_window_system (f);
1110   view = FRAME_NS_VIEW (f);
1111   dpyinfo = FRAME_DISPLAY_INFO (f);
1113   if (dpyinfo->x_highlight_frame == f)
1114     dpyinfo->x_highlight_frame = 0;
1116   if ([[view window] windowNumber] <= 0)
1117     {
1118       /* the window is still deferred.  Make it very small, bring it
1119          on screen and order it out. */
1120       NSRect s = { { 100, 100}, {0, 0} };
1121       NSRect t;
1122       t = [[view window] frame];
1123       [[view window] setFrame: s display: NO];
1124       [[view window] orderBack: NSApp];
1125       [[view window] orderOut: NSApp];
1126       [[view window] setFrame: t display: NO];
1127     }
1128   [[view window] miniaturize: NSApp];
1131 /* Free X resources of frame F.  */
1133 void
1134 x_free_frame_resources (struct frame *f)
1136   NSView *view;
1137   struct ns_display_info *dpyinfo;
1138   Mouse_HLInfo *hlinfo;
1140   NSTRACE (x_free_frame_resources);
1141   check_window_system (f);
1142   view = FRAME_NS_VIEW (f);
1143   dpyinfo = FRAME_DISPLAY_INFO (f);
1144   hlinfo = MOUSE_HL_INFO (f);
1146   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1148   block_input ();
1150   free_frame_menubar (f);
1152   if (FRAME_FACE_CACHE (f))
1153     free_frame_faces (f);
1155   if (f == dpyinfo->x_focus_frame)
1156     dpyinfo->x_focus_frame = 0;
1157   if (f == dpyinfo->x_highlight_frame)
1158     dpyinfo->x_highlight_frame = 0;
1159   if (f == hlinfo->mouse_face_mouse_frame)
1160     reset_mouse_highlight (hlinfo);
1162   if (f->output_data.ns->miniimage != nil)
1163     [f->output_data.ns->miniimage release];
1165   [[view window] close];
1166   [view release];
1168   xfree (f->output_data.ns);
1170   unblock_input ();
1173 void
1174 x_destroy_window (struct frame *f)
1175 /* --------------------------------------------------------------------------
1176      External: Delete the window
1177    -------------------------------------------------------------------------- */
1179   NSTRACE (x_destroy_window);
1180   check_window_system (f);
1181   x_free_frame_resources (f);
1182   ns_window_num--;
1186 void
1187 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1188 /* --------------------------------------------------------------------------
1189      External: Position the window
1190    -------------------------------------------------------------------------- */
1192   NSView *view = FRAME_NS_VIEW (f);
1193   NSArray *screens = [NSScreen screens];
1194   NSScreen *fscreen = [screens objectAtIndex: 0];
1195   NSScreen *screen = [[view window] screen];
1197   NSTRACE (x_set_offset);
1199   block_input ();
1201   f->left_pos = xoff;
1202   f->top_pos = yoff;
1204   if (view != nil && screen && fscreen)
1205     {
1206       f->left_pos = f->size_hint_flags & XNegative
1207         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1208         : f->left_pos;
1209       /* We use visibleFrame here to take menu bar into account.
1210          Ideally we should also adjust left/top with visibleFrame.origin.  */
1212       f->top_pos = f->size_hint_flags & YNegative
1213         ? ([screen visibleFrame].size.height + f->top_pos
1214            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1215            - FRAME_TOOLBAR_HEIGHT (f))
1216         : f->top_pos;
1217 #ifdef NS_IMPL_GNUSTEP
1218       if (f->left_pos < 100)
1219         f->left_pos = 100;  /* don't overlap menu */
1220 #endif
1221       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1222          menu bar.  */
1223       f->output_data.ns->dont_constrain = 0;
1224       [[view window] setFrameTopLeftPoint:
1225                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1226                                     SCREENMAXBOUND ([fscreen frame].size.height
1227                                                     - NS_TOP_POS (f)))];
1228       f->size_hint_flags &= ~(XNegative|YNegative);
1229     }
1231   unblock_input ();
1235 void
1236 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1237 /* --------------------------------------------------------------------------
1238      Adjust window pixel size based on given character grid size
1239      Impl is a bit more complex than other terms, need to do some
1240      internal clipping.
1241    -------------------------------------------------------------------------- */
1243   EmacsView *view = FRAME_NS_VIEW (f);
1244   NSWindow *window = [view window];
1245   NSRect wr = [window frame];
1246   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1247   int pixelwidth, pixelheight;
1249   NSTRACE (x_set_window_size);
1251   if (view == nil)
1252     return;
1254 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1256   block_input ();
1258   check_frame_size (f, &rows, &cols);
1260   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1261   compute_fringe_widths (f, 0);
1263   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1264   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1266   /* If we have a toolbar, take its height into account. */
1267   if (tb && ! [view isFullscreen])
1268     {
1269     /* NOTE: previously this would generate wrong result if toolbar not
1270              yet displayed and fixing toolbar_height=32 helped, but
1271              now (200903) seems no longer needed */
1272     FRAME_TOOLBAR_HEIGHT (f) =
1273       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1274         - FRAME_NS_TITLEBAR_HEIGHT (f);
1275 #ifdef NS_IMPL_GNUSTEP
1276       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1277 #endif
1278     }
1279   else
1280     FRAME_TOOLBAR_HEIGHT (f) = 0;
1282   wr.size.width = pixelwidth + f->border_width;
1283   wr.size.height = pixelheight;
1284   if (! [view isFullscreen])
1285     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1286       + FRAME_TOOLBAR_HEIGHT (f);
1288   /* Do not try to constrain to this screen.  We may have multiple
1289      screens, and want Emacs to span those.  Constraining to screen
1290      prevents that, and that is not nice to the user.  */
1291  if (f->output_data.ns->zooming)
1292    f->output_data.ns->zooming = 0;
1293  else
1294    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1296   [view setRows: rows andColumns: cols];
1297   [window setFrame: wr display: YES];
1299 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1301   /* This is a trick to compensate for Emacs' managing the scrollbar area
1302      as a fixed number of standard character columns.  Instead of leaving
1303      blank space for the extra, we chopped it off above.  Now for
1304      left-hand scrollbars, we shift all rendering to the left by the
1305      difference between the real width and Emacs' imagined one.  For
1306      right-hand bars, don't worry about it since the extra is never used.
1307      (Obviously doesn't work for vertically split windows tho..) */
1308   {
1309     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1310       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1311                      - NS_SCROLL_BAR_WIDTH (f), 0)
1312       : NSMakePoint (0, 0);
1313     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1314     [view setBoundsOrigin: origin];
1315   }
1317   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1318   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1319   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1320 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1322   mark_window_cursors_off (XWINDOW (f->root_window));
1323   cancel_mouse_face (f);
1325   unblock_input ();
1329 static void
1330 ns_fullscreen_hook (struct frame *f)
1332   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1334   if (!FRAME_VISIBLE_P (f))
1335     return;
1337    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1338     {
1339       /* Old style fs don't initiate correctly if created from
1340          init/default-frame alist, so use a timer (not nice...).
1341       */
1342       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1343                                      selector: @selector (handleFS)
1344                                      userInfo: nil repeats: NO];
1345       return;
1346     }
1348   block_input ();
1349   [view handleFS];
1350   unblock_input ();
1353 /* ==========================================================================
1355     Color management
1357    ========================================================================== */
1360 NSColor *
1361 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1363   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1364   if (idx < 1 || idx >= color_table->avail)
1365     return nil;
1366   return color_table->colors[idx];
1370 unsigned long
1371 ns_index_color (NSColor *color, struct frame *f)
1373   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1374   ptrdiff_t idx;
1375   ptrdiff_t i;
1377   if (!color_table->colors)
1378     {
1379       color_table->size = NS_COLOR_CAPACITY;
1380       color_table->avail = 1; /* skip idx=0 as marker */
1381       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1382       color_table->colors[0] = nil;
1383       color_table->empty_indices = [[NSMutableSet alloc] init];
1384     }
1386   /* do we already have this color ? */
1387   for (i = 1; i < color_table->avail; i++)
1388     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1389       return i;
1391   if ([color_table->empty_indices count] > 0)
1392     {
1393       NSNumber *index = [color_table->empty_indices anyObject];
1394       [color_table->empty_indices removeObject: index];
1395       idx = [index unsignedLongValue];
1396     }
1397   else
1398     {
1399       if (color_table->avail == color_table->size)
1400         color_table->colors =
1401           xpalloc (color_table->colors, &color_table->size, 1,
1402                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1403       idx = color_table->avail++;
1404     }
1406   color_table->colors[idx] = color;
1407   [color retain];
1408 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1409   return idx;
1413 void
1414 ns_free_indexed_color (unsigned long idx, struct frame *f)
1416   struct ns_color_table *color_table;
1417   NSColor *color;
1418   NSNumber *index;
1420   if (!f)
1421     return;
1423   color_table = FRAME_DISPLAY_INFO (f)->color_table;
1425   if (idx <= 0 || idx >= color_table->size) {
1426     message1 ("ns_free_indexed_color: Color index out of range.\n");
1427     return;
1428   }
1430   index = [NSNumber numberWithUnsignedInt: idx];
1431   if ([color_table->empty_indices containsObject: index]) {
1432     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1433     return;
1434   }
1436   color = color_table->colors[idx];
1437   [color release];
1438   color_table->colors[idx] = nil;
1439   [color_table->empty_indices addObject: index];
1440 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1444 static int
1445 ns_get_color (const char *name, NSColor **col)
1446 /* --------------------------------------------------------------------------
1447      Parse a color name
1448    -------------------------------------------------------------------------- */
1449 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1450    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1451    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1453   NSColor *new = nil;
1454   static char hex[20];
1455   int scaling;
1456   float r = -1.0, g, b;
1457   NSString *nsname = [NSString stringWithUTF8String: name];
1459 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1460   block_input ();
1462   if ([nsname isEqualToString: @"ns_selection_color"])
1463     {
1464       nsname = ns_selection_color;
1465       name = [ns_selection_color UTF8String];
1466     }
1468   /* First, check for some sort of numeric specification. */
1469   hex[0] = '\0';
1471   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1472     {
1473       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1474       [scanner scanFloat: &r];
1475       [scanner scanFloat: &g];
1476       [scanner scanFloat: &b];
1477     }
1478   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1479     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1480   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1481     {
1482       int len = (strlen(name) - 1);
1483       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1484       int i;
1485       scaling = strlen(name+start) / 3;
1486       for (i = 0; i < 3; i++)
1487         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1488                  name + start + i * scaling);
1489       hex[3 * (scaling + 1) - 1] = '\0';
1490     }
1492   if (hex[0])
1493     {
1494       int rr, gg, bb;
1495       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1496       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1497         {
1498           r = rr / fscale;
1499           g = gg / fscale;
1500           b = bb / fscale;
1501         }
1502     }
1504   if (r >= 0.0F)
1505     {
1506       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1507       unblock_input ();
1508       return 0;
1509     }
1511   /* Otherwise, color is expected to be from a list */
1512   {
1513     NSEnumerator *lenum, *cenum;
1514     NSString *name;
1515     NSColorList *clist;
1517 #ifdef NS_IMPL_GNUSTEP
1518     /* XXX: who is wrong, the requestor or the implementation? */
1519     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1520         == NSOrderedSame)
1521       nsname = @"highlightColor";
1522 #endif
1524     lenum = [[NSColorList availableColorLists] objectEnumerator];
1525     while ( (clist = [lenum nextObject]) && new == nil)
1526       {
1527         cenum = [[clist allKeys] objectEnumerator];
1528         while ( (name = [cenum nextObject]) && new == nil )
1529           {
1530             if ([name compare: nsname
1531                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1532               new = [clist colorWithKey: name];
1533           }
1534       }
1535   }
1537   if (new)
1538     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1539   unblock_input ();
1540   return new ? 0 : 1;
1545 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1546 /* --------------------------------------------------------------------------
1547      Convert a Lisp string object to a NS color
1548    -------------------------------------------------------------------------- */
1550   NSTRACE (ns_lisp_to_color);
1551   if (STRINGP (color))
1552     return ns_get_color (SSDATA (color), col);
1553   else if (SYMBOLP (color))
1554     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1555   return 1;
1559 Lisp_Object
1560 ns_color_to_lisp (NSColor *col)
1561 /* --------------------------------------------------------------------------
1562      Convert a color to a lisp string with the RGB equivalent
1563    -------------------------------------------------------------------------- */
1565   EmacsCGFloat red, green, blue, alpha, gray;
1566   char buf[1024];
1567   const char *str;
1568   NSTRACE (ns_color_to_lisp);
1570   block_input ();
1571   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1573       if ((str =[[col colorNameComponent] UTF8String]))
1574         {
1575           unblock_input ();
1576           return build_string ((char *)str);
1577         }
1579     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1580         getRed: &red green: &green blue: &blue alpha: &alpha];
1581   if (red ==green && red ==blue)
1582     {
1583       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1584             getWhite: &gray alpha: &alpha];
1585       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1586                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1587       unblock_input ();
1588       return build_string (buf);
1589     }
1591   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1592             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1594   unblock_input ();
1595   return build_string (buf);
1599 void
1600 ns_query_color(void *col, XColor *color_def, int setPixel)
1601 /* --------------------------------------------------------------------------
1602          Get ARGB values out of NSColor col and put them into color_def.
1603          If setPixel, set the pixel to a concatenated version.
1604          and set color_def pixel to the resulting index.
1605    -------------------------------------------------------------------------- */
1607   EmacsCGFloat r, g, b, a;
1609   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1610   color_def->red   = r * 65535;
1611   color_def->green = g * 65535;
1612   color_def->blue  = b * 65535;
1614   if (setPixel == YES)
1615     color_def->pixel
1616       = ARGB_TO_ULONG((int)(a*255),
1617                       (int)(r*255), (int)(g*255), (int)(b*255));
1621 bool
1622 ns_defined_color (struct frame *f,
1623                   const char *name,
1624                   XColor *color_def,
1625                   bool alloc,
1626                   bool makeIndex)
1627 /* --------------------------------------------------------------------------
1628          Return true if named color found, and set color_def rgb accordingly.
1629          If makeIndex and alloc are nonzero put the color in the color_table,
1630          and set color_def pixel to the resulting index.
1631          If makeIndex is zero, set color_def pixel to ARGB.
1632          Return false if not found
1633    -------------------------------------------------------------------------- */
1635   NSColor *col;
1636   NSTRACE (ns_defined_color);
1638   block_input ();
1639   if (ns_get_color (name, &col) != 0) /* Color not found  */
1640     {
1641       unblock_input ();
1642       return 0;
1643     }
1644   if (makeIndex && alloc)
1645     color_def->pixel = ns_index_color (col, f);
1646   ns_query_color (col, color_def, !makeIndex);
1647   unblock_input ();
1648   return 1;
1652 void
1653 x_set_frame_alpha (struct frame *f)
1654 /* --------------------------------------------------------------------------
1655      change the entire-frame transparency
1656    -------------------------------------------------------------------------- */
1658   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1659   double alpha = 1.0;
1660   double alpha_min = 1.0;
1662   if (dpyinfo->x_highlight_frame == f)
1663     alpha = f->alpha[0];
1664   else
1665     alpha = f->alpha[1];
1667   if (FLOATP (Vframe_alpha_lower_limit))
1668     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1669   else if (INTEGERP (Vframe_alpha_lower_limit))
1670     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1672   if (alpha < 0.0)
1673     return;
1674   else if (1.0 < alpha)
1675     alpha = 1.0;
1676   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1677     alpha = alpha_min;
1679 #ifdef NS_IMPL_COCOA
1680   {
1681     EmacsView *view = FRAME_NS_VIEW (f);
1682   [[view window] setAlphaValue: alpha];
1683   }
1684 #endif
1688 /* ==========================================================================
1690     Mouse handling
1692    ========================================================================== */
1695 void
1696 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1697 /* --------------------------------------------------------------------------
1698      Programmatically reposition mouse pointer in pixel coordinates
1699    -------------------------------------------------------------------------- */
1701   NSTRACE (x_set_mouse_pixel_position);
1702   ns_raise_frame (f);
1703 #if 0
1704   /* FIXME: this does not work, and what about GNUstep? */
1705 #ifdef NS_IMPL_COCOA
1706   [FRAME_NS_VIEW (f) lockFocus];
1707   PSsetmouse ((float)pix_x, (float)pix_y);
1708   [FRAME_NS_VIEW (f) unlockFocus];
1709 #endif
1710 #endif
1714 void
1715 x_set_mouse_position (struct frame *f, int h, int v)
1716 /* --------------------------------------------------------------------------
1717      Programmatically reposition mouse pointer in character coordinates
1718    -------------------------------------------------------------------------- */
1720   int pix_x, pix_y;
1722   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1723   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1725   if (pix_x < 0) pix_x = 0;
1726   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1728   if (pix_y < 0) pix_y = 0;
1729   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1731   x_set_mouse_pixel_position (f, pix_x, pix_y);
1735 static int
1736 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1737 /*   ------------------------------------------------------------------------
1738      Called by EmacsView on mouseMovement events.  Passes on
1739      to emacs mainstream code if we moved off of a rect of interest
1740      known as last_mouse_glyph.
1741      ------------------------------------------------------------------------ */
1743 //  NSTRACE (note_mouse_movement);
1745   XSETFRAME (last_mouse_motion_frame, frame);
1747   /* Note, this doesn't get called for enter/leave, since we don't have a
1748      position.  Those are taken care of in the corresponding NSView methods. */
1750   /* has movement gone beyond last rect we were tracking? */
1751   if (x < last_mouse_glyph.origin.x ||
1752       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1753       y < last_mouse_glyph.origin.y ||
1754       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1755     {
1756       ns_update_begin(frame);
1757       frame->mouse_moved = 1;
1758       note_mouse_highlight (frame, x, y);
1759       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1760       ns_update_end(frame);
1761       return 1;
1762     }
1764   return 0;
1768 static void
1769 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1770                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1771                    Time *time)
1772 /* --------------------------------------------------------------------------
1773     External (hook): inform emacs about mouse position and hit parts.
1774     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1775     x & y should be position in the scrollbar (the whole bar, not the handle)
1776     and length of scrollbar respectively
1777    -------------------------------------------------------------------------- */
1779   id view;
1780   NSPoint position;
1781   Lisp_Object frame, tail;
1782   struct frame *f;
1783   struct ns_display_info *dpyinfo;
1785   NSTRACE (ns_mouse_position);
1787   if (*fp == NULL)
1788     {
1789       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1790       return;
1791     }
1793   dpyinfo = FRAME_DISPLAY_INFO (*fp);
1795   block_input ();
1797   if (last_mouse_scroll_bar != nil && insist == 0)
1798     {
1799       /* TODO: we do not use this path at the moment because drag events will
1800            go directly to the EmacsScroller.  Leaving code in for now. */
1801       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1802                                               x: x y: y];
1803       if (time) *time = last_mouse_movement_time;
1804       last_mouse_scroll_bar = nil;
1805     }
1806   else
1807     {
1808       /* Clear the mouse-moved flag for every frame on this display.  */
1809       FOR_EACH_FRAME (tail, frame)
1810         if (FRAME_NS_P (XFRAME (frame))
1811             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1812           XFRAME (frame)->mouse_moved = 0;
1814       last_mouse_scroll_bar = nil;
1815       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1816         f = last_mouse_frame;
1817       else
1818         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1819                                     : SELECTED_FRAME ();
1821       if (f && FRAME_NS_P (f))
1822         {
1823           view = FRAME_NS_VIEW (*fp);
1825           position = [[view window] mouseLocationOutsideOfEventStream];
1826           position = [view convertPoint: position fromView: nil];
1827           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1828 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1830           if (bar_window) *bar_window = Qnil;
1831           if (part) *part = 0; /*scroll_bar_handle; */
1833           if (x) XSETINT (*x, lrint (position.x));
1834           if (y) XSETINT (*y, lrint (position.y));
1835           if (time) *time = last_mouse_movement_time;
1836           *fp = f;
1837         }
1838     }
1840   unblock_input ();
1844 static void
1845 ns_frame_up_to_date (struct frame *f)
1846 /* --------------------------------------------------------------------------
1847     External (hook): Fix up mouse highlighting right after a full update.
1848     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1849    -------------------------------------------------------------------------- */
1851   NSTRACE (ns_frame_up_to_date);
1853   if (FRAME_NS_P (f))
1854     {
1855       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1856       if (f == hlinfo->mouse_face_mouse_frame)
1857         {
1858           block_input ();
1859           ns_update_begin(f);
1860           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1861                                 hlinfo->mouse_face_mouse_x,
1862                                 hlinfo->mouse_face_mouse_y);
1863           ns_update_end(f);
1864           unblock_input ();
1865         }
1866     }
1870 static void
1871 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1872 /* --------------------------------------------------------------------------
1873     External (RIF): set frame mouse pointer type.
1874    -------------------------------------------------------------------------- */
1876   NSTRACE (ns_define_frame_cursor);
1877   if (FRAME_POINTER_TYPE (f) != cursor)
1878     {
1879       EmacsView *view = FRAME_NS_VIEW (f);
1880       FRAME_POINTER_TYPE (f) = cursor;
1881       [[view window] invalidateCursorRectsForView: view];
1882       /* Redisplay assumes this function also draws the changed frame
1883          cursor, but this function doesn't, so do it explicitly.  */
1884       x_update_cursor (f, 1);
1885     }
1890 /* ==========================================================================
1892     Keyboard handling
1894    ========================================================================== */
1897 static unsigned
1898 ns_convert_key (unsigned code)
1899 /* --------------------------------------------------------------------------
1900     Internal call used by NSView-keyDown.
1901    -------------------------------------------------------------------------- */
1903   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1904                                 / sizeof (convert_ns_to_X_keysym[0]));
1905   unsigned keysym;
1906   /* An array would be faster, but less easy to read. */
1907   for (keysym = 0; keysym < last_keysym; keysym += 2)
1908     if (code == convert_ns_to_X_keysym[keysym])
1909       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1910   return 0;
1911 /* if decide to use keyCode and Carbon table, use this line:
1912      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1916 char *
1917 x_get_keysym_name (int keysym)
1918 /* --------------------------------------------------------------------------
1919     Called by keyboard.c.  Not sure if the return val is important, except
1920     that it be unique.
1921    -------------------------------------------------------------------------- */
1923   static char value[16];
1924   NSTRACE (x_get_keysym_name);
1925   sprintf (value, "%d", keysym);
1926   return value;
1931 /* ==========================================================================
1933     Block drawing operations
1935    ========================================================================== */
1938 static void
1939 ns_redraw_scroll_bars (struct frame *f)
1941   int i;
1942   id view;
1943   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1944   NSTRACE (ns_redraw_scroll_bars);
1945   for (i =[subviews count]-1; i >= 0; i--)
1946     {
1947       view = [subviews objectAtIndex: i];
1948       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1949       [view display];
1950     }
1954 void
1955 ns_clear_frame (struct frame *f)
1956 /* --------------------------------------------------------------------------
1957       External (hook): Erase the entire frame
1958    -------------------------------------------------------------------------- */
1960   NSView *view = FRAME_NS_VIEW (f);
1961   NSRect r;
1963   NSTRACE (ns_clear_frame);
1965  /* comes on initial frame because we have
1966     after-make-frame-functions = select-frame */
1967  if (!FRAME_DEFAULT_FACE (f))
1968    return;
1970   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1972   r = [view bounds];
1974   block_input ();
1975   ns_focus (f, &r, 1);
1976   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
1977   NSRectFill (r);
1978   ns_unfocus (f);
1980   /* as of 2006/11 or so this is now needed */
1981   ns_redraw_scroll_bars (f);
1982   unblock_input ();
1986 static void
1987 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
1988 /* --------------------------------------------------------------------------
1989     External (RIF):  Clear section of frame
1990    -------------------------------------------------------------------------- */
1992   NSRect r = NSMakeRect (x, y, width, height);
1993   NSView *view = FRAME_NS_VIEW (f);
1994   struct face *face = FRAME_DEFAULT_FACE (f);
1996   if (!view || !face)
1997     return;
1999   NSTRACE (ns_clear_frame_area);
2001   r = NSIntersectionRect (r, [view frame]);
2002   ns_focus (f, &r, 1);
2003   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2005   NSRectFill (r);
2007   ns_unfocus (f);
2008   return;
2012 static void
2013 ns_scroll_run (struct window *w, struct run *run)
2014 /* --------------------------------------------------------------------------
2015     External (RIF):  Insert or delete n lines at line vpos
2016    -------------------------------------------------------------------------- */
2018   struct frame *f = XFRAME (w->frame);
2019   int x, y, width, height, from_y, to_y, bottom_y;
2021   NSTRACE (ns_scroll_run);
2023   /* begin copy from other terms */
2024   /* Get frame-relative bounding box of the text display area of W,
2025      without mode lines.  Include in this box the left and right
2026      fringe of W.  */
2027   window_box (w, ANY_AREA, &x, &y, &width, &height);
2029   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2030   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2031   bottom_y = y + height;
2033   if (to_y < from_y)
2034     {
2035       /* Scrolling up.  Make sure we don't copy part of the mode
2036          line at the bottom.  */
2037       if (from_y + run->height > bottom_y)
2038         height = bottom_y - from_y;
2039       else
2040         height = run->height;
2041     }
2042   else
2043     {
2044       /* Scrolling down.  Make sure we don't copy over the mode line.
2045          at the bottom.  */
2046       if (to_y + run->height > bottom_y)
2047         height = bottom_y - to_y;
2048       else
2049         height = run->height;
2050     }
2051   /* end copy from other terms */
2053   if (height == 0)
2054       return;
2056   block_input ();
2058   x_clear_cursor (w);
2060   {
2061     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2062     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2063     NSPoint dstOrigin = NSMakePoint (x, to_y);
2065     ns_focus (f, &dstRect, 1);
2066     NSCopyBits (0, srcRect , dstOrigin);
2067     ns_unfocus (f);
2068   }
2070   unblock_input ();
2074 static void
2075 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2076 /* --------------------------------------------------------------------------
2077     External (RIF): preparatory to fringe update after text was updated
2078    -------------------------------------------------------------------------- */
2080   struct frame *f;
2081   int width, height;
2083   NSTRACE (ns_after_update_window_line);
2085   /* begin copy from other terms */
2086   eassert (w);
2088   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2089     desired_row->redraw_fringe_bitmaps_p = 1;
2091   /* When a window has disappeared, make sure that no rest of
2092      full-width rows stays visible in the internal border.  */
2093   if (windows_or_buffers_changed
2094       && desired_row->full_width_p
2095       && (f = XFRAME (w->frame),
2096           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2097           width != 0)
2098       && (height = desired_row->visible_height,
2099           height > 0))
2100     {
2101       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2103       block_input ();
2104       ns_clear_frame_area (f, 0, y, width, height);
2105       ns_clear_frame_area (f,
2106                            FRAME_PIXEL_WIDTH (f) - width,
2107                            y, width, height);
2108       unblock_input ();
2109     }
2113 static void
2114 ns_shift_glyphs_for_insert (struct frame *f,
2115                            int x, int y, int width, int height,
2116                            int shift_by)
2117 /* --------------------------------------------------------------------------
2118     External (RIF): copy an area horizontally, don't worry about clearing src
2119    -------------------------------------------------------------------------- */
2121   NSRect srcRect = NSMakeRect (x, y, width, height);
2122   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2123   NSPoint dstOrigin = dstRect.origin;
2125   NSTRACE (ns_shift_glyphs_for_insert);
2127   ns_focus (f, &dstRect, 1);
2128   NSCopyBits (0, srcRect, dstOrigin);
2129   ns_unfocus (f);
2134 /* ==========================================================================
2136     Character encoding and metrics
2138    ========================================================================== */
2141 static void
2142 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2143 /* --------------------------------------------------------------------------
2144      External (RIF); compute left/right overhang of whole string and set in s
2145    -------------------------------------------------------------------------- */
2147   struct font *font = s->font;
2149   if (s->char2b)
2150     {
2151       struct font_metrics metrics;
2152       unsigned int codes[2];
2153       codes[0] = *(s->char2b);
2154       codes[1] = *(s->char2b + s->nchars - 1);
2156       font->driver->text_extents (font, codes, 2, &metrics);
2157       s->left_overhang = -metrics.lbearing;
2158       s->right_overhang
2159         = metrics.rbearing > metrics.width
2160         ? metrics.rbearing - metrics.width : 0;
2161     }
2162   else
2163     {
2164       s->left_overhang = 0;
2165       if (EQ (font->driver->type, Qns))
2166         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2167           FONT_HEIGHT (font) * 0.2 : 0;
2168       else
2169         s->right_overhang = 0;
2170     }
2175 /* ==========================================================================
2177     Fringe and cursor drawing
2179    ========================================================================== */
2182 extern int max_used_fringe_bitmap;
2183 static void
2184 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2185                       struct draw_fringe_bitmap_params *p)
2186 /* --------------------------------------------------------------------------
2187     External (RIF); fringe-related
2188    -------------------------------------------------------------------------- */
2190   struct frame *f = XFRAME (WINDOW_FRAME (w));
2191   struct face *face = p->face;
2192   static EmacsImage **bimgs = NULL;
2193   static int nBimgs = 0;
2195   /* grow bimgs if needed */
2196   if (nBimgs < max_used_fringe_bitmap)
2197     {
2198       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2199       memset (bimgs + nBimgs, 0,
2200               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2201       nBimgs = max_used_fringe_bitmap;
2202     }
2204   /* Must clip because of partially visible lines.  */
2205   ns_clip_to_row (w, row, ANY_AREA, YES);
2207   if (!p->overlay_p)
2208     {
2209       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2211       /* If the fringe is adjacent to the left (right) scroll bar of a
2212          leftmost (rightmost, respectively) window, then extend its
2213          background to the gap between the fringe and the bar.  */
2214       if ((WINDOW_LEFTMOST_P (w)
2215            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2216           || (WINDOW_RIGHTMOST_P (w)
2217               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2218         {
2219           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2221           if (sb_width > 0)
2222             {
2223               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2224               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2225                                     * FRAME_COLUMN_WIDTH (f));
2227               if (bx < 0)
2228                 {
2229                   /* Bitmap fills the fringe.  */
2230                   if (bar_area_x + bar_area_width == p->x)
2231                     bx = bar_area_x + sb_width;
2232                   else if (p->x + p->wd == bar_area_x)
2233                     bx = bar_area_x;
2234                   if (bx >= 0)
2235                     {
2236                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2238                       nx = bar_area_width - sb_width;
2239                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2240                                                             row->y));
2241                       ny = row->visible_height;
2242                     }
2243                 }
2244               else
2245                 {
2246                   if (bar_area_x + bar_area_width == bx)
2247                     {
2248                       bx = bar_area_x + sb_width;
2249                       nx += bar_area_width - sb_width;
2250                     }
2251                   else if (bx + nx == bar_area_x)
2252                     nx += bar_area_width - sb_width;
2253                 }
2254             }
2255         }
2257       if (bx >= 0 && nx > 0)
2258         {
2259           NSRect r = NSMakeRect (bx, by, nx, ny);
2260           NSRectClip (r);
2261           [ns_lookup_indexed_color (face->background, f) set];
2262           NSRectFill (r);
2263         }
2264     }
2266   if (p->which)
2267     {
2268       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2269       EmacsImage *img = bimgs[p->which - 1];
2271       if (!img)
2272         {
2273           unsigned short *bits = p->bits + p->dh;
2274           int len = p->h;
2275           int i;
2276           unsigned char *cbits = xmalloc (len);
2278           for (i = 0; i < len; i++)
2279             cbits[i] = ~(bits[i] & 0xff);
2280           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2281                                            flip: NO];
2282           bimgs[p->which - 1] = img;
2283           xfree (cbits);
2284         }
2286       NSRectClip (r);
2287       /* Since we composite the bitmap instead of just blitting it, we need
2288          to erase the whole background. */
2289       [ns_lookup_indexed_color(face->background, f) set];
2290       NSRectFill (r);
2291       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2292 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2293       [img drawInRect: r
2294               fromRect: NSZeroRect
2295              operation: NSCompositeSourceOver
2296               fraction: 1.0
2297            respectFlipped: YES
2298                 hints: nil];
2299 #else
2300       {
2301         NSPoint pt = r.origin;
2302         pt.y += p->h;
2303         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2304       }
2305 #endif
2306     }
2307   ns_unfocus (f);
2311 static void
2312 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2313                        int x, int y, enum text_cursor_kinds cursor_type,
2314                        int cursor_width, bool on_p, bool active_p)
2315 /* --------------------------------------------------------------------------
2316      External call (RIF): draw cursor.
2317      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2318    -------------------------------------------------------------------------- */
2320   NSRect r, s;
2321   int fx, fy, h, cursor_height;
2322   struct frame *f = WINDOW_XFRAME (w);
2323   struct glyph *phys_cursor_glyph;
2324   struct glyph *cursor_glyph;
2325   struct face *face;
2326   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2328   /* If cursor is out of bounds, don't draw garbage.  This can happen
2329      in mini-buffer windows when switching between echo area glyphs
2330      and mini-buffer.  */
2332   NSTRACE (dumpcursor);
2334   if (!on_p)
2335     return;
2337   w->phys_cursor_type = cursor_type;
2338   w->phys_cursor_on_p = on_p;
2340   if (cursor_type == NO_CURSOR)
2341     {
2342       w->phys_cursor_width = 0;
2343       return;
2344     }
2346   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2347     {
2348       if (glyph_row->exact_window_width_line_p
2349           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2350         {
2351           glyph_row->cursor_in_fringe_p = 1;
2352           draw_fringe_bitmap (w, glyph_row, 0);
2353         }
2354       return;
2355     }
2357   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2358      (other terminals do it the other way round).  We must set
2359      w->phys_cursor_width to the cursor width.  For bar cursors, that
2360      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2361   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2363   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2364      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2365   if (cursor_type == BAR_CURSOR)
2366     {
2367       if (cursor_width < 1)
2368         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2369       w->phys_cursor_width = cursor_width;
2370     }
2371   /* If we have an HBAR, "cursor_width" MAY specify height. */
2372   else if (cursor_type == HBAR_CURSOR)
2373     {
2374       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2375       fy += h - cursor_height;
2376       h = cursor_height;
2377     }
2379   r.origin.x = fx, r.origin.y = fy;
2380   r.size.height = h;
2381   r.size.width = w->phys_cursor_width;
2383   /* TODO: only needed in rare cases with last-resort font in HELLO..
2384      should we do this more efficiently? */
2385   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2388   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2389   if (face && NS_FACE_BACKGROUND (face)
2390       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2391     {
2392       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2393       hollow_color = FRAME_CURSOR_COLOR (f);
2394     }
2395   else
2396     [FRAME_CURSOR_COLOR (f) set];
2398 #ifdef NS_IMPL_COCOA
2399   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2400            atomic.  Cleaner ways of doing this should be investigated.
2401            One way would be to set a global variable DRAWING_CURSOR
2402            when making the call to draw_phys..(), don't focus in that
2403            case, then move the ns_unfocus() here after that call. */
2404   NSDisableScreenUpdates ();
2405 #endif
2407   switch (cursor_type)
2408     {
2409     case NO_CURSOR:
2410       break;
2411     case FILLED_BOX_CURSOR:
2412       NSRectFill (r);
2413       break;
2414     case HOLLOW_BOX_CURSOR:
2415       NSRectFill (r);
2416       [hollow_color set];
2417       NSRectFill (NSInsetRect (r, 1, 1));
2418       [FRAME_CURSOR_COLOR (f) set];
2419       break;
2420     case HBAR_CURSOR:
2421       NSRectFill (r);
2422       break;
2423     case BAR_CURSOR:
2424       s = r;
2425       /* If the character under cursor is R2L, draw the bar cursor
2426          on the right of its glyph, rather than on the left.  */
2427       cursor_glyph = get_phys_cursor_glyph (w);
2428       if ((cursor_glyph->resolved_level & 1) != 0)
2429         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2431       NSRectFill (s);
2432       break;
2433     }
2434   ns_unfocus (f);
2436   /* draw the character under the cursor */
2437   if (cursor_type != NO_CURSOR)
2438     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2440 #ifdef NS_IMPL_COCOA
2441   NSEnableScreenUpdates ();
2442 #endif
2447 static void
2448 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2449 /* --------------------------------------------------------------------------
2450      External (RIF): Draw a vertical line.
2451    -------------------------------------------------------------------------- */
2453   struct frame *f = XFRAME (WINDOW_FRAME (w));
2454   struct face *face;
2455   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2457   NSTRACE (ns_draw_vertical_window_border);
2459   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2460   if (face)
2461       [ns_lookup_indexed_color(face->foreground, f) set];
2463   ns_focus (f, &r, 1);
2464   NSRectFill(r);
2465   ns_unfocus (f);
2469 void
2470 show_hourglass (struct atimer *timer)
2472   if (hourglass_shown_p)
2473     return;
2475   block_input ();
2477   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2479   hourglass_shown_p = 1;
2480   unblock_input ();
2484 void
2485 hide_hourglass (void)
2487   if (!hourglass_shown_p)
2488     return;
2490   block_input ();
2492   /* TODO: remove NSProgressIndicator from all frames */
2494   hourglass_shown_p = 0;
2495   unblock_input ();
2500 /* ==========================================================================
2502     Glyph drawing operations
2504    ========================================================================== */
2506 static int
2507 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2508 /* --------------------------------------------------------------------------
2509     Wrapper utility to account for internal border width on full-width lines,
2510     and allow top full-width rows to hit the frame top.  nr should be pointer
2511     to two successive NSRects.  Number of rects actually used is returned.
2512    -------------------------------------------------------------------------- */
2514   int n = get_glyph_string_clip_rects (s, nr, 2);
2515   return n;
2518 /* --------------------------------------------------------------------
2519    Draw a wavy line under glyph string s. The wave fills wave_height
2520    pixels from y.
2522                     x          wave_length = 2
2523                                  --
2524                 y    *   *   *   *   *
2525                      |* * * * * * * * *
2526     wave_height = 3  | *   *   *   *
2527   --------------------------------------------------------------------- */
2529 static void
2530 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2532   int wave_height = 3, wave_length = 2;
2533   int y, dx, dy, odd, xmax;
2534   NSPoint a, b;
2535   NSRect waveClip;
2537   dx = wave_length;
2538   dy = wave_height - 1;
2539   y =  s->ybase - wave_height + 3;
2540   xmax = x + width;
2542   /* Find and set clipping rectangle */
2543   waveClip = NSMakeRect (x, y, width, wave_height);
2544   [[NSGraphicsContext currentContext] saveGraphicsState];
2545   NSRectClip (waveClip);
2547   /* Draw the waves */
2548   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2549   b.x = a.x + dx;
2550   odd = (int)(a.x/dx) % 2;
2551   a.y = b.y = y + 0.5;
2553   if (odd)
2554     a.y += dy;
2555   else
2556     b.y += dy;
2558   while (a.x <= xmax)
2559     {
2560       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2561       a.x = b.x, a.y = b.y;
2562       b.x += dx, b.y = y + 0.5 + odd*dy;
2563       odd = !odd;
2564     }
2566   /* Restore previous clipping rectangle(s) */
2567   [[NSGraphicsContext currentContext] restoreGraphicsState];
2572 void
2573 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2574                          NSColor *defaultCol, CGFloat width, CGFloat x)
2575 /* --------------------------------------------------------------------------
2576    Draw underline, overline, and strike-through on glyph string s.
2577    -------------------------------------------------------------------------- */
2579   if (s->for_overlaps)
2580     return;
2582   /* Do underline. */
2583   if (face->underline_p)
2584     {
2585       if (s->face->underline_type == FACE_UNDER_WAVE)
2586         {
2587           if (face->underline_defaulted_p)
2588             [defaultCol set];
2589           else
2590             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2592           ns_draw_underwave (s, width, x);
2593         }
2594       else if (s->face->underline_type == FACE_UNDER_LINE)
2595         {
2597           NSRect r;
2598           unsigned long thickness, position;
2600           /* If the prev was underlined, match its appearance. */
2601           if (s->prev && s->prev->face->underline_p
2602               && s->prev->face->underline_type == FACE_UNDER_LINE
2603               && s->prev->underline_thickness > 0)
2604             {
2605               thickness = s->prev->underline_thickness;
2606               position = s->prev->underline_position;
2607             }
2608           else
2609             {
2610               struct font *font;
2611               unsigned long descent;
2613               font=s->font;
2614               descent = s->y + s->height - s->ybase;
2616               /* Use underline thickness of font, defaulting to 1. */
2617               thickness = (font && font->underline_thickness > 0)
2618                 ? font->underline_thickness : 1;
2620               /* Determine the offset of underlining from the baseline. */
2621               if (x_underline_at_descent_line)
2622                 position = descent - thickness;
2623               else if (x_use_underline_position_properties
2624                        && font && font->underline_position >= 0)
2625                 position = font->underline_position;
2626               else if (font)
2627                 position = lround (font->descent / 2);
2628               else
2629                 position = underline_minimum_offset;
2631               position = max (position, underline_minimum_offset);
2633               /* Ensure underlining is not cropped. */
2634               if (descent <= position)
2635                 {
2636                   position = descent - 1;
2637                   thickness = 1;
2638                 }
2639               else if (descent < position + thickness)
2640                 thickness = 1;
2641             }
2643           s->underline_thickness = thickness;
2644           s->underline_position = position;
2646           r = NSMakeRect (x, s->ybase + position, width, thickness);
2648           if (face->underline_defaulted_p)
2649             [defaultCol set];
2650           else
2651             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2652           NSRectFill (r);
2653         }
2654     }
2655   /* Do overline. We follow other terms in using a thickness of 1
2656      and ignoring overline_margin. */
2657   if (face->overline_p)
2658     {
2659       NSRect r;
2660       r = NSMakeRect (x, s->y, width, 1);
2662       if (face->overline_color_defaulted_p)
2663         [defaultCol set];
2664       else
2665         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2666       NSRectFill (r);
2667     }
2669   /* Do strike-through.  We follow other terms for thickness and
2670      vertical position.*/
2671   if (face->strike_through_p)
2672     {
2673       NSRect r;
2674       unsigned long dy;
2676       dy = lrint ((s->height - 1) / 2);
2677       r = NSMakeRect (x, s->y + dy, width, 1);
2679       if (face->strike_through_color_defaulted_p)
2680         [defaultCol set];
2681       else
2682         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2683       NSRectFill (r);
2684     }
2687 static void
2688 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2689              char left_p, char right_p)
2690 /* --------------------------------------------------------------------------
2691     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2692     Note we can't just use an NSDrawRect command, because of the possibility
2693     of some sides not being drawn, and because the rect will be filled.
2694    -------------------------------------------------------------------------- */
2696   NSRect s = r;
2697   [col set];
2699   /* top, bottom */
2700   s.size.height = thickness;
2701   NSRectFill (s);
2702   s.origin.y += r.size.height - thickness;
2703   NSRectFill (s);
2705   s.size.height = r.size.height;
2706   s.origin.y = r.origin.y;
2708   /* left, right (optional) */
2709   s.size.width = thickness;
2710   if (left_p)
2711     NSRectFill (s);
2712   if (right_p)
2713     {
2714       s.origin.x += r.size.width - thickness;
2715       NSRectFill (s);
2716     }
2720 static void
2721 ns_draw_relief (NSRect r, int thickness, char raised_p,
2722                char top_p, char bottom_p, char left_p, char right_p,
2723                struct glyph_string *s)
2724 /* --------------------------------------------------------------------------
2725     Draw a relief rect inside r, optionally leaving some sides open.
2726     Note we can't just use an NSDrawBezel command, because of the possibility
2727     of some sides not being drawn, and because the rect will be filled.
2728    -------------------------------------------------------------------------- */
2730   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2731   NSColor *newBaseCol = nil;
2732   NSRect sr = r;
2734   NSTRACE (ns_draw_relief);
2736   /* set up colors */
2738   if (s->face->use_box_color_for_shadows_p)
2739     {
2740       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2741     }
2742 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2743            && s->img->pixmap
2744            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2745        {
2746          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2747        } */
2748   else
2749     {
2750       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2751     }
2753   if (newBaseCol == nil)
2754     newBaseCol = [NSColor grayColor];
2756   if (newBaseCol != baseCol)  /* TODO: better check */
2757     {
2758       [baseCol release];
2759       baseCol = [newBaseCol retain];
2760       [lightCol release];
2761       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2762       [darkCol release];
2763       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2764     }
2766   [(raised_p ? lightCol : darkCol) set];
2768   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2770   /* top */
2771   sr.size.height = thickness;
2772   if (top_p) NSRectFill (sr);
2774   /* left */
2775   sr.size.height = r.size.height;
2776   sr.size.width = thickness;
2777   if (left_p) NSRectFill (sr);
2779   [(raised_p ? darkCol : lightCol) set];
2781   /* bottom */
2782   sr.size.width = r.size.width;
2783   sr.size.height = thickness;
2784   sr.origin.y += r.size.height - thickness;
2785   if (bottom_p) NSRectFill (sr);
2787   /* right */
2788   sr.size.height = r.size.height;
2789   sr.origin.y = r.origin.y;
2790   sr.size.width = thickness;
2791   sr.origin.x += r.size.width - thickness;
2792   if (right_p) NSRectFill (sr);
2796 static void
2797 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2798 /* --------------------------------------------------------------------------
2799       Function modeled after x_draw_glyph_string_box ().
2800       Sets up parameters for drawing.
2801    -------------------------------------------------------------------------- */
2803   int right_x, last_x;
2804   char left_p, right_p;
2805   struct glyph *last_glyph;
2806   NSRect r;
2807   int thickness;
2808   struct face *face;
2810   if (s->hl == DRAW_MOUSE_FACE)
2811     {
2812       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2813       if (!face)
2814         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2815     }
2816   else
2817     face = s->face;
2819   thickness = face->box_line_width;
2821   NSTRACE (ns_dumpglyphs_box_or_relief);
2823   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2824             ? WINDOW_RIGHT_EDGE_X (s->w)
2825             : window_box_right (s->w, s->area));
2826   last_glyph = (s->cmp || s->img
2827                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2829   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2830               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2832   left_p = (s->first_glyph->left_box_line_p
2833             || (s->hl == DRAW_MOUSE_FACE
2834                 && (s->prev == NULL || s->prev->hl != s->hl)));
2835   right_p = (last_glyph->right_box_line_p
2836              || (s->hl == DRAW_MOUSE_FACE
2837                  && (s->next == NULL || s->next->hl != s->hl)));
2839   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2841   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2842   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2843     {
2844       ns_draw_box (r, abs (thickness),
2845                    ns_lookup_indexed_color (face->box_color, s->f),
2846                   left_p, right_p);
2847     }
2848   else
2849     {
2850       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2851                      1, 1, left_p, right_p, s);
2852     }
2856 static void
2857 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2858 /* --------------------------------------------------------------------------
2859       Modeled after x_draw_glyph_string_background, which draws BG in
2860       certain cases.  Others are left to the text rendering routine.
2861    -------------------------------------------------------------------------- */
2863   NSTRACE (ns_maybe_dumpglyphs_background);
2865   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2866     {
2867       int box_line_width = max (s->face->box_line_width, 0);
2868       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2869           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2870         {
2871           struct face *face;
2872           if (s->hl == DRAW_MOUSE_FACE)
2873             {
2874               face = FACE_FROM_ID (s->f,
2875                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2876               if (!face)
2877                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2878             }
2879           else
2880             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2881           if (!face->stipple)
2882             [(NS_FACE_BACKGROUND (face) != 0
2883               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2884               : FRAME_BACKGROUND_COLOR (s->f)) set];
2885           else
2886             {
2887               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
2888               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2889             }
2891           if (s->hl != DRAW_CURSOR)
2892             {
2893               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2894                                     s->background_width,
2895                                     s->height-2*box_line_width);
2896               NSRectFill (r);
2897             }
2899           s->background_filled_p = 1;
2900         }
2901     }
2905 static void
2906 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2907 /* --------------------------------------------------------------------------
2908       Renders an image and associated borders.
2909    -------------------------------------------------------------------------- */
2911   EmacsImage *img = s->img->pixmap;
2912   int box_line_vwidth = max (s->face->box_line_width, 0);
2913   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2914   int bg_x, bg_y, bg_height;
2915   int th;
2916   char raised_p;
2917   NSRect br;
2918   struct face *face;
2919   NSColor *tdCol;
2921   NSTRACE (ns_dumpglyphs_image);
2923   if (s->face->box != FACE_NO_BOX
2924       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2925     x += abs (s->face->box_line_width);
2927   bg_x = x;
2928   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2929   bg_height = s->height;
2930   /* other terms have this, but was causing problems w/tabbar mode */
2931   /* - 2 * box_line_vwidth; */
2933   if (s->slice.x == 0) x += s->img->hmargin;
2934   if (s->slice.y == 0) y += s->img->vmargin;
2936   /* Draw BG: if we need larger area than image itself cleared, do that,
2937      otherwise, since we composite the image under NS (instead of mucking
2938      with its background color), we must clear just the image area. */
2939   if (s->hl == DRAW_MOUSE_FACE)
2940     {
2941       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2942       if (!face)
2943        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2944     }
2945   else
2946     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2948   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2950   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2951       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2952     {
2953       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2954       s->background_filled_p = 1;
2955     }
2956   else
2957     {
2958       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2959     }
2961   NSRectFill (br);
2963   /* Draw the image.. do we need to draw placeholder if img ==nil? */
2964   if (img != nil)
2965     {
2966 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2967       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
2968       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
2969                               s->slice.width, s->slice.height);
2970       [img drawInRect: dr
2971              fromRect: ir
2972              operation: NSCompositeSourceOver
2973               fraction: 1.0
2974            respectFlipped: YES
2975                 hints: nil];
2976 #else
2977       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
2978                   operation: NSCompositeSourceOver];
2979 #endif
2980     }
2982   if (s->hl == DRAW_CURSOR)
2983     {
2984     [FRAME_CURSOR_COLOR (s->f) set];
2985     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
2986       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
2987     else
2988       /* Currently on NS img->mask is always 0. Since
2989          get_window_cursor_type specifies a hollow box cursor when on
2990          a non-masked image we never reach this clause. But we put it
2991          in in anticipation of better support for image masks on
2992          NS. */
2993       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
2994     }
2995   else
2996     {
2997       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
2998     }
3000   /* Draw underline, overline, strike-through. */
3001   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3003   /* Draw relief, if requested */
3004   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3005     {
3006       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3007         {
3008           th = tool_bar_button_relief >= 0 ?
3009             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3010           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3011         }
3012       else
3013         {
3014           th = abs (s->img->relief);
3015           raised_p = (s->img->relief > 0);
3016         }
3018       r.origin.x = x - th;
3019       r.origin.y = y - th;
3020       r.size.width = s->slice.width + 2*th-1;
3021       r.size.height = s->slice.height + 2*th-1;
3022       ns_draw_relief (r, th, raised_p,
3023                       s->slice.y == 0,
3024                       s->slice.y + s->slice.height == s->img->height,
3025                       s->slice.x == 0,
3026                       s->slice.x + s->slice.width == s->img->width, s);
3027     }
3029   /* If there is no mask, the background won't be seen,
3030      so draw a rectangle on the image for the cursor.
3031      Do this for all images, getting transparency right is not reliable.  */
3032   if (s->hl == DRAW_CURSOR)
3033     {
3034       int thickness = abs (s->img->relief);
3035       if (thickness == 0) thickness = 1;
3036       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3037     }
3041 static void
3042 ns_dumpglyphs_stretch (struct glyph_string *s)
3044   NSRect r[2];
3045   int n, i;
3046   struct face *face;
3047   NSColor *fgCol, *bgCol;
3049   if (!s->background_filled_p)
3050     {
3051       n = ns_get_glyph_string_clip_rect (s, r);
3052       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3054       ns_focus (s->f, r, n);
3056       if (s->hl == DRAW_MOUSE_FACE)
3057        {
3058          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3059          if (!face)
3060            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3061        }
3062       else
3063        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3065       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3066       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3068       for (i = 0; i < n; ++i)
3069         {
3070           if (!s->row->full_width_p)
3071             {
3072               int overrun, leftoverrun;
3074               /* truncate to avoid overwriting fringe and/or scrollbar */
3075               overrun = max (0, (s->x + s->background_width)
3076                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3077                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3078               r[i].size.width -= overrun;
3080               /* truncate to avoid overwriting to left of the window box */
3081               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3082                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3084               if (leftoverrun > 0)
3085                 {
3086                   r[i].origin.x += leftoverrun;
3087                   r[i].size.width -= leftoverrun;
3088                 }
3090               /* XXX: Try to work between problem where a stretch glyph on
3091                  a partially-visible bottom row will clear part of the
3092                  modeline, and another where list-buffers headers and similar
3093                  rows erroneously have visible_height set to 0.  Not sure
3094                  where this is coming from as other terms seem not to show. */
3095               r[i].size.height = min (s->height, s->row->visible_height);
3096             }
3098           [bgCol set];
3100           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3101              overwriting cursor (usually when cursor on a tab) */
3102           if (s->hl == DRAW_CURSOR)
3103             {
3104               CGFloat x, width;
3106               x = r[i].origin.x;
3107               width = s->w->phys_cursor_width;
3108               r[i].size.width -= width;
3109               r[i].origin.x += width;
3111               NSRectFill (r[i]);
3113               /* Draw overlining, etc. on the cursor. */
3114               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3115                 ns_draw_text_decoration (s, face, bgCol, width, x);
3116               else
3117                 ns_draw_text_decoration (s, face, fgCol, width, x);
3118             }
3119           else
3120             {
3121               NSRectFill (r[i]);
3122             }
3124           /* Draw overlining, etc. on the stretch glyph (or the part
3125              of the stretch glyph after the cursor). */
3126           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3127                                    r[i].origin.x);
3128         }
3129       ns_unfocus (s->f);
3130       s->background_filled_p = 1;
3131     }
3135 static void
3136 ns_draw_glyph_string (struct glyph_string *s)
3137 /* --------------------------------------------------------------------------
3138       External (RIF): Main draw-text call.
3139    -------------------------------------------------------------------------- */
3141   /* TODO (optimize): focus for box and contents draw */
3142   NSRect r[2];
3143   int n, flags;
3144   char box_drawn_p = 0;
3145   struct font *font = s->face->font;
3146   if (! font) font = FRAME_FONT (s->f);
3148   NSTRACE (ns_draw_glyph_string);
3150   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3151     {
3152       int width;
3153       struct glyph_string *next;
3155       for (width = 0, next = s->next;
3156            next && width < s->right_overhang;
3157            width += next->width, next = next->next)
3158         if (next->first_glyph->type != IMAGE_GLYPH)
3159           {
3160             if (next->first_glyph->type != STRETCH_GLYPH)
3161               {
3162                 n = ns_get_glyph_string_clip_rect (s->next, r);
3163                 ns_focus (s->f, r, n);
3164                 ns_maybe_dumpglyphs_background (s->next, 1);
3165                 ns_unfocus (s->f);
3166               }
3167             else
3168               {
3169                 ns_dumpglyphs_stretch (s->next);
3170               }
3171             next->num_clips = 0;
3172           }
3173     }
3175   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3176         && (s->first_glyph->type == CHAR_GLYPH
3177             || s->first_glyph->type == COMPOSITE_GLYPH))
3178     {
3179       n = ns_get_glyph_string_clip_rect (s, r);
3180       ns_focus (s->f, r, n);
3181       ns_maybe_dumpglyphs_background (s, 1);
3182       ns_dumpglyphs_box_or_relief (s);
3183       ns_unfocus (s->f);
3184       box_drawn_p = 1;
3185     }
3187   switch (s->first_glyph->type)
3188     {
3190     case IMAGE_GLYPH:
3191       n = ns_get_glyph_string_clip_rect (s, r);
3192       ns_focus (s->f, r, n);
3193       ns_dumpglyphs_image (s, r[0]);
3194       ns_unfocus (s->f);
3195       break;
3197     case STRETCH_GLYPH:
3198       ns_dumpglyphs_stretch (s);
3199       break;
3201     case CHAR_GLYPH:
3202     case COMPOSITE_GLYPH:
3203       n = ns_get_glyph_string_clip_rect (s, r);
3204       ns_focus (s->f, r, n);
3206       if (s->for_overlaps || (s->cmp_from > 0
3207                               && ! s->first_glyph->u.cmp.automatic))
3208         s->background_filled_p = 1;
3209       else
3210         ns_maybe_dumpglyphs_background
3211           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3213       flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3214         (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3215          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3216           NS_DUMPGLYPH_NORMAL));
3218       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3219         {
3220           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3221           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3222           NS_FACE_FOREGROUND (s->face) = tmp;
3223         }
3225       font->driver->draw
3226         (s, 0, s->nchars, s->x, s->y,
3227          (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3228          || flags == NS_DUMPGLYPH_MOUSEFACE);
3230       {
3231         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3232                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3233                                                    s->f)
3234                         : FRAME_FOREGROUND_COLOR (s->f));
3235         [col set];
3237         /* Draw underline, overline, strike-through. */
3238         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3239       }
3241       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3242         {
3243           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3244           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3245           NS_FACE_FOREGROUND (s->face) = tmp;
3246         }
3248       ns_unfocus (s->f);
3249       break;
3251     case GLYPHLESS_GLYPH:
3252       n = ns_get_glyph_string_clip_rect (s, r);
3253       ns_focus (s->f, r, n);
3255       if (s->for_overlaps || (s->cmp_from > 0
3256                               && ! s->first_glyph->u.cmp.automatic))
3257         s->background_filled_p = 1;
3258       else
3259         ns_maybe_dumpglyphs_background
3260           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3261       /* ... */
3262       /* Not yet implemented.  */
3263       /* ... */
3264       ns_unfocus (s->f);
3265       break;
3267     default:
3268       emacs_abort ();
3269     }
3271   /* Draw box if not done already. */
3272   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3273     {
3274       n = ns_get_glyph_string_clip_rect (s, r);
3275       ns_focus (s->f, r, n);
3276       ns_dumpglyphs_box_or_relief (s);
3277       ns_unfocus (s->f);
3278     }
3280   s->num_clips = 0;
3285 /* ==========================================================================
3287     Event loop
3289    ========================================================================== */
3292 static void
3293 ns_send_appdefined (int value)
3294 /* --------------------------------------------------------------------------
3295     Internal: post an appdefined event which EmacsApp-sendEvent will
3296               recognize and take as a command to halt the event loop.
3297    -------------------------------------------------------------------------- */
3299   /*NSTRACE (ns_send_appdefined); */
3301 #ifdef NS_IMPL_GNUSTEP
3302   // GNUStep needs postEvent to happen on the main thread.
3303   if (! [[NSThread currentThread] isMainThread])
3304     {
3305       EmacsApp *app = (EmacsApp *)NSApp;
3306       app->nextappdefined = value;
3307       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3308                             withObject:nil
3309                          waitUntilDone:YES];
3310       return;
3311     }
3312 #endif
3314   /* Only post this event if we haven't already posted one.  This will end
3315        the [NXApp run] main loop after having processed all events queued at
3316        this moment.  */
3317   if (send_appdefined)
3318     {
3319       NSEvent *nxev;
3321       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3322       send_appdefined = NO;
3324       /* Don't need wakeup timer any more */
3325       if (timed_entry)
3326         {
3327           [timed_entry invalidate];
3328           [timed_entry release];
3329           timed_entry = nil;
3330         }
3332       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3333                                 location: NSMakePoint (0, 0)
3334                            modifierFlags: 0
3335                                timestamp: 0
3336                             windowNumber: [[NSApp mainWindow] windowNumber]
3337                                  context: [NSApp context]
3338                                  subtype: 0
3339                                    data1: value
3340                                    data2: 0];
3342       /* Post an application defined event on the event queue.  When this is
3343          received the [NXApp run] will return, thus having processed all
3344          events which are currently queued.  */
3345       [NSApp postEvent: nxev atStart: NO];
3346     }
3349 #ifdef HAVE_NATIVE_FS
3350 static void
3351 check_native_fs ()
3353   Lisp_Object frame, tail;
3355   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3356     return;
3358   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3360   /* Clear the mouse-moved flag for every frame on this display.  */
3361   FOR_EACH_FRAME (tail, frame)
3362     {
3363       struct frame *f = XFRAME (frame);
3364       if (FRAME_NS_P (f))
3365         {
3366           EmacsView *view = FRAME_NS_VIEW (f);
3367           [view updateCollectionBehaviour];
3368         }
3369     }
3371 #endif
3373 /* GNUStep and OSX <= 10.4 does not have cancelTracking.  */
3374 #if defined (NS_IMPL_COCOA) && \
3375   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
3376 /* Check if menu open should be cancelled or continued as normal.  */
3377 void
3378 ns_check_menu_open (NSMenu *menu)
3380   /* Click in menu bar? */
3381   NSArray *a = [[NSApp mainMenu] itemArray];
3382   int i;
3383   BOOL found = NO;
3385   if (menu == nil) // Menu tracking ended.
3386     {
3387       if (menu_will_open_state == MENU_OPENING)
3388         menu_will_open_state = MENU_NONE;
3389       return;
3390     }
3392   for (i = 0; ! found && i < [a count]; i++)
3393     found = menu == [[a objectAtIndex:i] submenu];
3394   if (found)
3395     {
3396       if (menu_will_open_state == MENU_NONE && emacs_event)
3397         {
3398           NSEvent *theEvent = [NSApp currentEvent];
3399           struct frame *emacsframe = SELECTED_FRAME ();
3401           [menu cancelTracking];
3402           menu_will_open_state = MENU_PENDING;
3403           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3404           EV_TRAILER (theEvent);
3406           CGEventRef ourEvent = CGEventCreate (NULL);
3407           menu_mouse_point = CGEventGetLocation (ourEvent);
3408           CFRelease (ourEvent);
3409         }
3410       else if (menu_will_open_state == MENU_OPENING)
3411         {
3412           menu_will_open_state = MENU_NONE;
3413         }
3414     }
3417 /* Redo saved menu click if state is MENU_PENDING.  */
3418 void
3419 ns_check_pending_open_menu ()
3421   if (menu_will_open_state == MENU_PENDING)
3422     {
3423       CGEventSourceRef source
3424         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3426       CGEventRef event = CGEventCreateMouseEvent (source,
3427                                                   kCGEventLeftMouseDown,
3428                                                   menu_mouse_point,
3429                                                   kCGMouseButtonLeft);
3430       CGEventSetType (event, kCGEventLeftMouseDown);
3431       CGEventPost (kCGHIDEventTap, event);
3432       CFRelease (event);
3433       CFRelease (source);
3435       menu_will_open_state = MENU_OPENING;
3436     }
3438 #endif /* NS_IMPL_COCOA) && >= MAC_OS_X_VERSION_10_5 */
3440 static int
3441 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3442 /* --------------------------------------------------------------------------
3443      External (hook): Post an event to ourself and keep reading events until
3444      we read it back again.  In effect process all events which were waiting.
3445      From 21+ we have to manage the event buffer ourselves.
3446    -------------------------------------------------------------------------- */
3448   struct input_event ev;
3449   int nevents;
3451 /* NSTRACE (ns_read_socket); */
3453 #ifdef HAVE_NATIVE_FS
3454   check_native_fs ();
3455 #endif
3457   if ([NSApp modalWindow] != nil)
3458     return -1;
3460   if (hold_event_q.nr > 0)
3461     {
3462       int i;
3463       for (i = 0; i < hold_event_q.nr; ++i)
3464         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3465       hold_event_q.nr = 0;
3466       return i;
3467     }
3469   block_input ();
3470   n_emacs_events_pending = 0;
3471   EVENT_INIT (ev);
3472   emacs_event = &ev;
3473   q_event_ptr = hold_quit;
3475   /* we manage autorelease pools by allocate/reallocate each time around
3476      the loop; strict nesting is occasionally violated but seems not to
3477      matter.. earlier methods using full nesting caused major memory leaks */
3478   [outerpool release];
3479   outerpool = [[NSAutoreleasePool alloc] init];
3481   /* If have pending open-file requests, attend to the next one of those. */
3482   if (ns_pending_files && [ns_pending_files count] != 0
3483       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3484     {
3485       [ns_pending_files removeObjectAtIndex: 0];
3486     }
3487   /* Deal with pending service requests. */
3488   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3489     && [(EmacsApp *)
3490          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3491                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3492     {
3493       [ns_pending_service_names removeObjectAtIndex: 0];
3494       [ns_pending_service_args removeObjectAtIndex: 0];
3495     }
3496   else
3497     {
3498       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3499          to ourself, otherwise [NXApp run] will never exit.  */
3500       send_appdefined = YES;
3501       ns_send_appdefined (-1);
3503       if (++apploopnr != 1)
3504         {
3505           emacs_abort ();
3506         }
3507       [NSApp run];
3508       --apploopnr;
3509     }
3511   nevents = n_emacs_events_pending;
3512   n_emacs_events_pending = 0;
3513   emacs_event = q_event_ptr = NULL;
3514   unblock_input ();
3516   return nevents;
3521 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3522            fd_set *exceptfds, struct timespec const *timeout,
3523            sigset_t const *sigmask)
3524 /* --------------------------------------------------------------------------
3525      Replacement for select, checking for events
3526    -------------------------------------------------------------------------- */
3528   int result;
3529   int t, k, nr = 0;
3530   struct input_event event;
3531   char c;
3533 /*  NSTRACE (ns_select); */
3535 #ifdef HAVE_NATIVE_FS
3536   check_native_fs ();
3537 #endif
3539   if (hold_event_q.nr > 0)
3540     {
3541       /* We already have events pending. */
3542       raise (SIGIO);
3543       errno = EINTR;
3544       return -1;
3545     }
3547   for (k = 0; k < nfds+1; k++)
3548     {
3549       if (readfds && FD_ISSET(k, readfds)) ++nr;
3550       if (writefds && FD_ISSET(k, writefds)) ++nr;
3551     }
3553   if (NSApp == nil
3554       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3555     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3557   [outerpool release];
3558   outerpool = [[NSAutoreleasePool alloc] init];
3561   send_appdefined = YES;
3562   if (nr > 0)
3563     {
3564       pthread_mutex_lock (&select_mutex);
3565       select_nfds = nfds;
3566       select_valid = 0;
3567       if (readfds)
3568         {
3569           select_readfds = *readfds;
3570           select_valid += SELECT_HAVE_READ;
3571         }
3572       if (writefds)
3573         {
3574           select_writefds = *writefds;
3575           select_valid += SELECT_HAVE_WRITE;
3576         }
3578       if (timeout)
3579         {
3580           select_timeout = *timeout;
3581           select_valid += SELECT_HAVE_TMO;
3582         }
3584       pthread_mutex_unlock (&select_mutex);
3586       /* Inform fd_handler that select should be called */
3587       c = 'g';
3588       emacs_write_sig (selfds[1], &c, 1);
3589     }
3590   else if (nr == 0 && timeout)
3591     {
3592       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3593       double time = timespectod (*timeout);
3594       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3595                                                       target: NSApp
3596                                                     selector:
3597                                   @selector (timeout_handler:)
3598                                                     userInfo: 0
3599                                                      repeats: NO]
3600                       retain];
3601     }
3602   else /* No timeout and no file descriptors, can this happen?  */
3603     {
3604       /* Send appdefined so we exit from the loop */
3605       ns_send_appdefined (-1);
3606     }
3608   EVENT_INIT (event);
3609   block_input ();
3610   emacs_event = &event;
3611   if (++apploopnr != 1)
3612     {
3613       emacs_abort ();
3614     }
3615   [NSApp run];
3616   --apploopnr;
3617   emacs_event = NULL;
3618   if (nr > 0 && readfds)
3619     {
3620       c = 's';
3621       emacs_write_sig (selfds[1], &c, 1);
3622     }
3623   unblock_input ();
3625   t = last_appdefined_event_data;
3627   if (t != NO_APPDEFINED_DATA)
3628     {
3629       last_appdefined_event_data = NO_APPDEFINED_DATA;
3631       if (t == -2)
3632         {
3633           /* The NX_APPDEFINED event we received was a timeout. */
3634           result = 0;
3635         }
3636       else if (t == -1)
3637         {
3638           /* The NX_APPDEFINED event we received was the result of
3639              at least one real input event arriving.  */
3640           errno = EINTR;
3641           result = -1;
3642         }
3643       else
3644         {
3645           /* Received back from select () in fd_handler; copy the results */
3646           pthread_mutex_lock (&select_mutex);
3647           if (readfds) *readfds = select_readfds;
3648           if (writefds) *writefds = select_writefds;
3649           pthread_mutex_unlock (&select_mutex);
3650           result = t;
3651         }
3652     }
3653   else
3654     {
3655       errno = EINTR;
3656       result = -1;
3657     }
3659   return result;
3664 /* ==========================================================================
3666     Scrollbar handling
3668    ========================================================================== */
3671 static void
3672 ns_set_vertical_scroll_bar (struct window *window,
3673                            int portion, int whole, int position)
3674 /* --------------------------------------------------------------------------
3675       External (hook): Update or add scrollbar
3676    -------------------------------------------------------------------------- */
3678   Lisp_Object win;
3679   NSRect r, v;
3680   struct frame *f = XFRAME (WINDOW_FRAME (window));
3681   EmacsView *view = FRAME_NS_VIEW (f);
3682   int window_y, window_height;
3683   int top, left, height, width, sb_width, sb_left;
3684   EmacsScroller *bar;
3685   BOOL fringe_extended_p;
3687   /* optimization; display engine sends WAY too many of these.. */
3688   if (!NILP (window->vertical_scroll_bar))
3689     {
3690       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3691       if ([bar checkSamePosition: position portion: portion whole: whole])
3692         {
3693           if (view->scrollbarsNeedingUpdate == 0)
3694             {
3695               if (!windows_or_buffers_changed)
3696                   return;
3697             }
3698           else
3699             view->scrollbarsNeedingUpdate--;
3700         }
3701     }
3703   NSTRACE (ns_set_vertical_scroll_bar);
3705   /* Get dimensions.  */
3706   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3707   top = window_y;
3708   height = window_height;
3709   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3710   left = WINDOW_SCROLL_BAR_AREA_X (window);
3712   /* allow for displaying a skinnier scrollbar than char area allotted */
3713   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3714     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3715   sb_left = left;
3717   r = NSMakeRect (sb_left, top, sb_width, height);
3718   /* the parent view is flipped, so we need to flip y value */
3719   v = [view frame];
3720   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3722   fringe_extended_p = WINDOW_FRINGE_EXTENDED_P (window);
3724   XSETWINDOW (win, window);
3725   block_input ();
3727   /* we want at least 5 lines to display a scrollbar */
3728   if (WINDOW_TOTAL_LINES (window) < 5)
3729     {
3730       if (!NILP (window->vertical_scroll_bar))
3731         {
3732           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3733           [bar removeFromSuperview];
3734           wset_vertical_scroll_bar (window, Qnil);
3735         }
3736       ns_clear_frame_area (f, sb_left, top, width, height);
3737       unblock_input ();
3738       return;
3739     }
3741   if (NILP (window->vertical_scroll_bar))
3742     {
3743       if (width > 0 && height > 0)
3744         {
3745           if (fringe_extended_p)
3746             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3747           else
3748             ns_clear_frame_area (f, left, top, width, height);
3749         }
3751       bar = [[EmacsScroller alloc] initFrame: r window: win];
3752       wset_vertical_scroll_bar (window, make_save_ptr (bar));
3753     }
3754   else
3755     {
3756       NSRect oldRect;
3757       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3758       oldRect = [bar frame];
3759       r.size.width = oldRect.size.width;
3760       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3761         {
3762           if (oldRect.origin.x != r.origin.x)
3763               ns_clear_frame_area (f, sb_left, top, width, height);
3764           [bar setFrame: r];
3765         }
3766     }
3768   [bar setPosition: position portion: portion whole: whole];
3769   unblock_input ();
3773 static void
3774 ns_condemn_scroll_bars (struct frame *f)
3775 /* --------------------------------------------------------------------------
3776      External (hook): arrange for all frame's scrollbars to be removed
3777      at next call to judge_scroll_bars, except for those redeemed.
3778    -------------------------------------------------------------------------- */
3780   int i;
3781   id view;
3782   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3784   NSTRACE (ns_condemn_scroll_bars);
3786   for (i =[subviews count]-1; i >= 0; i--)
3787     {
3788       view = [subviews objectAtIndex: i];
3789       if ([view isKindOfClass: [EmacsScroller class]])
3790         [view condemn];
3791     }
3795 static void
3796 ns_redeem_scroll_bar (struct window *window)
3797 /* --------------------------------------------------------------------------
3798      External (hook): arrange to spare this window's scrollbar
3799      at next call to judge_scroll_bars.
3800    -------------------------------------------------------------------------- */
3802   id bar;
3803   NSTRACE (ns_redeem_scroll_bar);
3804   if (!NILP (window->vertical_scroll_bar))
3805     {
3806       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3807       [bar reprieve];
3808     }
3812 static void
3813 ns_judge_scroll_bars (struct frame *f)
3814 /* --------------------------------------------------------------------------
3815      External (hook): destroy all scrollbars on frame that weren't
3816      redeemed after call to condemn_scroll_bars.
3817    -------------------------------------------------------------------------- */
3819   int i;
3820   id view;
3821   EmacsView *eview = FRAME_NS_VIEW (f);
3822   NSArray *subviews = [[eview superview] subviews];
3823   BOOL removed = NO;
3825   NSTRACE (ns_judge_scroll_bars);
3826   for (i = [subviews count]-1; i >= 0; --i)
3827     {
3828       view = [subviews objectAtIndex: i];
3829       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3830       [view judge];
3831       removed = YES;
3832     }
3834   if (removed)
3835     [eview updateFrameSize: NO];
3838 /* ==========================================================================
3840     Initialization
3842    ========================================================================== */
3845 x_display_pixel_height (struct ns_display_info *dpyinfo)
3847   NSArray *screens = [NSScreen screens];
3848   NSEnumerator *enumerator = [screens objectEnumerator];
3849   NSScreen *screen;
3850   NSRect frame;
3852   frame = NSZeroRect;
3853   while ((screen = [enumerator nextObject]) != nil)
3854     frame = NSUnionRect (frame, [screen frame]);
3856   return NSHeight (frame);
3860 x_display_pixel_width (struct ns_display_info *dpyinfo)
3862   NSArray *screens = [NSScreen screens];
3863   NSEnumerator *enumerator = [screens objectEnumerator];
3864   NSScreen *screen;
3865   NSRect frame;
3867   frame = NSZeroRect;
3868   while ((screen = [enumerator nextObject]) != nil)
3869     frame = NSUnionRect (frame, [screen frame]);
3871   return NSWidth (frame);
3875 static Lisp_Object ns_string_to_lispmod (const char *s)
3876 /* --------------------------------------------------------------------------
3877      Convert modifier name to lisp symbol
3878    -------------------------------------------------------------------------- */
3880   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3881     return Qmeta;
3882   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3883     return Qsuper;
3884   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3885     return Qcontrol;
3886   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3887     return Qalt;
3888   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3889     return Qhyper;
3890   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3891     return Qnone;
3892   else
3893     return Qnil;
3897 static void
3898 ns_default (const char *parameter, Lisp_Object *result,
3899            Lisp_Object yesval, Lisp_Object noval,
3900            BOOL is_float, BOOL is_modstring)
3901 /* --------------------------------------------------------------------------
3902       Check a parameter value in user's preferences
3903    -------------------------------------------------------------------------- */
3905   const char *value = ns_get_defaults_value (parameter);
3907   if (value)
3908     {
3909       double f;
3910       char *pos;
3911       if (c_strcasecmp (value, "YES") == 0)
3912         *result = yesval;
3913       else if (c_strcasecmp (value, "NO") == 0)
3914         *result = noval;
3915       else if (is_float && (f = strtod (value, &pos), pos != value))
3916         *result = make_float (f);
3917       else if (is_modstring && value)
3918         *result = ns_string_to_lispmod (value);
3919       else fprintf (stderr,
3920                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3921     }
3925 static void
3926 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3927 /* --------------------------------------------------------------------------
3928       Initialize global info and storage for display.
3929    -------------------------------------------------------------------------- */
3931     NSScreen *screen = [NSScreen mainScreen];
3932     NSWindowDepth depth = [screen depth];
3934     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3935     dpyinfo->resy = 72.27;
3936     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3937                                                   NSColorSpaceFromDepth (depth)]
3938                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3939                                                  NSColorSpaceFromDepth (depth)];
3940     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3941     dpyinfo->image_cache = make_image_cache ();
3942     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
3943     dpyinfo->color_table->colors = NULL;
3944     dpyinfo->root_window = 42; /* a placeholder.. */
3945     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3946     dpyinfo->n_fonts = 0;
3947     dpyinfo->smallest_font_height = 1;
3948     dpyinfo->smallest_char_width = 1;
3950     reset_mouse_highlight (&dpyinfo->mouse_highlight);
3954 /* This and next define (many of the) public functions in this file. */
3955 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3956          with using despite presence in the "system dependent" redisplay
3957          interface.  In addition, many of the ns_ methods have code that is
3958          shared with all terms, indicating need for further refactoring. */
3959 extern frame_parm_handler ns_frame_parm_handlers[];
3960 static struct redisplay_interface ns_redisplay_interface =
3962   ns_frame_parm_handlers,
3963   x_produce_glyphs,
3964   x_write_glyphs,
3965   x_insert_glyphs,
3966   x_clear_end_of_line,
3967   ns_scroll_run,
3968   ns_after_update_window_line,
3969   ns_update_window_begin,
3970   ns_update_window_end,
3971   0, /* flush_display */
3972   x_clear_window_mouse_face,
3973   x_get_glyph_overhangs,
3974   x_fix_overlapping_area,
3975   ns_draw_fringe_bitmap,
3976   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3977   0, /* destroy_fringe_bitmap */
3978   ns_compute_glyph_string_overhangs,
3979   ns_draw_glyph_string,
3980   ns_define_frame_cursor,
3981   ns_clear_frame_area,
3982   ns_draw_window_cursor,
3983   ns_draw_vertical_window_border,
3984   ns_shift_glyphs_for_insert
3988 static void
3989 ns_delete_display (struct ns_display_info *dpyinfo)
3991   /* TODO... */
3995 /* This function is called when the last frame on a display is deleted. */
3996 static void
3997 ns_delete_terminal (struct terminal *terminal)
3999   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4001   /* Protect against recursive calls.  delete_frame in
4002      delete_terminal calls us back when it deletes our last frame.  */
4003   if (!terminal->name)
4004     return;
4006   block_input ();
4008   x_destroy_all_bitmaps (dpyinfo);
4009   ns_delete_display (dpyinfo);
4010   unblock_input ();
4014 static struct terminal *
4015 ns_create_terminal (struct ns_display_info *dpyinfo)
4016 /* --------------------------------------------------------------------------
4017       Set up use of NS before we make the first connection.
4018    -------------------------------------------------------------------------- */
4020   struct terminal *terminal;
4022   NSTRACE (ns_create_terminal);
4024   terminal = create_terminal ();
4026   terminal->type = output_ns;
4027   terminal->display_info.ns = dpyinfo;
4028   dpyinfo->terminal = terminal;
4030   terminal->rif = &ns_redisplay_interface;
4032   terminal->clear_frame_hook = ns_clear_frame;
4033   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4034   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
4035   terminal->ring_bell_hook = ns_ring_bell;
4036   terminal->reset_terminal_modes_hook = NULL;
4037   terminal->set_terminal_modes_hook = NULL;
4038   terminal->update_begin_hook = ns_update_begin;
4039   terminal->update_end_hook = ns_update_end;
4040   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4041   terminal->read_socket_hook = ns_read_socket;
4042   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4043   terminal->mouse_position_hook = ns_mouse_position;
4044   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4045   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4047   terminal->fullscreen_hook = ns_fullscreen_hook;
4049   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4050   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4051   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4052   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4054   terminal->delete_frame_hook = x_destroy_window;
4055   terminal->delete_terminal_hook = ns_delete_terminal;
4057   terminal->scroll_region_ok = 1;
4058   terminal->char_ins_del_ok = 1;
4059   terminal->line_ins_del_ok = 1;
4060   terminal->fast_clear_end_of_line = 1;
4061   terminal->memory_below_frame = 0;
4063   return terminal;
4067 struct ns_display_info *
4068 ns_term_init (Lisp_Object display_name)
4069 /* --------------------------------------------------------------------------
4070      Start the Application and get things rolling.
4071    -------------------------------------------------------------------------- */
4073   struct terminal *terminal;
4074   struct ns_display_info *dpyinfo;
4075   static int ns_initialized = 0;
4076   Lisp_Object tmp;
4078   if (ns_initialized) return x_display_list;
4079   ns_initialized = 1;
4081   NSTRACE (ns_term_init);
4083   [outerpool release];
4084   outerpool = [[NSAutoreleasePool alloc] init];
4086   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4087   /*GSDebugAllocationActive (YES); */
4088   block_input ();
4090   baud_rate = 38400;
4091   Fset_input_interrupt_mode (Qnil);
4093   if (selfds[0] == -1)
4094     {
4095       if (emacs_pipe (selfds) != 0)
4096         {
4097           fprintf (stderr, "Failed to create pipe: %s\n",
4098                    emacs_strerror (errno));
4099           emacs_abort ();
4100         }
4102       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4103       FD_ZERO (&select_readfds);
4104       FD_ZERO (&select_writefds);
4105       pthread_mutex_init (&select_mutex, NULL);
4106     }
4108   ns_pending_files = [[NSMutableArray alloc] init];
4109   ns_pending_service_names = [[NSMutableArray alloc] init];
4110   ns_pending_service_args = [[NSMutableArray alloc] init];
4112 /* Start app and create the main menu, window, view.
4113      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4114      The view will then ask the NSApp to stop and return to Emacs. */
4115   [EmacsApp sharedApplication];
4116   if (NSApp == nil)
4117     return NULL;
4118   [NSApp setDelegate: NSApp];
4120   /* Start the select thread.  */
4121   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4122                            toTarget:NSApp
4123                          withObject:nil];
4125   /* debugging: log all notifications */
4126   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4127                                          selector: @selector (logNotification:)
4128                                              name: nil object: nil]; */
4130   dpyinfo = xzalloc (sizeof *dpyinfo);
4132   ns_initialize_display_info (dpyinfo);
4133   terminal = ns_create_terminal (dpyinfo);
4135   terminal->kboard = xmalloc (sizeof *terminal->kboard);
4136   init_kboard (terminal->kboard);
4137   kset_window_system (terminal->kboard, Qns);
4138   terminal->kboard->next_kboard = all_kboards;
4139   all_kboards = terminal->kboard;
4140   /* Don't let the initial kboard remain current longer than necessary.
4141      That would cause problems if a file loaded on startup tries to
4142      prompt in the mini-buffer.  */
4143   if (current_kboard == initial_kboard)
4144     current_kboard = terminal->kboard;
4145   terminal->kboard->reference_count++;
4147   dpyinfo->next = x_display_list;
4148   x_display_list = dpyinfo;
4150   /* Put it on ns_display_name_list */
4151   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4152                                 ns_display_name_list);
4153   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4155   terminal->name = xstrdup (SSDATA (display_name));
4157   unblock_input ();
4159   if (!inhibit_x_resources)
4160     {
4161       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4162                  Qt, Qnil, NO, NO);
4163       tmp = Qnil;
4164       /* this is a standard variable */
4165       ns_default ("AppleAntiAliasingThreshold", &tmp,
4166                  make_float (10.0), make_float (6.0), YES, NO);
4167       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4168     }
4170   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4171                          stringForKey: @"AppleHighlightColor"];
4172   if (ns_selection_color == nil)
4173     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4175   {
4176     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4178     if ( cl == nil )
4179       {
4180         Lisp_Object color_file, color_map, color;
4181         unsigned long c;
4182         char *name;
4184         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4185                          Fsymbol_value (intern ("data-directory")));
4187         color_map = Fx_load_color_file (color_file);
4188         if (NILP (color_map))
4189           fatal ("Could not read %s.\n", SDATA (color_file));
4191         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4192         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4193           {
4194             color = XCAR (color_map);
4195             name = SSDATA (XCAR (color));
4196             c = XINT (XCDR (color));
4197             [cl setColor:
4198                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4199                                             green: GREEN_FROM_ULONG (c) / 255.0
4200                                              blue: BLUE_FROM_ULONG (c) / 255.0
4201                                             alpha: 1.0]
4202                   forKey: [NSString stringWithUTF8String: name]];
4203           }
4204         [cl writeToFile: nil];
4205       }
4206   }
4208   {
4209 #ifdef NS_IMPL_GNUSTEP
4210     Vwindow_system_version = build_string (gnustep_base_version);
4211 #else
4212     /*PSnextrelease (128, c); */
4213     char c[DBL_BUFSIZE_BOUND];
4214     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4215     Vwindow_system_version = make_unibyte_string (c, len);
4216 #endif
4217   }
4219   delete_keyboard_wait_descriptor (0);
4221   ns_app_name = [[NSProcessInfo processInfo] processName];
4223 /* Set up OS X app menu */
4224 #ifdef NS_IMPL_COCOA
4225   {
4226     NSMenu *appMenu;
4227     NSMenuItem *item;
4228     /* set up the application menu */
4229     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4230     [svcsMenu setAutoenablesItems: NO];
4231     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4232     [appMenu setAutoenablesItems: NO];
4233     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4234     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4236     [appMenu insertItemWithTitle: @"About Emacs"
4237                           action: @selector (orderFrontStandardAboutPanel:)
4238                    keyEquivalent: @""
4239                          atIndex: 0];
4240     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4241     [appMenu insertItemWithTitle: @"Preferences..."
4242                           action: @selector (showPreferencesWindow:)
4243                    keyEquivalent: @","
4244                          atIndex: 2];
4245     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4246     item = [appMenu insertItemWithTitle: @"Services"
4247                                  action: @selector (menuDown:)
4248                           keyEquivalent: @""
4249                                 atIndex: 4];
4250     [appMenu setSubmenu: svcsMenu forItem: item];
4251     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4252     [appMenu insertItemWithTitle: @"Hide Emacs"
4253                           action: @selector (hide:)
4254                    keyEquivalent: @"h"
4255                          atIndex: 6];
4256     item =  [appMenu insertItemWithTitle: @"Hide Others"
4257                           action: @selector (hideOtherApplications:)
4258                    keyEquivalent: @"h"
4259                          atIndex: 7];
4260     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4261     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4262     [appMenu insertItemWithTitle: @"Quit Emacs"
4263                           action: @selector (terminate:)
4264                    keyEquivalent: @"q"
4265                          atIndex: 9];
4267     item = [mainMenu insertItemWithTitle: ns_app_name
4268                                   action: @selector (menuDown:)
4269                            keyEquivalent: @""
4270                                  atIndex: 0];
4271     [mainMenu setSubmenu: appMenu forItem: item];
4272     [dockMenu insertItemWithTitle: @"New Frame"
4273                            action: @selector (newFrame:)
4274                     keyEquivalent: @""
4275                           atIndex: 0];
4277     [NSApp setMainMenu: mainMenu];
4278     [NSApp setAppleMenu: appMenu];
4279     [NSApp setServicesMenu: svcsMenu];
4280     /* Needed at least on Cocoa, to get dock menu to show windows */
4281     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4283     [[NSNotificationCenter defaultCenter]
4284       addObserver: mainMenu
4285          selector: @selector (trackingNotification:)
4286              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4287     [[NSNotificationCenter defaultCenter]
4288       addObserver: mainMenu
4289          selector: @selector (trackingNotification:)
4290              name: NSMenuDidEndTrackingNotification object: mainMenu];
4291   }
4292 #endif /* MAC OS X menu setup */
4294   /* Register our external input/output types, used for determining
4295      applicable services and also drag/drop eligibility. */
4296   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4297   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4298                       retain];
4299   ns_drag_types = [[NSArray arrayWithObjects:
4300                             NSStringPboardType,
4301                             NSTabularTextPboardType,
4302                             NSFilenamesPboardType,
4303                             NSURLPboardType,
4304                             NSColorPboardType,
4305                             NSFontPboardType, nil] retain];
4307   /* If fullscreen is in init/default-frame-alist, focus isn't set
4308      right for fullscreen windows, so set this.  */
4309   [NSApp activateIgnoringOtherApps:YES];
4311   [NSApp run];
4312   ns_do_open_file = YES;
4314 #ifdef NS_IMPL_GNUSTEP
4315   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4316      We must re-catch it so subprocess works.  */
4317   catch_child_signal ();
4318 #endif
4319   return dpyinfo;
4323 void
4324 ns_term_shutdown (int sig)
4326   [[NSUserDefaults standardUserDefaults] synchronize];
4328   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4329   if (STRINGP (Vauto_save_list_file_name))
4330     unlink (SSDATA (Vauto_save_list_file_name));
4332   if (sig == 0 || sig == SIGTERM)
4333     {
4334       [NSApp terminate: NSApp];
4335     }
4336   else // force a stack trace to happen
4337     {
4338       emacs_abort ();
4339     }
4343 /* ==========================================================================
4345     EmacsApp implementation
4347    ========================================================================== */
4350 @implementation EmacsApp
4352 - (void)logNotification: (NSNotification *)notification
4354   const char *name = [[notification name] UTF8String];
4355   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4356       && !strstr (name, "WindowNumber"))
4357     NSLog (@"notification: '%@'", [notification name]);
4361 - (void)sendEvent: (NSEvent *)theEvent
4362 /* --------------------------------------------------------------------------
4363      Called when NSApp is running for each event received.  Used to stop
4364      the loop when we choose, since there's no way to just run one iteration.
4365    -------------------------------------------------------------------------- */
4367   int type = [theEvent type];
4368   NSWindow *window = [theEvent window];
4370 /*  NSTRACE (sendEvent); */
4371 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4373 #ifdef NS_IMPL_GNUSTEP
4374   // Keyboard events aren't propagated to file dialogs for some reason.
4375   if ([NSApp modalWindow] != nil &&
4376       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4377     {
4378       [[NSApp modalWindow] sendEvent: theEvent];
4379       return;
4380     }
4381 #endif
4383   if (type == NSApplicationDefined)
4384     {
4385       switch ([theEvent data2])
4386         {
4387 #ifdef NS_IMPL_COCOA
4388         case NSAPP_DATA2_RUNASSCRIPT:
4389           ns_run_ascript ();
4390           [self stop: self];
4391           return;
4392 #endif
4393         case NSAPP_DATA2_RUNFILEDIALOG:
4394           ns_run_file_dialog ();
4395           [self stop: self];
4396           return;
4397         }
4398     }
4400   if (type == NSCursorUpdate && window == nil)
4401     {
4402       fprintf (stderr, "Dropping external cursor update event.\n");
4403       return;
4404     }
4406   if (type == NSApplicationDefined)
4407     {
4408       /* Events posted by ns_send_appdefined interrupt the run loop here.
4409          But, if a modal window is up, an appdefined can still come through,
4410          (e.g., from a makeKeyWindow event) but stopping self also stops the
4411          modal loop. Just defer it until later. */
4412       if ([NSApp modalWindow] == nil)
4413         {
4414           last_appdefined_event_data = [theEvent data1];
4415           [self stop: self];
4416         }
4417       else
4418         {
4419           send_appdefined = YES;
4420         }
4421     }
4424 #ifdef NS_IMPL_COCOA
4425   /* If no dialog and none of our frames have focus and it is a move, skip it.
4426      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4427      such as Wifi, sound, date or similar.
4428      This prevents "spooky" highlighting in the frame under the menu.  */
4429   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4430     {
4431       struct ns_display_info *di;
4432       BOOL has_focus = NO;
4433       for (di = x_display_list; ! has_focus && di; di = di->next)
4434         has_focus = di->x_focus_frame != 0;
4435       if (! has_focus)
4436         return;
4437     }
4438 #endif
4440   [super sendEvent: theEvent];
4444 - (void)showPreferencesWindow: (id)sender
4446   struct frame *emacsframe = SELECTED_FRAME ();
4447   NSEvent *theEvent = [NSApp currentEvent];
4449   if (!emacs_event)
4450     return;
4451   emacs_event->kind = NS_NONKEY_EVENT;
4452   emacs_event->code = KEY_NS_SHOW_PREFS;
4453   emacs_event->modifiers = 0;
4454   EV_TRAILER (theEvent);
4458 - (void)newFrame: (id)sender
4460   struct frame *emacsframe = SELECTED_FRAME ();
4461   NSEvent *theEvent = [NSApp currentEvent];
4463   if (!emacs_event)
4464     return;
4465   emacs_event->kind = NS_NONKEY_EVENT;
4466   emacs_event->code = KEY_NS_NEW_FRAME;
4467   emacs_event->modifiers = 0;
4468   EV_TRAILER (theEvent);
4472 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4473 - (BOOL) openFile: (NSString *)fileName
4475   struct frame *emacsframe = SELECTED_FRAME ();
4476   NSEvent *theEvent = [NSApp currentEvent];
4478   if (!emacs_event)
4479     return NO;
4481   emacs_event->kind = NS_NONKEY_EVENT;
4482   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4483   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4484   ns_input_line = Qnil; /* can be start or cons start,end */
4485   emacs_event->modifiers =0;
4486   EV_TRAILER (theEvent);
4488   return YES;
4492 /* **************************************************************************
4494       EmacsApp delegate implementation
4496    ************************************************************************** */
4498 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4499 /* --------------------------------------------------------------------------
4500      When application is loaded, terminate event loop in ns_term_init
4501    -------------------------------------------------------------------------- */
4503   NSTRACE (applicationDidFinishLaunching);
4504   [NSApp setServicesProvider: NSApp];
4505   ns_send_appdefined (-2);
4509 /* Termination sequences:
4510     C-x C-c:
4511     Cmd-Q:
4512     MenuBar | File | Exit:
4513     Select Quit from App menubar:
4514         -terminate
4515         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4516         ns_term_shutdown()
4518     Select Quit from Dock menu:
4519     Logout attempt:
4520         -appShouldTerminate
4521           Cancel -> Nothing else
4522           Accept ->
4524           -terminate
4525           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4526           ns_term_shutdown()
4530 - (void) terminate: (id)sender
4532   struct frame *emacsframe = SELECTED_FRAME ();
4534   if (!emacs_event)
4535     return;
4537   emacs_event->kind = NS_NONKEY_EVENT;
4538   emacs_event->code = KEY_NS_POWER_OFF;
4539   emacs_event->arg = Qt; /* mark as non-key event */
4540   EV_TRAILER ((id)nil);
4544 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4546   int ret;
4548   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4549     return NSTerminateNow;
4551     ret = NSRunAlertPanel(ns_app_name,
4552                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4553                           @"Save Buffers and Exit", @"Cancel", nil);
4555     if (ret == NSAlertDefaultReturn)
4556         return NSTerminateNow;
4557     else if (ret == NSAlertAlternateReturn)
4558         return NSTerminateCancel;
4559     return NSTerminateNow;  /* just in case */
4562 static int
4563 not_in_argv (NSString *arg)
4565   int k;
4566   const char *a = [arg UTF8String];
4567   for (k = 1; k < initial_argc; ++k)
4568     if (strcmp (a, initial_argv[k]) == 0) return 0;
4569   return 1;
4572 /*   Notification from the Workspace to open a file */
4573 - (BOOL)application: sender openFile: (NSString *)file
4575   if (ns_do_open_file || not_in_argv (file))
4576     [ns_pending_files addObject: file];
4577   return YES;
4581 /*   Open a file as a temporary file */
4582 - (BOOL)application: sender openTempFile: (NSString *)file
4584   if (ns_do_open_file || not_in_argv (file))
4585     [ns_pending_files addObject: file];
4586   return YES;
4590 /*   Notification from the Workspace to open a file noninteractively (?) */
4591 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4593   if (ns_do_open_file || not_in_argv (file))
4594     [ns_pending_files addObject: file];
4595   return YES;
4598 /*   Notification from the Workspace to open multiple files */
4599 - (void)application: sender openFiles: (NSArray *)fileList
4601   NSEnumerator *files = [fileList objectEnumerator];
4602   NSString *file;
4603   /* Don't open files from the command line unconditionally,
4604      Cocoa parses the command line wrong, --option value tries to open value
4605      if --option is the last option.  */
4606   while ((file = [files nextObject]) != nil)
4607     if (ns_do_open_file || not_in_argv (file))
4608       [ns_pending_files addObject: file];
4610   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4615 /* Handle dock menu requests.  */
4616 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4618   return dockMenu;
4622 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4623 - (void)applicationWillBecomeActive: (NSNotification *)notification
4625   //ns_app_active=YES;
4627 - (void)applicationDidBecomeActive: (NSNotification *)notification
4629   NSTRACE (applicationDidBecomeActive);
4631   //ns_app_active=YES;
4633   ns_update_auto_hide_menu_bar ();
4634   // No constraining takes place when the application is not active.
4635   ns_constrain_all_frames ();
4637 - (void)applicationDidResignActive: (NSNotification *)notification
4639   //ns_app_active=NO;
4640   ns_send_appdefined (-1);
4645 /* ==========================================================================
4647     EmacsApp aux handlers for managing event loop
4649    ========================================================================== */
4652 - (void)timeout_handler: (NSTimer *)timedEntry
4653 /* --------------------------------------------------------------------------
4654      The timeout specified to ns_select has passed.
4655    -------------------------------------------------------------------------- */
4657   /*NSTRACE (timeout_handler); */
4658   ns_send_appdefined (-2);
4661 #ifdef NS_IMPL_GNUSTEP
4662 - (void)sendFromMainThread:(id)unused
4664   ns_send_appdefined (nextappdefined);
4666 #endif
4668 - (void)fd_handler:(id)unused
4669 /* --------------------------------------------------------------------------
4670      Check data waiting on file descriptors and terminate if so
4671    -------------------------------------------------------------------------- */
4673   int result;
4674   int waiting = 1, nfds;
4675   char c;
4677   fd_set readfds, writefds, *wfds;
4678   struct timespec timeout, *tmo;
4679   NSAutoreleasePool *pool = nil;
4681   /* NSTRACE (fd_handler); */
4683   for (;;)
4684     {
4685       [pool release];
4686       pool = [[NSAutoreleasePool alloc] init];
4688       if (waiting)
4689         {
4690           fd_set fds;
4691           FD_ZERO (&fds);
4692           FD_SET (selfds[0], &fds);
4693           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4694           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4695             waiting = 0;
4696         }
4697       else
4698         {
4699           pthread_mutex_lock (&select_mutex);
4700           nfds = select_nfds;
4702           if (select_valid & SELECT_HAVE_READ)
4703             readfds = select_readfds;
4704           else
4705             FD_ZERO (&readfds);
4707           if (select_valid & SELECT_HAVE_WRITE)
4708             {
4709               writefds = select_writefds;
4710               wfds = &writefds;
4711             }
4712           else
4713             wfds = NULL;
4714           if (select_valid & SELECT_HAVE_TMO)
4715             {
4716               timeout = select_timeout;
4717               tmo = &timeout;
4718             }
4719           else
4720             tmo = NULL;
4722           pthread_mutex_unlock (&select_mutex);
4724           FD_SET (selfds[0], &readfds);
4725           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4727           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4729           if (result == 0)
4730             ns_send_appdefined (-2);
4731           else if (result > 0)
4732             {
4733               if (FD_ISSET (selfds[0], &readfds))
4734                 {
4735                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4736                     waiting = 1;
4737                 }
4738               else
4739                 {
4740                   pthread_mutex_lock (&select_mutex);
4741                   if (select_valid & SELECT_HAVE_READ)
4742                     select_readfds = readfds;
4743                   if (select_valid & SELECT_HAVE_WRITE)
4744                     select_writefds = writefds;
4745                   if (select_valid & SELECT_HAVE_TMO)
4746                     select_timeout = timeout;
4747                   pthread_mutex_unlock (&select_mutex);
4749                   ns_send_appdefined (result);
4750                 }
4751             }
4752           waiting = 1;
4753         }
4754     }
4759 /* ==========================================================================
4761     Service provision
4763    ========================================================================== */
4765 /* called from system: queue for next pass through event loop */
4766 - (void)requestService: (NSPasteboard *)pboard
4767               userData: (NSString *)userData
4768                  error: (NSString **)error
4770   [ns_pending_service_names addObject: userData];
4771   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4772       SSDATA (ns_string_from_pasteboard (pboard))]];
4776 /* called from ns_read_socket to clear queue */
4777 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4779   struct frame *emacsframe = SELECTED_FRAME ();
4780   NSEvent *theEvent = [NSApp currentEvent];
4782   if (!emacs_event)
4783     return NO;
4785   emacs_event->kind = NS_NONKEY_EVENT;
4786   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4787   ns_input_spi_name = build_string ([name UTF8String]);
4788   ns_input_spi_arg = build_string ([arg UTF8String]);
4789   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4790   EV_TRAILER (theEvent);
4792   return YES;
4796 @end  /* EmacsApp */
4800 /* ==========================================================================
4802     EmacsView implementation
4804    ========================================================================== */
4807 @implementation EmacsView
4809 /* needed to inform when window closed from LISP */
4810 - (void) setWindowClosing: (BOOL)closing
4812   windowClosing = closing;
4816 - (void)dealloc
4818   NSTRACE (EmacsView_dealloc);
4819   [toolbar release];
4820   if (fs_state == FULLSCREEN_BOTH)
4821     [nonfs_window release];
4822   [super dealloc];
4826 /* called on font panel selection */
4827 - (void)changeFont: (id)sender
4829   NSEvent *e = [[self window] currentEvent];
4830   struct face *face = FRAME_DEFAULT_FACE (emacsframe);
4831   struct font *font = face->font;
4832   id newFont;
4833   CGFloat size;
4834   NSFont *nsfont;
4836   NSTRACE (changeFont);
4838   if (!emacs_event)
4839     return;
4841   if (EQ (font->driver->type, Qns))
4842     nsfont = ((struct nsfont_info *)font)->nsfont;
4843 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
4844   else
4845     nsfont = (NSFont *) macfont_get_nsctfont (font);
4846 #endif
4848   if ((newFont = [sender convertFont: nsfont]))
4849     {
4850       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4852       emacs_event->kind = NS_NONKEY_EVENT;
4853       emacs_event->modifiers = 0;
4854       emacs_event->code = KEY_NS_CHANGE_FONT;
4856       size = [newFont pointSize];
4857       ns_input_fontsize = make_number (lrint (size));
4858       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4859       EV_TRAILER (e);
4860     }
4864 - (BOOL)acceptsFirstResponder
4866   NSTRACE (acceptsFirstResponder);
4867   return YES;
4871 - (void)resetCursorRects
4873   NSRect visible = [self visibleRect];
4874   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4875   NSTRACE (resetCursorRects);
4877   if (currentCursor == nil)
4878     currentCursor = [NSCursor arrowCursor];
4880   if (!NSIsEmptyRect (visible))
4881     [self addCursorRect: visible cursor: currentCursor];
4882   [currentCursor setOnMouseEntered: YES];
4887 /*****************************************************************************/
4888 /* Keyboard handling. */
4889 #define NS_KEYLOG 0
4891 - (void)keyDown: (NSEvent *)theEvent
4893   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4894   int code;
4895   unsigned fnKeysym = 0;
4896   static NSMutableArray *nsEvArray;
4897 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4898   static BOOL firstTime = YES;
4899 #endif
4900   int left_is_none;
4901   unsigned int flags = [theEvent modifierFlags];
4903   NSTRACE (keyDown);
4905   /* Rhapsody and OS X give up and down events for the arrow keys */
4906   if (ns_fake_keydown == YES)
4907     ns_fake_keydown = NO;
4908   else if ([theEvent type] != NSKeyDown)
4909     return;
4911   if (!emacs_event)
4912     return;
4914  if (![[self window] isKeyWindow]
4915      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4916      /* we must avoid an infinite loop here. */
4917      && (EmacsView *)[[theEvent window] delegate] != self)
4918    {
4919      /* XXX: There is an occasional condition in which, when Emacs display
4920          updates a different frame from the current one, and temporarily
4921          selects it, then processes some interrupt-driven input
4922          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4923          for some reason that window has its first responder set to the NSView
4924          most recently updated (I guess), which is not the correct one. */
4925      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4926      return;
4927    }
4929   if (nsEvArray == nil)
4930     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4932   [NSCursor setHiddenUntilMouseMoves: YES];
4934   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4935     {
4936       clear_mouse_face (hlinfo);
4937       hlinfo->mouse_face_hidden = 1;
4938     }
4940   if (!processingCompose)
4941     {
4942       /* When using screen sharing, no left or right information is sent,
4943          so use Left key in those cases.  */
4944       int is_left_key, is_right_key;
4946       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4947         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4949       /* (Carbon way: [theEvent keyCode]) */
4951       /* is it a "function key"? */
4952       fnKeysym = (code < 0x00ff && (flags&NSNumericPadKeyMask))
4953         ? ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask)
4954         : ns_convert_key (code);
4956       if (fnKeysym)
4957         {
4958           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4959              because Emacs treats Delete and KP-Delete same (in simple.el). */
4960           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4961 #ifdef NS_IMPL_GNUSTEP
4962               /*  GNUstep uses incompatible keycodes, even for those that are
4963                   supposed to be hardware independent.  Just check for delete.
4964                   Keypad delete does not have keysym 0xFFFF.
4965                   See http://savannah.gnu.org/bugs/?25395
4966               */
4967               || (fnKeysym == 0xFFFF && code == 127)
4968 #endif
4969             )
4970             code = 0xFF08; /* backspace */
4971           else
4972             code = fnKeysym;
4973         }
4975       /* are there modifiers? */
4976       emacs_event->modifiers = 0;
4978       if (flags & NSHelpKeyMask)
4979           emacs_event->modifiers |= hyper_modifier;
4981       if (flags & NSShiftKeyMask)
4982         emacs_event->modifiers |= shift_modifier;
4984       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
4985       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
4986         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
4988       if (is_right_key)
4989         emacs_event->modifiers |= parse_solitary_modifier
4990           (EQ (ns_right_command_modifier, Qleft)
4991            ? ns_command_modifier
4992            : ns_right_command_modifier);
4994       if (is_left_key)
4995         {
4996           emacs_event->modifiers |= parse_solitary_modifier
4997             (ns_command_modifier);
4999           /* if super (default), take input manager's word so things like
5000              dvorak / qwerty layout work */
5001           if (EQ (ns_command_modifier, Qsuper)
5002               && !fnKeysym
5003               && [[theEvent characters] length] != 0)
5004             {
5005               /* XXX: the code we get will be unshifted, so if we have
5006                  a shift modifier, must convert ourselves */
5007               if (!(flags & NSShiftKeyMask))
5008                 code = [[theEvent characters] characterAtIndex: 0];
5009 #if 0
5010               /* this is ugly and also requires linking w/Carbon framework
5011                  (for LMGetKbdType) so for now leave this rare (?) case
5012                  undealt with.. in future look into CGEvent methods */
5013               else
5014                 {
5015                   long smv = GetScriptManagerVariable (smKeyScript);
5016                   Handle uchrHandle = GetResource
5017                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5018                   UInt32 dummy = 0;
5019                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5020                                  [[theEvent characters] characterAtIndex: 0],
5021                                  kUCKeyActionDisplay,
5022                                  (flags & ~NSCommandKeyMask) >> 8,
5023                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5024                                  &dummy, 1, &dummy, &code);
5025                   code &= 0xFF;
5026                 }
5027 #endif
5028             }
5029         }
5031       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5032       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5033         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5035       if (is_right_key)
5036           emacs_event->modifiers |= parse_solitary_modifier
5037               (EQ (ns_right_control_modifier, Qleft)
5038                ? ns_control_modifier
5039                : ns_right_control_modifier);
5041       if (is_left_key)
5042         emacs_event->modifiers |= parse_solitary_modifier
5043           (ns_control_modifier);
5045       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5046           emacs_event->modifiers |=
5047             parse_solitary_modifier (ns_function_modifier);
5049       left_is_none = NILP (ns_alternate_modifier)
5050         || EQ (ns_alternate_modifier, Qnone);
5052       is_right_key = (flags & NSRightAlternateKeyMask)
5053         == NSRightAlternateKeyMask;
5054       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5055         || (! is_right_key
5056             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5058       if (is_right_key)
5059         {
5060           if ((NILP (ns_right_alternate_modifier)
5061                || EQ (ns_right_alternate_modifier, Qnone)
5062                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5063               && !fnKeysym)
5064             {   /* accept pre-interp alt comb */
5065               if ([[theEvent characters] length] > 0)
5066                 code = [[theEvent characters] characterAtIndex: 0];
5067               /*HACK: clear lone shift modifier to stop next if from firing */
5068               if (emacs_event->modifiers == shift_modifier)
5069                 emacs_event->modifiers = 0;
5070             }
5071           else
5072             emacs_event->modifiers |= parse_solitary_modifier
5073               (EQ (ns_right_alternate_modifier, Qleft)
5074                ? ns_alternate_modifier
5075                : ns_right_alternate_modifier);
5076         }
5078       if (is_left_key) /* default = meta */
5079         {
5080           if (left_is_none && !fnKeysym)
5081             {   /* accept pre-interp alt comb */
5082               if ([[theEvent characters] length] > 0)
5083                 code = [[theEvent characters] characterAtIndex: 0];
5084               /*HACK: clear lone shift modifier to stop next if from firing */
5085               if (emacs_event->modifiers == shift_modifier)
5086                 emacs_event->modifiers = 0;
5087             }
5088           else
5089               emacs_event->modifiers |=
5090                 parse_solitary_modifier (ns_alternate_modifier);
5091         }
5093   if (NS_KEYLOG)
5094     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5095              code, fnKeysym, flags, emacs_event->modifiers);
5097       /* if it was a function key or had modifiers, pass it directly to emacs */
5098       if (fnKeysym || (emacs_event->modifiers
5099                        && (emacs_event->modifiers != shift_modifier)
5100                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5101 /*[[theEvent characters] length] */
5102         {
5103           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5104           if (code < 0x20)
5105             code |= (1<<28)|(3<<16);
5106           else if (code == 0x7f)
5107             code |= (1<<28)|(3<<16);
5108           else if (!fnKeysym)
5109             emacs_event->kind = code > 0xFF
5110               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5112           emacs_event->code = code;
5113           EV_TRAILER (theEvent);
5114           processingCompose = NO;
5115           return;
5116         }
5117     }
5120 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5121   /* if we get here we should send the key for input manager processing */
5122   /* Disable warning, there is nothing a user can do about it anyway, and
5123      it does not seem to matter.  */
5124 #if 0
5125   if (firstTime && [[NSInputManager currentInputManager]
5126                      wantsToDelayTextChangeNotifications] == NO)
5127     fprintf (stderr,
5128           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5129 #endif
5130   firstTime = NO;
5131 #endif
5132   if (NS_KEYLOG && !processingCompose)
5133     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5135   processingCompose = YES;
5136   [nsEvArray addObject: theEvent];
5137   [self interpretKeyEvents: nsEvArray];
5138   [nsEvArray removeObject: theEvent];
5142 #ifdef NS_IMPL_COCOA
5143 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5144    decided not to send key-down for.
5145    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5146    This only applies on Tiger and earlier.
5147    If it matches one of these, send it on to keyDown. */
5148 -(void)keyUp: (NSEvent *)theEvent
5150   int flags = [theEvent modifierFlags];
5151   int code = [theEvent keyCode];
5152   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5153       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5154     {
5155       if (NS_KEYLOG)
5156         fprintf (stderr, "keyUp: passed test");
5157       ns_fake_keydown = YES;
5158       [self keyDown: theEvent];
5159     }
5161 #endif
5164 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5167 /* <NSTextInput>: called when done composing;
5168    NOTE: also called when we delete over working text, followed immed.
5169          by doCommandBySelector: deleteBackward: */
5170 - (void)insertText: (id)aString
5172   int code;
5173   int len = [(NSString *)aString length];
5174   int i;
5176   if (NS_KEYLOG)
5177     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5178   processingCompose = NO;
5180   if (!emacs_event)
5181     return;
5183   /* first, clear any working text */
5184   if (workingText != nil)
5185     [self deleteWorkingText];
5187   /* now insert the string as keystrokes */
5188   for (i =0; i<len; i++)
5189     {
5190       code = [aString characterAtIndex: i];
5191       /* TODO: still need this? */
5192       if (code == 0x2DC)
5193         code = '~'; /* 0x7E */
5194       if (code != 32) /* Space */
5195         emacs_event->modifiers = 0;
5196       emacs_event->kind
5197         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5198       emacs_event->code = code;
5199       EV_TRAILER ((id)nil);
5200     }
5204 /* <NSTextInput>: inserts display of composing characters */
5205 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5207   NSString *str = [aString respondsToSelector: @selector (string)] ?
5208     [aString string] : aString;
5209   if (NS_KEYLOG)
5210     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
5211            selRange.length, selRange.location);
5213   if (workingText != nil)
5214     [self deleteWorkingText];
5215   if ([str length] == 0)
5216     return;
5218   if (!emacs_event)
5219     return;
5221   processingCompose = YES;
5222   workingText = [str copy];
5223   ns_working_text = build_string ([workingText UTF8String]);
5225   emacs_event->kind = NS_TEXT_EVENT;
5226   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5227   EV_TRAILER ((id)nil);
5231 /* delete display of composing characters [not in <NSTextInput>] */
5232 - (void)deleteWorkingText
5234   if (workingText == nil)
5235     return;
5236   if (NS_KEYLOG)
5237     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
5238   [workingText release];
5239   workingText = nil;
5240   processingCompose = NO;
5242   if (!emacs_event)
5243     return;
5245   emacs_event->kind = NS_TEXT_EVENT;
5246   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5247   EV_TRAILER ((id)nil);
5251 - (BOOL)hasMarkedText
5253   return workingText != nil;
5257 - (NSRange)markedRange
5259   NSRange rng = workingText != nil
5260     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5261   if (NS_KEYLOG)
5262     NSLog (@"markedRange request");
5263   return rng;
5267 - (void)unmarkText
5269   if (NS_KEYLOG)
5270     NSLog (@"unmark (accept) text");
5271   [self deleteWorkingText];
5272   processingCompose = NO;
5276 /* used to position char selection windows, etc. */
5277 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5279   NSRect rect;
5280   NSPoint pt;
5281   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5282   if (NS_KEYLOG)
5283     NSLog (@"firstRectForCharRange request");
5285   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5286   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5287   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5288   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5289                                        +FRAME_LINE_HEIGHT (emacsframe));
5291   pt = [self convertPoint: pt toView: nil];
5292   pt = [[self window] convertBaseToScreen: pt];
5293   rect.origin = pt;
5294   return rect;
5298 - (NSInteger)conversationIdentifier
5300   return (NSInteger)self;
5304 - (void)doCommandBySelector: (SEL)aSelector
5306   if (NS_KEYLOG)
5307     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5309   processingCompose = NO;
5310   if (aSelector == @selector (deleteBackward:))
5311     {
5312       /* happens when user backspaces over an ongoing composition:
5313          throw a 'delete' into the event queue */
5314       if (!emacs_event)
5315         return;
5316       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5317       emacs_event->code = 0xFF08;
5318       EV_TRAILER ((id)nil);
5319     }
5322 - (NSArray *)validAttributesForMarkedText
5324   static NSArray *arr = nil;
5325   if (arr == nil) arr = [NSArray new];
5326  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5327   return arr;
5330 - (NSRange)selectedRange
5332   if (NS_KEYLOG)
5333     NSLog (@"selectedRange request");
5334   return NSMakeRange (NSNotFound, 0);
5337 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5338     GNUSTEP_GUI_MINOR_VERSION > 22
5339 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5340 #else
5341 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5342 #endif
5344   if (NS_KEYLOG)
5345     NSLog (@"characterIndexForPoint request");
5346   return 0;
5349 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5351   static NSAttributedString *str = nil;
5352   if (str == nil) str = [NSAttributedString new];
5353   if (NS_KEYLOG)
5354     NSLog (@"attributedSubstringFromRange request");
5355   return str;
5358 /* End <NSTextInput> impl. */
5359 /*****************************************************************************/
5362 /* This is what happens when the user presses a mouse button.  */
5363 - (void)mouseDown: (NSEvent *)theEvent
5365   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5367   NSTRACE (mouseDown);
5369   [self deleteWorkingText];
5371   if (!emacs_event)
5372     return;
5374   last_mouse_frame = emacsframe;
5375   /* appears to be needed to prevent spurious movement events generated on
5376      button clicks */
5377   last_mouse_frame->mouse_moved = 0;
5379   if ([theEvent type] == NSScrollWheel)
5380     {
5381       CGFloat delta = [theEvent deltaY];
5382       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5383       if (delta == 0)
5384         return;
5385       emacs_event->kind = WHEEL_EVENT;
5386       emacs_event->code = 0;
5387       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5388         ((delta > 0) ? up_modifier : down_modifier);
5389     }
5390   else
5391     {
5392       emacs_event->kind = MOUSE_CLICK_EVENT;
5393       emacs_event->code = EV_BUTTON (theEvent);
5394       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5395                              | EV_UDMODIFIERS (theEvent);
5396     }
5397   XSETINT (emacs_event->x, lrint (p.x));
5398   XSETINT (emacs_event->y, lrint (p.y));
5399   EV_TRAILER (theEvent);
5403 - (void)rightMouseDown: (NSEvent *)theEvent
5405   NSTRACE (rightMouseDown);
5406   [self mouseDown: theEvent];
5410 - (void)otherMouseDown: (NSEvent *)theEvent
5412   NSTRACE (otherMouseDown);
5413   [self mouseDown: theEvent];
5417 - (void)mouseUp: (NSEvent *)theEvent
5419   NSTRACE (mouseUp);
5420   [self mouseDown: theEvent];
5424 - (void)rightMouseUp: (NSEvent *)theEvent
5426   NSTRACE (rightMouseUp);
5427   [self mouseDown: theEvent];
5431 - (void)otherMouseUp: (NSEvent *)theEvent
5433   NSTRACE (otherMouseUp);
5434   [self mouseDown: theEvent];
5438 - (void) scrollWheel: (NSEvent *)theEvent
5440   NSTRACE (scrollWheel);
5441   [self mouseDown: theEvent];
5445 /* Tell emacs the mouse has moved. */
5446 - (void)mouseMoved: (NSEvent *)e
5448   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5449   Lisp_Object frame;
5451 //  NSTRACE (mouseMoved);
5453   last_mouse_movement_time = EV_TIMESTAMP (e);
5454   last_mouse_motion_position
5455     = [self convertPoint: [e locationInWindow] fromView: nil];
5457   /* update any mouse face */
5458   if (hlinfo->mouse_face_hidden)
5459     {
5460       hlinfo->mouse_face_hidden = 0;
5461       clear_mouse_face (hlinfo);
5462     }
5464   /* tooltip handling */
5465   previous_help_echo_string = help_echo_string;
5466   help_echo_string = Qnil;
5468   if (!NILP (Vmouse_autoselect_window))
5469     {
5470       NSTRACE (mouse_autoselect_window);
5471       static Lisp_Object last_mouse_window;
5472       Lisp_Object window = window_from_coordinates
5473         (emacsframe, last_mouse_motion_position.x,
5474          last_mouse_motion_position.y, 0, 0);
5476       if (WINDOWP (window)
5477           && !EQ (window, last_mouse_window)
5478           && !EQ (window, selected_window)
5479           && (focus_follows_mouse
5480               || (EQ (XWINDOW (window)->frame,
5481                       XWINDOW (selected_window)->frame))))
5482         {
5483           NSTRACE (in_window);
5484           emacs_event->kind = SELECT_WINDOW_EVENT;
5485           emacs_event->frame_or_window = window;
5486           EV_TRAILER2 (e);
5487         }
5488       /* Remember the last window where we saw the mouse.  */
5489       last_mouse_window = window;
5490     }
5492   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5493                             last_mouse_motion_position.y))
5494     help_echo_string = previous_help_echo_string;
5496   XSETFRAME (frame, emacsframe);
5497   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5498     {
5499       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5500          (note_mouse_highlight), which is called through the
5501          note_mouse_movement () call above */
5502       gen_help_event (help_echo_string, frame, help_echo_window,
5503                       help_echo_object, help_echo_pos);
5504     }
5505   else
5506     {
5507       help_echo_string = Qnil;
5508       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5509     }
5511   if (emacsframe->mouse_moved && send_appdefined)
5512     ns_send_appdefined (-1);
5516 - (void)mouseDragged: (NSEvent *)e
5518   NSTRACE (mouseDragged);
5519   [self mouseMoved: e];
5523 - (void)rightMouseDragged: (NSEvent *)e
5525   NSTRACE (rightMouseDragged);
5526   [self mouseMoved: e];
5530 - (void)otherMouseDragged: (NSEvent *)e
5532   NSTRACE (otherMouseDragged);
5533   [self mouseMoved: e];
5537 - (BOOL)windowShouldClose: (id)sender
5539   NSEvent *e =[[self window] currentEvent];
5541   NSTRACE (windowShouldClose);
5542   windowClosing = YES;
5543   if (!emacs_event)
5544     return NO;
5545   emacs_event->kind = DELETE_WINDOW_EVENT;
5546   emacs_event->modifiers = 0;
5547   emacs_event->code = 0;
5548   EV_TRAILER (e);
5549   /* Don't close this window, let this be done from lisp code.  */
5550   return NO;
5553 - (void) updateFrameSize: (BOOL) delay;
5555   NSWindow *window = [self window];
5556   NSRect wr = [window frame];
5557   int extra = 0;
5558   int gsextra = 0;
5559 #ifdef NS_IMPL_GNUSTEP
5560   gsextra = 3;
5561 #endif
5563   int oldc = cols, oldr = rows;
5564   int oldw = FRAME_PIXEL_WIDTH (emacsframe),
5565     oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5566   int neww, newh;
5568   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, wr.size.width + gsextra);
5570   if (cols < MINWIDTH)
5571     cols = MINWIDTH;
5573   if (! [self isFullscreen])
5574     {
5575       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5576         + FRAME_TOOLBAR_HEIGHT (emacsframe) - gsextra;
5577     }
5579   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, wr.size.height - extra);
5581   if (rows < MINHEIGHT)
5582     rows = MINHEIGHT;
5584   neww = (int)wr.size.width - emacsframe->border_width;
5585   newh = (int)wr.size.height - extra;
5587   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5588     {
5589       NSView *view = FRAME_NS_VIEW (emacsframe);
5590       NSWindow *win = [view window];
5591       NSSize sz = [win resizeIncrements];
5593       FRAME_PIXEL_WIDTH (emacsframe) = neww;
5594       FRAME_PIXEL_HEIGHT (emacsframe) = newh;
5595       change_frame_size (emacsframe, rows, cols, 0, delay, 0);
5596       SET_FRAME_GARBAGED (emacsframe);
5597       cancel_mouse_face (emacsframe);
5599       // Did resize increments change because of a font change?
5600       if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5601           sz.height != FRAME_LINE_HEIGHT (emacsframe))
5602         {
5603           sz.width = FRAME_COLUMN_WIDTH (emacsframe);
5604           sz.height = FRAME_LINE_HEIGHT (emacsframe);
5605           [win setResizeIncrements: sz];
5606         }
5608       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5609       [self windowDidMove:nil];   // Update top/left.
5610     }
5613 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5614 /* normalize frame to gridded text size */
5616   int extra = 0;
5617   int gsextra = 0;
5618 #ifdef NS_IMPL_GNUSTEP
5619   gsextra = 3;
5620 #endif
5622   NSTRACE (windowWillResize);
5623 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5625   if (fs_state == FULLSCREEN_MAXIMIZED
5626       && (maximized_width != (int)frameSize.width
5627           || maximized_height != (int)frameSize.height))
5628     [self setFSValue: FULLSCREEN_NONE];
5629   else if (fs_state == FULLSCREEN_WIDTH
5630            && maximized_width != (int)frameSize.width)
5631     [self setFSValue: FULLSCREEN_NONE];
5632   else if (fs_state == FULLSCREEN_HEIGHT
5633            && maximized_height != (int)frameSize.height)
5634     [self setFSValue: FULLSCREEN_NONE];
5635   if (fs_state == FULLSCREEN_NONE)
5636     maximized_width = maximized_height = -1;
5638   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5639                                          frameSize.width + gsextra);
5640   if (cols < MINWIDTH)
5641     cols = MINWIDTH;
5643   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5644                                            frameSize.height - extra);
5645   if (rows < MINHEIGHT)
5646     rows = MINHEIGHT;
5647 #ifdef NS_IMPL_COCOA
5648   {
5649     /* this sets window title to have size in it; the wm does this under GS */
5650     NSRect r = [[self window] frame];
5651     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5652       {
5653         if (old_title != 0)
5654           {
5655             xfree (old_title);
5656             old_title = 0;
5657           }
5658       }
5659     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5660       {
5661         char *size_title;
5662         NSWindow *window = [self window];
5663         if (old_title == 0)
5664           {
5665             char *t = strdup ([[[self window] title] UTF8String]);
5666             char *pos = strstr (t, "  â€”  ");
5667             if (pos)
5668               *pos = '\0';
5669             old_title = t;
5670           }
5671         size_title = xmalloc (strlen (old_title) + 40);
5672         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5673         [window setTitle: [NSString stringWithUTF8String: size_title]];
5674         [window display];
5675         xfree (size_title);
5676       }
5677   }
5678 #endif /* NS_IMPL_COCOA */
5679 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5681   return frameSize;
5685 - (void)windowDidResize: (NSNotification *)notification
5687   if (! [self fsIsNative])
5688     {
5689       NSWindow *theWindow = [notification object];
5690       /* We can get notification on the non-FS window when in
5691          fullscreen mode.  */
5692       if ([self window] != theWindow) return;
5693     }
5695 #ifdef NS_IMPL_GNUSTEP
5696   NSWindow *theWindow = [notification object];
5698    /* In GNUstep, at least currently, it's possible to get a didResize
5699       without getting a willResize.. therefore we need to act as if we got
5700       the willResize now */
5701   NSSize sz = [theWindow frame].size;
5702   sz = [self windowWillResize: theWindow toSize: sz];
5703 #endif /* NS_IMPL_GNUSTEP */
5705   NSTRACE (windowDidResize);
5706 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5708 if (cols > 0 && rows > 0)
5709     {
5710       [self updateFrameSize: YES];
5711     }
5713   ns_send_appdefined (-1);
5716 #ifdef NS_IMPL_COCOA
5717 - (void)viewDidEndLiveResize
5719   [super viewDidEndLiveResize];
5720   if (old_title != 0)
5721     {
5722       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
5723       xfree (old_title);
5724       old_title = 0;
5725     }
5726   maximizing_resize = NO;
5728 #endif /* NS_IMPL_COCOA */
5731 - (void)windowDidBecomeKey: (NSNotification *)notification
5732 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5734   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5735   struct frame *old_focus = dpyinfo->x_focus_frame;
5737   NSTRACE (windowDidBecomeKey);
5739   if (emacsframe != old_focus)
5740     dpyinfo->x_focus_frame = emacsframe;
5742   ns_frame_rehighlight (emacsframe);
5744   if (emacs_event)
5745     {
5746       emacs_event->kind = FOCUS_IN_EVENT;
5747       EV_TRAILER ((id)nil);
5748     }
5752 - (void)windowDidResignKey: (NSNotification *)notification
5753 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5755   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5756   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
5757   NSTRACE (windowDidResignKey);
5759   if (is_focus_frame)
5760     dpyinfo->x_focus_frame = 0;
5762   ns_frame_rehighlight (emacsframe);
5764   /* FIXME: for some reason needed on second and subsequent clicks away
5765             from sole-frame Emacs to get hollow box to show */
5766   if (!windowClosing && [[self window] isVisible] == YES)
5767     {
5768       x_update_cursor (emacsframe, 1);
5769       x_set_frame_alpha (emacsframe);
5770     }
5772   if (emacs_event && is_focus_frame)
5773     {
5774       [self deleteWorkingText];
5775       emacs_event->kind = FOCUS_OUT_EVENT;
5776       EV_TRAILER ((id)nil);
5777     }
5781 - (void)windowWillMiniaturize: sender
5783   NSTRACE (windowWillMiniaturize);
5787 - (BOOL)isFlipped
5789   return YES;
5793 - (BOOL)isOpaque
5795   return NO;
5799 - initFrameFromEmacs: (struct frame *)f
5801   NSRect r, wr;
5802   Lisp_Object tem;
5803   NSWindow *win;
5804   NSSize sz;
5805   NSColor *col;
5806   NSString *name;
5808   NSTRACE (initFrameFromEmacs);
5810   windowClosing = NO;
5811   processingCompose = NO;
5812   scrollbarsNeedingUpdate = 0;
5813   fs_state = FULLSCREEN_NONE;
5814   fs_before_fs = next_maximized = -1;
5815 #ifdef HAVE_NATIVE_FS
5816   fs_is_native = ns_use_native_fullscreen;
5817 #else
5818   fs_is_native = NO;
5819 #endif
5820   maximized_width = maximized_height = -1;
5821   nonfs_window = nil;
5823 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5825   ns_userRect = NSMakeRect (0, 0, 0, 0);
5826   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5827                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5828   [self initWithFrame: r];
5829   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5831   FRAME_NS_VIEW (f) = self;
5832   emacsframe = f;
5833 #ifdef NS_IMPL_COCOA
5834   old_title = 0;
5835   maximizing_resize = NO;
5836 #endif
5838   win = [[EmacsWindow alloc]
5839             initWithContentRect: r
5840                       styleMask: (NSResizableWindowMask |
5841 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5842                                   NSTitledWindowMask |
5843 #endif
5844                                   NSMiniaturizableWindowMask |
5845                                   NSClosableWindowMask)
5846                         backing: NSBackingStoreBuffered
5847                           defer: YES];
5849 #ifdef HAVE_NATIVE_FS
5850     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
5851 #endif
5853   wr = [win frame];
5854   bwidth = f->border_width = wr.size.width - r.size.width;
5855   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5857   [win setAcceptsMouseMovedEvents: YES];
5858   [win setDelegate: self];
5859   [win useOptimizedDrawing: YES];
5861   sz.width = FRAME_COLUMN_WIDTH (f);
5862   sz.height = FRAME_LINE_HEIGHT (f);
5863   [win setResizeIncrements: sz];
5865   [[win contentView] addSubview: self];
5867   if (ns_drag_types)
5868     [self registerForDraggedTypes: ns_drag_types];
5870   tem = f->name;
5871   name = [NSString stringWithUTF8String:
5872                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5873   [win setTitle: name];
5875   /* toolbar support */
5876   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5877                          [NSString stringWithFormat: @"Emacs Frame %d",
5878                                    ns_window_num]];
5879   [win setToolbar: toolbar];
5880   [toolbar setVisible: NO];
5881 #ifdef NS_IMPL_COCOA
5882   {
5883     NSButton *toggleButton;
5884   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5885   [toggleButton setTarget: self];
5886   [toggleButton setAction: @selector (toggleToolbar: )];
5887   }
5888 #endif
5889   FRAME_TOOLBAR_HEIGHT (f) = 0;
5891   tem = f->icon_name;
5892   if (!NILP (tem))
5893     [win setMiniwindowTitle:
5894            [NSString stringWithUTF8String: SSDATA (tem)]];
5896   {
5897     NSScreen *screen = [win screen];
5899     if (screen != 0)
5900       [win setFrameTopLeftPoint: NSMakePoint
5901            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5902             IN_BOUND (-SCREENMAX,
5903                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5904   }
5906   [win makeFirstResponder: self];
5908   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5909                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5910   [win setBackgroundColor: col];
5911   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
5912     [win setOpaque: NO];
5914   [self allocateGState];
5916   [NSApp registerServicesMenuSendTypes: ns_send_types
5917                            returnTypes: nil];
5919   ns_window_num++;
5920   return self;
5924 - (void)windowDidMove: sender
5926   NSWindow *win = [self window];
5927   NSRect r = [win frame];
5928   NSArray *screens = [NSScreen screens];
5929   NSScreen *screen = [screens objectAtIndex: 0];
5931   NSTRACE (windowDidMove);
5933   if (!emacsframe->output_data.ns)
5934     return;
5935   if (screen != nil)
5936     {
5937       emacsframe->left_pos = r.origin.x;
5938       emacsframe->top_pos =
5939         [screen frame].size.height - (r.origin.y + r.size.height);
5940     }
5944 /* Called AFTER method below, but before our windowWillResize call there leads
5945    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5946    location so set_window_size moves the frame. */
5947 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5949   emacsframe->output_data.ns->zooming = 1;
5950   return YES;
5954 /* Override to do something slightly nonstandard, but nice.  First click on
5955    zoom button will zoom vertically.  Second will zoom completely.  Third
5956    returns to original. */
5957 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5958                         defaultFrame:(NSRect)defaultFrame
5960   NSRect result = [sender frame];
5962   NSTRACE (windowWillUseStandardFrame);
5964   if (fs_before_fs != -1) /* Entering fullscreen */
5965       {
5966         result = defaultFrame;
5967       }
5968   else if (next_maximized == FULLSCREEN_HEIGHT
5969       || (next_maximized == -1
5970           && abs (defaultFrame.size.height - result.size.height)
5971           > FRAME_LINE_HEIGHT (emacsframe)))
5972     {
5973       /* first click */
5974       ns_userRect = result;
5975       maximized_height = result.size.height = defaultFrame.size.height;
5976       maximized_width = -1;
5977       result.origin.y = defaultFrame.origin.y;
5978       [self setFSValue: FULLSCREEN_HEIGHT];
5979 #ifdef NS_IMPL_COCOA
5980       maximizing_resize = YES;
5981 #endif
5982     }
5983   else if (next_maximized == FULLSCREEN_WIDTH)
5984     {
5985       ns_userRect = result;
5986       maximized_width = result.size.width = defaultFrame.size.width;
5987       maximized_height = -1;
5988       result.origin.x = defaultFrame.origin.x;
5989       [self setFSValue: FULLSCREEN_WIDTH];
5990     }
5991   else if (next_maximized == FULLSCREEN_MAXIMIZED
5992            || (next_maximized == -1
5993                && abs (defaultFrame.size.width - result.size.width)
5994                > FRAME_COLUMN_WIDTH (emacsframe)))
5995     {
5996       result = defaultFrame;  /* second click */
5997       maximized_width = result.size.width;
5998       maximized_height = result.size.height;
5999       [self setFSValue: FULLSCREEN_MAXIMIZED];
6000 #ifdef NS_IMPL_COCOA
6001       maximizing_resize = YES;
6002 #endif
6003     }
6004   else
6005     {
6006       /* restore */
6007       result = ns_userRect.size.height ? ns_userRect : result;
6008       ns_userRect = NSMakeRect (0, 0, 0, 0);
6009 #ifdef NS_IMPL_COCOA
6010       maximizing_resize = fs_state != FULLSCREEN_NONE;
6011 #endif
6012       [self setFSValue: FULLSCREEN_NONE];
6013       maximized_width = maximized_height = -1;
6014     }
6016   if (fs_before_fs == -1) next_maximized = -1;
6017   [self windowWillResize: sender toSize: result.size];
6018   return result;
6022 - (void)windowDidDeminiaturize: sender
6024   NSTRACE (windowDidDeminiaturize);
6025   if (!emacsframe->output_data.ns)
6026     return;
6028   SET_FRAME_ICONIFIED (emacsframe, 0);
6029   SET_FRAME_VISIBLE (emacsframe, 1);
6030   windows_or_buffers_changed++;
6032   if (emacs_event)
6033     {
6034       emacs_event->kind = DEICONIFY_EVENT;
6035       EV_TRAILER ((id)nil);
6036     }
6040 - (void)windowDidExpose: sender
6042   NSTRACE (windowDidExpose);
6043   if (!emacsframe->output_data.ns)
6044     return;
6046   SET_FRAME_VISIBLE (emacsframe, 1);
6047   SET_FRAME_GARBAGED (emacsframe);
6049   if (send_appdefined)
6050     ns_send_appdefined (-1);
6054 - (void)windowDidMiniaturize: sender
6056   NSTRACE (windowDidMiniaturize);
6057   if (!emacsframe->output_data.ns)
6058     return;
6060   SET_FRAME_ICONIFIED (emacsframe, 1);
6061   SET_FRAME_VISIBLE (emacsframe, 0);
6063   if (emacs_event)
6064     {
6065       emacs_event->kind = ICONIFY_EVENT;
6066       EV_TRAILER ((id)nil);
6067     }
6070 #ifdef HAVE_NATIVE_FS
6071 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6072       willUseFullScreenPresentationOptions:
6073   (NSApplicationPresentationOptions)proposedOptions
6075   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6077 #endif
6079 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6081   fs_before_fs = fs_state;
6084 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6086   [self setFSValue: FULLSCREEN_BOTH];
6087   if (! [self fsIsNative])
6088     {
6089       [self windowDidBecomeKey:notification];
6090       [nonfs_window orderOut:self];
6091     }
6092   else if (! FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6093     [toolbar setVisible:NO];
6096 - (void)windowWillExitFullScreen:(NSNotification *)notification
6098   if (next_maximized != -1)
6099     fs_before_fs = next_maximized;
6102 - (void)windowDidExitFullScreen:(NSNotification *)notification
6104   [self setFSValue: fs_before_fs];
6105   fs_before_fs = -1;
6106 #ifdef NS_IMPL_COCOA
6107   [self updateCollectionBehaviour];
6108 #endif
6109   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6110     {
6111       [toolbar setVisible:YES];
6112       update_frame_tool_bar (emacsframe);
6113       [self updateFrameSize:YES];
6114       [[self window] display];
6115     }
6116   else
6117     [toolbar setVisible:NO];
6119   if (next_maximized != -1)
6120     [[self window] performZoom:self];
6123 - (BOOL)fsIsNative
6125   return fs_is_native;
6128 - (BOOL)isFullscreen
6130   if (! fs_is_native) return nonfs_window != nil;
6131 #ifdef HAVE_NATIVE_FS
6132   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6133 #else
6134   return NO;
6135 #endif
6138 #ifdef HAVE_NATIVE_FS
6139 - (void)updateCollectionBehaviour
6141   if (! [self isFullscreen])
6142     {
6143       NSWindow *win = [self window];
6144       NSWindowCollectionBehavior b = [win collectionBehavior];
6145       if (ns_use_native_fullscreen)
6146         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6147       else
6148         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6150       [win setCollectionBehavior: b];
6151       fs_is_native = ns_use_native_fullscreen;
6152     }
6154 #endif
6156 - (void)toggleFullScreen: (id)sender
6158   NSWindow *w, *fw;
6159   BOOL onFirstScreen;
6160   struct frame *f;
6161   NSSize sz;
6162   NSRect r, wr;
6163   NSColor *col;
6165   if (fs_is_native)
6166     {
6167 #ifdef NS_IMPL_COCOA
6168       [[self window] toggleFullScreen:sender];
6169 #endif
6170       return;
6171     }
6173   w = [self window];
6174   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6175   f = emacsframe;
6176   wr = [w frame];
6177   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6178                                  (FRAME_DEFAULT_FACE (f)),
6179                                  f);
6181   sz.width = FRAME_COLUMN_WIDTH (f);
6182   sz.height = FRAME_LINE_HEIGHT (f);
6184   if (fs_state != FULLSCREEN_BOTH)
6185     {
6186       /* Hide dock and menubar if we are on the primary screen.  */
6187       if (onFirstScreen)
6188         {
6189 #if defined (NS_IMPL_COCOA) && \
6190   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6191           NSApplicationPresentationOptions options
6192             = NSApplicationPresentationAutoHideDock
6193             | NSApplicationPresentationAutoHideMenuBar;
6195           [NSApp setPresentationOptions: options];
6196 #else
6197           [NSMenu setMenuBarVisible:NO];
6198 #endif
6199         }
6201       fw = [[EmacsFSWindow alloc]
6202                        initWithContentRect:[w contentRectForFrameRect:wr]
6203                                  styleMask:NSBorderlessWindowMask
6204                                    backing:NSBackingStoreBuffered
6205                                      defer:YES
6206                                     screen:[w screen]];
6208       [fw setContentView:[w contentView]];
6209       [fw setTitle:[w title]];
6210       [fw setDelegate:self];
6211       [fw setAcceptsMouseMovedEvents: YES];
6212       [fw useOptimizedDrawing: YES];
6213       [fw setResizeIncrements: sz];
6214       [fw setBackgroundColor: col];
6215       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6216         [fw setOpaque: NO];
6218       f->border_width = 0;
6219       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6220       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6221       FRAME_TOOLBAR_HEIGHT (f) = 0;
6223       nonfs_window = w;
6225       [self windowWillEnterFullScreen:nil];
6226       [fw makeKeyAndOrderFront:NSApp];
6227       [fw makeFirstResponder:self];
6228       [w orderOut:self];
6229       r = [fw frameRectForContentRect:[[fw screen] frame]];
6230       [fw setFrame: r display:YES animate:YES];
6231       [self windowDidEnterFullScreen:nil];
6232       [fw display];
6233     }
6234   else
6235     {
6236       fw = w;
6237       w = nonfs_window;
6238       nonfs_window = nil;
6240       if (onFirstScreen)
6241         {
6242 #if defined (NS_IMPL_COCOA) && \
6243   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6244           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6245 #else
6246           [NSMenu setMenuBarVisible:YES];
6247 #endif
6248         }
6250       [w setContentView:[fw contentView]];
6251       [w setResizeIncrements: sz];
6252       [w setBackgroundColor: col];
6253       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6254         [w setOpaque: NO];
6256       f->border_width = bwidth;
6257       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6258       if (FRAME_EXTERNAL_TOOL_BAR (f))
6259         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6261       [self windowWillExitFullScreen:nil];
6262       [fw setFrame: [w frame] display:YES animate:YES];
6263       [fw close];
6264       [w makeKeyAndOrderFront:NSApp];
6265       [self windowDidExitFullScreen:nil];
6266       [self updateFrameSize:YES];
6267     }
6270 - (void)handleFS
6272   if (fs_state != emacsframe->want_fullscreen)
6273     {
6274       if (fs_state == FULLSCREEN_BOTH)
6275         {
6276           [self toggleFullScreen:self];
6277         }
6279       switch (emacsframe->want_fullscreen)
6280         {
6281         case FULLSCREEN_BOTH:
6282           [self toggleFullScreen:self];
6283           break;
6284         case FULLSCREEN_WIDTH:
6285           next_maximized = FULLSCREEN_WIDTH;
6286           if (fs_state != FULLSCREEN_BOTH)
6287             [[self window] performZoom:self];
6288           break;
6289         case FULLSCREEN_HEIGHT:
6290           next_maximized = FULLSCREEN_HEIGHT;
6291           if (fs_state != FULLSCREEN_BOTH)
6292             [[self window] performZoom:self];
6293           break;
6294         case FULLSCREEN_MAXIMIZED:
6295           next_maximized = FULLSCREEN_MAXIMIZED;
6296           if (fs_state != FULLSCREEN_BOTH)
6297             [[self window] performZoom:self];
6298           break;
6299         case FULLSCREEN_NONE:
6300           if (fs_state != FULLSCREEN_BOTH)
6301             {
6302               next_maximized = FULLSCREEN_NONE;
6303               [[self window] performZoom:self];
6304             }
6305           break;
6306         }
6308       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6309     }
6313 - (void) setFSValue: (int)value
6315   Lisp_Object lval = Qnil;
6316   switch (value)
6317     {
6318     case FULLSCREEN_BOTH:
6319       lval = Qfullboth;
6320       break;
6321     case FULLSCREEN_WIDTH:
6322       lval = Qfullwidth;
6323       break;
6324     case FULLSCREEN_HEIGHT:
6325       lval = Qfullheight;
6326       break;
6327     case FULLSCREEN_MAXIMIZED:
6328       lval = Qmaximized;
6329       break;
6330     }
6331   store_frame_param (emacsframe, Qfullscreen, lval);
6332   fs_state = value;
6335 - (void)mouseEntered: (NSEvent *)theEvent
6337   NSTRACE (mouseEntered);
6338   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6342 - (void)mouseExited: (NSEvent *)theEvent
6344   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6346   NSTRACE (mouseExited);
6348   if (!hlinfo)
6349     return;
6351   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6353   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6354     {
6355       clear_mouse_face (hlinfo);
6356       hlinfo->mouse_face_mouse_frame = 0;
6357     }
6361 - menuDown: sender
6363   NSTRACE (menuDown);
6364   if (context_menu_value == -1)
6365     context_menu_value = [sender tag];
6366   else
6367     {
6368       NSInteger tag = [sender tag];
6369       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6370                                     emacsframe->menu_bar_vector,
6371                                     (void *)tag);
6372     }
6374   ns_send_appdefined (-1);
6375   return self;
6379 - (EmacsToolbar *)toolbar
6381   return toolbar;
6385 /* this gets called on toolbar button click */
6386 - toolbarClicked: (id)item
6388   NSEvent *theEvent;
6389   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6391   NSTRACE (toolbarClicked);
6393   if (!emacs_event)
6394     return self;
6396   /* send first event (for some reason two needed) */
6397   theEvent = [[self window] currentEvent];
6398   emacs_event->kind = TOOL_BAR_EVENT;
6399   XSETFRAME (emacs_event->arg, emacsframe);
6400   EV_TRAILER (theEvent);
6402   emacs_event->kind = TOOL_BAR_EVENT;
6403 /*   XSETINT (emacs_event->code, 0); */
6404   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6405                            idx + TOOL_BAR_ITEM_KEY);
6406   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6407   EV_TRAILER (theEvent);
6408   return self;
6412 - toggleToolbar: (id)sender
6414   if (!emacs_event)
6415     return self;
6417   emacs_event->kind = NS_NONKEY_EVENT;
6418   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6419   EV_TRAILER ((id)nil);
6420   return self;
6424 - (void)drawRect: (NSRect)rect
6426   int x = NSMinX (rect), y = NSMinY (rect);
6427   int width = NSWidth (rect), height = NSHeight (rect);
6429   NSTRACE (drawRect);
6431   if (!emacsframe || !emacsframe->output_data.ns)
6432     return;
6434   ns_clear_frame_area (emacsframe, x, y, width, height);
6435   expose_frame (emacsframe, x, y, width, height);
6437   /*
6438     drawRect: may be called (at least in OS X 10.5) for invisible
6439     views as well for some reason.  Thus, do not infer visibility
6440     here.
6442     emacsframe->async_visible = 1;
6443     emacsframe->async_iconified = 0;
6444   */
6448 /* NSDraggingDestination protocol methods.  Actually this is not really a
6449    protocol, but a category of Object.  O well...  */
6451 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6453   NSTRACE (draggingEntered);
6454   return NSDragOperationGeneric;
6458 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6460   return YES;
6464 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6466   id pb;
6467   int x, y;
6468   NSString *type;
6469   NSEvent *theEvent = [[self window] currentEvent];
6470   NSPoint position;
6472   NSTRACE (performDragOperation);
6474   if (!emacs_event)
6475     return NO;
6477   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6478   x = lrint (position.x);  y = lrint (position.y);
6480   pb = [sender draggingPasteboard];
6481   type = [pb availableTypeFromArray: ns_drag_types];
6482   if (type == 0)
6483     {
6484       return NO;
6485     }
6486   else if ([type isEqualToString: NSFilenamesPboardType])
6487     {
6488       NSArray *files;
6489       NSEnumerator *fenum;
6490       NSString *file;
6492       if (!(files = [pb propertyListForType: type]))
6493         return NO;
6495       fenum = [files objectEnumerator];
6496       while ( (file = [fenum nextObject]) )
6497         {
6498           emacs_event->kind = NS_NONKEY_EVENT;
6499           emacs_event->code = KEY_NS_DRAG_FILE;
6500           XSETINT (emacs_event->x, x);
6501           XSETINT (emacs_event->y, y);
6502           ns_input_file = append2 (ns_input_file,
6503                                    build_string ([file UTF8String]));
6504           emacs_event->modifiers = EV_MODIFIERS (theEvent);
6505           EV_TRAILER (theEvent);
6506         }
6507       return YES;
6508     }
6509   else if ([type isEqualToString: NSURLPboardType])
6510     {
6511       NSString *file;
6512       NSURL *fileURL;
6514       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6515           [fileURL isFileURL] == NO)
6516         return NO;
6518       file = [fileURL path];
6519       emacs_event->kind = NS_NONKEY_EVENT;
6520       emacs_event->code = KEY_NS_DRAG_FILE;
6521       XSETINT (emacs_event->x, x);
6522       XSETINT (emacs_event->y, y);
6523       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6524       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6525       EV_TRAILER (theEvent);
6526       return YES;
6527     }
6528   else if ([type isEqualToString: NSStringPboardType]
6529            || [type isEqualToString: NSTabularTextPboardType])
6530     {
6531       NSString *data;
6533       if (! (data = [pb stringForType: type]))
6534         return NO;
6536       emacs_event->kind = NS_NONKEY_EVENT;
6537       emacs_event->code = KEY_NS_DRAG_TEXT;
6538       XSETINT (emacs_event->x, x);
6539       XSETINT (emacs_event->y, y);
6540       ns_input_text = build_string ([data UTF8String]);
6541       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6542       EV_TRAILER (theEvent);
6543       return YES;
6544     }
6545   else if ([type isEqualToString: NSColorPboardType])
6546     {
6547       NSColor *c = [NSColor colorFromPasteboard: pb];
6548       emacs_event->kind = NS_NONKEY_EVENT;
6549       emacs_event->code = KEY_NS_DRAG_COLOR;
6550       XSETINT (emacs_event->x, x);
6551       XSETINT (emacs_event->y, y);
6552       ns_input_color = ns_color_to_lisp (c);
6553       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6554       EV_TRAILER (theEvent);
6555       return YES;
6556     }
6557   else if ([type isEqualToString: NSFontPboardType])
6558     {
6559       /* impl based on GNUstep NSTextView.m */
6560       NSData *data = [pb dataForType: NSFontPboardType];
6561       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6562       NSFont *font = [dict objectForKey: NSFontAttributeName];
6563       char fontSize[10];
6565       if (font == nil)
6566         return NO;
6568       emacs_event->kind = NS_NONKEY_EVENT;
6569       emacs_event->code = KEY_NS_CHANGE_FONT;
6570       XSETINT (emacs_event->x, x);
6571       XSETINT (emacs_event->y, y);
6572       ns_input_font = build_string ([[font fontName] UTF8String]);
6573       snprintf (fontSize, 10, "%f", [font pointSize]);
6574       ns_input_fontsize = build_string (fontSize);
6575       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6576       EV_TRAILER (theEvent);
6577       return YES;
6578     }
6579   else
6580     {
6581       error ("Invalid data type in dragging pasteboard.");
6582       return NO;
6583     }
6587 - (id) validRequestorForSendType: (NSString *)typeSent
6588                       returnType: (NSString *)typeReturned
6590   NSTRACE (validRequestorForSendType);
6591   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6592       && typeReturned == nil)
6593     {
6594       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6595         return self;
6596     }
6598   return [super validRequestorForSendType: typeSent
6599                                returnType: typeReturned];
6603 /* The next two methods are part of NSServicesRequests informal protocol,
6604    supposedly called when a services menu item is chosen from this app.
6605    But this should not happen because we override the services menu with our
6606    own entries which call ns-perform-service.
6607    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6608    So let's at least stub them out until further investigation can be done. */
6610 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6612   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6613      be written into the buffer in place of the existing selection..
6614      ordinary service calls go through functions defined in ns-win.el */
6615   return NO;
6618 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6620   NSArray *typesDeclared;
6621   Lisp_Object val;
6623   /* We only support NSStringPboardType */
6624   if ([types containsObject:NSStringPboardType] == NO) {
6625     return NO;
6626   }
6628   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6629   if (CONSP (val) && SYMBOLP (XCAR (val)))
6630     {
6631       val = XCDR (val);
6632       if (CONSP (val) && NILP (XCDR (val)))
6633         val = XCAR (val);
6634     }
6635   if (! STRINGP (val))
6636     return NO;
6638   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6639   [pb declareTypes:typesDeclared owner:nil];
6640   ns_string_to_pasteboard (pb, val);
6641   return YES;
6645 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6646    (gives a miniaturized version of the window); currently we use the latter for
6647    frames whose active buffer doesn't correspond to any file
6648    (e.g., '*scratch*') */
6649 - setMiniwindowImage: (BOOL) setMini
6651   id image = [[self window] miniwindowImage];
6652   NSTRACE (setMiniwindowImage);
6654   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6655      about "AppleDockIconEnabled" notwithstanding, however the set message
6656      below has its effect nonetheless. */
6657   if (image != emacsframe->output_data.ns->miniimage)
6658     {
6659       if (image && [image isKindOfClass: [EmacsImage class]])
6660         [image release];
6661       [[self window] setMiniwindowImage:
6662                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6663     }
6665   return self;
6669 - (void) setRows: (int) r andColumns: (int) c
6671   rows = r;
6672   cols = c;
6675 @end  /* EmacsView */
6679 /* ==========================================================================
6681     EmacsWindow implementation
6683    ========================================================================== */
6685 @implementation EmacsWindow
6687 #ifdef NS_IMPL_COCOA
6688 - (id)accessibilityAttributeValue:(NSString *)attribute
6690   Lisp_Object str = Qnil;
6691   struct frame *f = SELECTED_FRAME ();
6692   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
6694   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6695     return NSAccessibilityTextFieldRole;
6697   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6698       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6699     {
6700       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6701     }
6702   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6703     {
6704       if (! NILP (BVAR (curbuf, mark_active)))
6705           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6707       if (NILP (str))
6708         {
6709           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6710           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6711           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6713           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6714             str = make_uninit_multibyte_string (range, byte_range);
6715           else
6716             str = make_uninit_string (range);
6717           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6718              Is this a problem?  */
6719           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6720         }
6721     }
6724   if (! NILP (str))
6725     {
6726       if (CONSP (str) && SYMBOLP (XCAR (str)))
6727         {
6728           str = XCDR (str);
6729           if (CONSP (str) && NILP (XCDR (str)))
6730             str = XCAR (str);
6731         }
6732       if (STRINGP (str))
6733         {
6734           const char *utfStr = SSDATA (str);
6735           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6736           return nsStr;
6737         }
6738     }
6740   return [super accessibilityAttributeValue:attribute];
6742 #endif /* NS_IMPL_COCOA */
6744 /* If we have multiple monitors, one above the other, we don't want to
6745    restrict the height to just one monitor.  So we override this.  */
6746 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6748   /* When making the frame visible for the first time or if there is just
6749      one screen, we want to constrain.  Other times not.  */
6750   NSUInteger nr_screens = [[NSScreen screens] count];
6751   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6752   NSTRACE (constrainFrameRect);
6754   if (nr_screens == 1)
6755     {
6756       NSRect r = [super constrainFrameRect:frameRect toScreen:screen];
6757       return r;
6758     }
6760   if (f->output_data.ns->dont_constrain
6761       || ns_menu_bar_should_be_hidden ())
6762     return frameRect;
6764   f->output_data.ns->dont_constrain = 1;
6765   return [super constrainFrameRect:frameRect toScreen:screen];
6768 @end /* EmacsWindow */
6771 @implementation EmacsFSWindow
6773 - (BOOL)canBecomeKeyWindow
6775   return YES;
6778 - (BOOL)canBecomeMainWindow
6780   return YES;
6783 @end
6785 /* ==========================================================================
6787     EmacsScroller implementation
6789    ========================================================================== */
6792 @implementation EmacsScroller
6794 /* for repeat button push */
6795 #define SCROLL_BAR_FIRST_DELAY 0.5
6796 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6798 + (CGFloat) scrollerWidth
6800   /* TODO: if we want to allow variable widths, this is the place to do it,
6801            however neither GNUstep nor Cocoa support it very well */
6802   return [NSScroller scrollerWidth];
6806 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6808   NSTRACE (EmacsScroller_initFrame);
6810   r.size.width = [EmacsScroller scrollerWidth];
6811   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6812   [self setContinuous: YES];
6813   [self setEnabled: YES];
6815   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6816      locked against the top and bottom edges, and right edge on OS X, where
6817      scrollers are on right. */
6818 #ifdef NS_IMPL_GNUSTEP
6819   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6820 #else
6821   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6822 #endif
6824   win = nwin;
6825   condemned = NO;
6826   pixel_height = NSHeight (r);
6827   if (pixel_height == 0) pixel_height = 1;
6828   min_portion = 20 / pixel_height;
6830   frame = XFRAME (XWINDOW (win)->frame);
6831   if (FRAME_LIVE_P (frame))
6832     {
6833       int i;
6834       EmacsView *view = FRAME_NS_VIEW (frame);
6835       NSView *sview = [[view window] contentView];
6836       NSArray *subs = [sview subviews];
6838       /* disable optimization stopping redraw of other scrollbars */
6839       view->scrollbarsNeedingUpdate = 0;
6840       for (i =[subs count]-1; i >= 0; i--)
6841         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6842           view->scrollbarsNeedingUpdate++;
6843       [sview addSubview: self];
6844     }
6846 /*  [self setFrame: r]; */
6848   return self;
6852 - (void)setFrame: (NSRect)newRect
6854   NSTRACE (EmacsScroller_setFrame);
6855 /*  block_input (); */
6856   pixel_height = NSHeight (newRect);
6857   if (pixel_height == 0) pixel_height = 1;
6858   min_portion = 20 / pixel_height;
6859   [super setFrame: newRect];
6860   [self display];
6861 /*  unblock_input (); */
6865 - (void)dealloc
6867   NSTRACE (EmacsScroller_dealloc);
6868   if (!NILP (win))
6869     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
6870   [super dealloc];
6874 - condemn
6876   NSTRACE (condemn);
6877   condemned =YES;
6878   return self;
6882 - reprieve
6884   NSTRACE (reprieve);
6885   condemned =NO;
6886   return self;
6890 - judge
6892   NSTRACE (judge);
6893   if (condemned)
6894     {
6895       EmacsView *view;
6896       block_input ();
6897       /* ensure other scrollbar updates after deletion */
6898       view = (EmacsView *)FRAME_NS_VIEW (frame);
6899       if (view != nil)
6900         view->scrollbarsNeedingUpdate++;
6901       [self removeFromSuperview];
6902       [self release];
6903       unblock_input ();
6904     }
6905   return self;
6909 - (void)resetCursorRects
6911   NSRect visible = [self visibleRect];
6912   NSTRACE (resetCursorRects);
6914   if (!NSIsEmptyRect (visible))
6915     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6916   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6920 - (int) checkSamePosition: (int) position portion: (int) portion
6921                     whole: (int) whole
6923   return em_position ==position && em_portion ==portion && em_whole ==whole
6924     && portion != whole; /* needed for resize empty buf */
6928 - setPosition: (int)position portion: (int)portion whole: (int)whole
6930   NSTRACE (setPosition);
6932   em_position = position;
6933   em_portion = portion;
6934   em_whole = whole;
6936   if (portion >= whole)
6937     {
6938 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6939       [self setKnobProportion: 1.0];
6940       [self setDoubleValue: 1.0];
6941 #else
6942       [self setFloatValue: 0.0 knobProportion: 1.0];
6943 #endif
6944     }
6945   else
6946     {
6947       float pos;
6948       CGFloat por;
6949       portion = max ((float)whole*min_portion/pixel_height, portion);
6950       pos = (float)position / (whole - portion);
6951       por = (CGFloat)portion/whole;
6952 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6953       [self setKnobProportion: por];
6954       [self setDoubleValue: pos];
6955 #else
6956       [self setFloatValue: pos knobProportion: por];
6957 #endif
6958     }
6960   /* Events may come here even if the event loop is not running.
6961      If we don't enter the event loop, the scroll bar will not update.
6962      So send SIGIO to ourselves.  */
6963   if (apploopnr == 0) raise (SIGIO);
6965   return self;
6968 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6969      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6970 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6971                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6973   *part = last_hit_part;
6974   *window = win;
6975   XSETINT (*y, pixel_height);
6976   if ([self floatValue] > 0.999F)
6977     XSETINT (*x, pixel_height);
6978   else
6979     XSETINT (*x, pixel_height * [self floatValue]);
6983 /* set up emacs_event */
6984 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6986   if (!emacs_event)
6987     return;
6989   emacs_event->part = last_hit_part;
6990   emacs_event->code = 0;
6991   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6992   emacs_event->frame_or_window = win;
6993   emacs_event->timestamp = EV_TIMESTAMP (e);
6994   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6995   emacs_event->arg = Qnil;
6996   XSETINT (emacs_event->x, loc * pixel_height);
6997   XSETINT (emacs_event->y, pixel_height-20);
6999   if (q_event_ptr)
7000     {
7001       n_emacs_events_pending++;
7002       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7003     }
7004   else
7005     hold_event (emacs_event);
7006   EVENT_INIT (*emacs_event);
7007   ns_send_appdefined (-1);
7011 /* called manually thru timer to implement repeated button action w/hold-down */
7012 - repeatScroll: (NSTimer *)scrollEntry
7014   NSEvent *e = [[self window] currentEvent];
7015   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
7016   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7018   /* clear timer if need be */
7019   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7020     {
7021         [scroll_repeat_entry invalidate];
7022         [scroll_repeat_entry release];
7023         scroll_repeat_entry = nil;
7025         if (inKnob)
7026           return self;
7028         scroll_repeat_entry
7029           = [[NSTimer scheduledTimerWithTimeInterval:
7030                         SCROLL_BAR_CONTINUOUS_DELAY
7031                                             target: self
7032                                           selector: @selector (repeatScroll:)
7033                                           userInfo: 0
7034                                            repeats: YES]
7035               retain];
7036     }
7038   [self sendScrollEventAtLoc: 0 fromEvent: e];
7039   return self;
7043 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
7044    mouseDragged events without going into a modal loop. */
7045 - (void)mouseDown: (NSEvent *)e
7047   NSRect sr, kr;
7048   /* hitPart is only updated AFTER event is passed on */
7049   NSScrollerPart part = [self testPart: [e locationInWindow]];
7050   CGFloat inc = 0.0, loc, kloc, pos;
7051   int edge = 0;
7053   NSTRACE (EmacsScroller_mouseDown);
7055   switch (part)
7056     {
7057     case NSScrollerDecrementPage:
7058         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7059     case NSScrollerIncrementPage:
7060         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7061     case NSScrollerDecrementLine:
7062       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7063     case NSScrollerIncrementLine:
7064       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7065     case NSScrollerKnob:
7066       last_hit_part = scroll_bar_handle; break;
7067     case NSScrollerKnobSlot:  /* GNUstep-only */
7068       last_hit_part = scroll_bar_move_ratio; break;
7069     default:  /* NSScrollerNoPart? */
7070       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7071                (long) part);
7072       return;
7073     }
7075   if (inc != 0.0)
7076     {
7077       pos = 0;      /* ignored */
7079       /* set a timer to repeat, as we can't let superclass do this modally */
7080       scroll_repeat_entry
7081         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7082                                             target: self
7083                                           selector: @selector (repeatScroll:)
7084                                           userInfo: 0
7085                                            repeats: YES]
7086             retain];
7087     }
7088   else
7089     {
7090       /* handle, or on GNUstep possibly slot */
7091       NSEvent *fake_event;
7093       /* compute float loc in slot and mouse offset on knob */
7094       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7095                       toView: nil];
7096       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7097       if (loc <= 0.0)
7098         {
7099           loc = 0.0;
7100           edge = -1;
7101         }
7102       else if (loc >= NSHeight (sr))
7103         {
7104           loc = NSHeight (sr);
7105           edge = 1;
7106         }
7108       if (edge)
7109         kloc = 0.5 * edge;
7110       else
7111         {
7112           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7113                           toView: nil];
7114           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7115         }
7116       last_mouse_offset = kloc;
7118       /* if knob, tell emacs a location offset by knob pos
7119          (to indicate top of handle) */
7120       if (part == NSScrollerKnob)
7121           pos = (loc - last_mouse_offset) / NSHeight (sr);
7122       else
7123         /* else this is a slot click on GNUstep: go straight there */
7124         pos = loc / NSHeight (sr);
7126       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7127       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7128                                       location: [e locationInWindow]
7129                                  modifierFlags: [e modifierFlags]
7130                                      timestamp: [e timestamp]
7131                                   windowNumber: [e windowNumber]
7132                                        context: [e context]
7133                                    eventNumber: [e eventNumber]
7134                                     clickCount: [e clickCount]
7135                                       pressure: [e pressure]];
7136       [super mouseUp: fake_event];
7137     }
7139   if (part != NSScrollerKnob)
7140     [self sendScrollEventAtLoc: pos fromEvent: e];
7144 /* Called as we manually track scroller drags, rather than superclass. */
7145 - (void)mouseDragged: (NSEvent *)e
7147     NSRect sr;
7148     double loc, pos;
7150     NSTRACE (EmacsScroller_mouseDragged);
7152       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7153                       toView: nil];
7154       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7156       if (loc <= 0.0)
7157         {
7158           loc = 0.0;
7159         }
7160       else if (loc >= NSHeight (sr) + last_mouse_offset)
7161         {
7162           loc = NSHeight (sr) + last_mouse_offset;
7163         }
7165       pos = (loc - last_mouse_offset) / NSHeight (sr);
7166       [self sendScrollEventAtLoc: pos fromEvent: e];
7170 - (void)mouseUp: (NSEvent *)e
7172   if (scroll_repeat_entry)
7173     {
7174       [scroll_repeat_entry invalidate];
7175       [scroll_repeat_entry release];
7176       scroll_repeat_entry = nil;
7177     }
7178   last_hit_part = 0;
7182 /* treat scrollwheel events in the bar as though they were in the main window */
7183 - (void) scrollWheel: (NSEvent *)theEvent
7185   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7186   [view mouseDown: theEvent];
7189 @end  /* EmacsScroller */
7192 #ifdef NS_IMPL_GNUSTEP
7193 /* Dummy class to get rid of startup warnings.  */
7194 @implementation EmacsDocument
7196 @end
7197 #endif
7200 /* ==========================================================================
7202    Font-related functions; these used to be in nsfaces.m
7204    ========================================================================== */
7207 Lisp_Object
7208 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7210   struct font *font = XFONT_OBJECT (font_object);
7212   if (fontset < 0)
7213     fontset = fontset_from_font (font_object);
7214   FRAME_FONTSET (f) = fontset;
7216   if (FRAME_FONT (f) == font)
7217     /* This font is already set in frame F.  There's nothing more to
7218        do.  */
7219     return font_object;
7221   FRAME_FONT (f) = font;
7223   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7224   FRAME_COLUMN_WIDTH (f) = font->average_width;
7225   FRAME_LINE_HEIGHT (f) = font->height;
7227   compute_fringe_widths (f, 1);
7229   /* Compute the scroll bar width in character columns.  */
7230   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7231     {
7232       int wid = FRAME_COLUMN_WIDTH (f);
7233       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7234         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7235     }
7236   else
7237     {
7238       int wid = FRAME_COLUMN_WIDTH (f);
7239       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7240     }
7242   /* Now make the frame display the given font.  */
7243   if (FRAME_NS_WINDOW (f) != 0)
7244         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
7246   return font_object;
7250 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7251 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7252          in 1.43. */
7254 const char *
7255 ns_xlfd_to_fontname (const char *xlfd)
7256 /* --------------------------------------------------------------------------
7257     Convert an X font name (XLFD) to an NS font name.
7258     Only family is used.
7259     The string returned is temporarily allocated.
7260    -------------------------------------------------------------------------- */
7262   char *name = xmalloc (180);
7263   int i, len;
7264   const char *ret;
7266   if (!strncmp (xlfd, "--", 2))
7267     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7268   else
7269     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7271   /* stopgap for malformed XLFD input */
7272   if (strlen (name) == 0)
7273     strcpy (name, "Monaco");
7275   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7276      also uppercase after '-' or ' ' */
7277   name[0] = c_toupper (name[0]);
7278   for (len =strlen (name), i =0; i<len; i++)
7279     {
7280       if (name[i] == '$')
7281         {
7282           name[i] = '-';
7283           if (i+1<len)
7284             name[i+1] = c_toupper (name[i+1]);
7285         }
7286       else if (name[i] == '_')
7287         {
7288           name[i] = ' ';
7289           if (i+1<len)
7290             name[i+1] = c_toupper (name[i+1]);
7291         }
7292     }
7293 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7294   ret = [[NSString stringWithUTF8String: name] UTF8String];
7295   xfree (name);
7296   return ret;
7300 void
7301 syms_of_nsterm (void)
7303   NSTRACE (syms_of_nsterm);
7305   ns_antialias_threshold = 10.0;
7307   /* from 23+ we need to tell emacs what modifiers there are.. */
7308   DEFSYM (Qmodifier_value, "modifier-value");
7309   DEFSYM (Qalt, "alt");
7310   DEFSYM (Qhyper, "hyper");
7311   DEFSYM (Qmeta, "meta");
7312   DEFSYM (Qsuper, "super");
7313   DEFSYM (Qcontrol, "control");
7314   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7316   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7317   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7318   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7319   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7320   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7322   DEFVAR_LISP ("ns-input-file", ns_input_file,
7323               "The file specified in the last NS event.");
7324   ns_input_file =Qnil;
7326   DEFVAR_LISP ("ns-input-text", ns_input_text,
7327               "The data received in the last NS text drag event.");
7328   ns_input_text =Qnil;
7330   DEFVAR_LISP ("ns-working-text", ns_working_text,
7331               "String for visualizing working composition sequence.");
7332   ns_working_text =Qnil;
7334   DEFVAR_LISP ("ns-input-font", ns_input_font,
7335               "The font specified in the last NS event.");
7336   ns_input_font =Qnil;
7338   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7339               "The fontsize specified in the last NS event.");
7340   ns_input_fontsize =Qnil;
7342   DEFVAR_LISP ("ns-input-line", ns_input_line,
7343                "The line specified in the last NS event.");
7344   ns_input_line =Qnil;
7346   DEFVAR_LISP ("ns-input-color", ns_input_color,
7347                "The color specified in the last NS event.");
7348   ns_input_color =Qnil;
7350   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7351                "The service name specified in the last NS event.");
7352   ns_input_spi_name =Qnil;
7354   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7355                "The service argument specified in the last NS event.");
7356   ns_input_spi_arg =Qnil;
7358   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7359                "This variable describes the behavior of the alternate or option key.\n\
7360 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7361 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7362 at all, allowing it to be used at a lower level for accented character entry.");
7363   ns_alternate_modifier = Qmeta;
7365   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7366                "This variable describes the behavior of the right alternate or option key.\n\
7367 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7368 Set to left means be the same key as `ns-alternate-modifier'.\n\
7369 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7370 at all, allowing it to be used at a lower level for accented character entry.");
7371   ns_right_alternate_modifier = Qleft;
7373   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7374                "This variable describes the behavior of the command key.\n\
7375 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7376   ns_command_modifier = Qsuper;
7378   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7379                "This variable describes the behavior of the right command key.\n\
7380 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7381 Set to left means be the same key as `ns-command-modifier'.\n\
7382 Set to none means that the command / option key is not interpreted by Emacs\n\
7383 at all, allowing it to be used at a lower level for accented character entry.");
7384   ns_right_command_modifier = Qleft;
7386   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7387                "This variable describes the behavior of the control key.\n\
7388 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7389   ns_control_modifier = Qcontrol;
7391   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7392                "This variable describes the behavior of the right control key.\n\
7393 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7394 Set to left means be the same key as `ns-control-modifier'.\n\
7395 Set to none means that the control / option key is not interpreted by Emacs\n\
7396 at all, allowing it to be used at a lower level for accented character entry.");
7397   ns_right_control_modifier = Qleft;
7399   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7400                "This variable describes the behavior of the function key (on laptops).\n\
7401 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7402 Set to none means that the function key is not interpreted by Emacs at all,\n\
7403 allowing it to be used at a lower level for accented character entry.");
7404   ns_function_modifier = Qnone;
7406   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7407                "Non-nil (the default) means to render text antialiased.");
7408   ns_antialias_text = Qt;
7410   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7411                "Whether to confirm application quit using dialog.");
7412   ns_confirm_quit = Qnil;
7414   staticpro (&ns_display_name_list);
7415   ns_display_name_list = Qnil;
7417   staticpro (&last_mouse_motion_frame);
7418   last_mouse_motion_frame = Qnil;
7420   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7421                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7422 Only works on OSX 10.6 or later.  */);
7423   ns_auto_hide_menu_bar = Qnil;
7425   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7426      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7427 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7428 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7429 Default is t for OSX >= 10.7, nil otherwise. */);
7430 #ifdef HAVE_NATIVE_FS
7431   ns_use_native_fullscreen = YES;
7432 #else
7433   ns_use_native_fullscreen = NO;
7434 #endif
7435   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7437   /* TODO: move to common code */
7438   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7439                doc: /* Which toolkit scroll bars Emacs uses, if any.
7440 A value of nil means Emacs doesn't use toolkit scroll bars.
7441 With the X Window system, the value is a symbol describing the
7442 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7443 With MS Windows or Nextstep, the value is t.  */);
7444   Vx_toolkit_scroll_bars = Qt;
7446   DEFVAR_BOOL ("x-use-underline-position-properties",
7447                x_use_underline_position_properties,
7448      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7449 A value of nil means ignore them.  If you encounter fonts with bogus
7450 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7451 to 4.1, set this to nil. */);
7452   x_use_underline_position_properties = 0;
7454   DEFVAR_BOOL ("x-underline-at-descent-line",
7455                x_underline_at_descent_line,
7456      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7457 A value of nil means to draw the underline according to the value of the
7458 variable `x-use-underline-position-properties', which is usually at the
7459 baseline level.  The default value is nil.  */);
7460   x_underline_at_descent_line = 0;
7462   /* Tell Emacs about this window system.  */
7463   Fprovide (Qns, Qnil);
7465   syms_of_nsfont ();
7466 #ifdef NS_IMPL_COCOA
7467 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
7468   syms_of_macfont ();
7469 #endif
7470 #endif
7471