* alloc.c (valgrind_p): Use bool for boolean.
[emacs.git] / src / nsterm.m
blob65c67eb9b56d9d16a084d5b9c22624fe47c36c97
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 static struct frame *ns_updating_frame;
195 static NSView *focus_view = NULL;
196 static int ns_window_num = 0;
197 #ifdef NS_IMPL_GNUSTEP
198 static NSRect uRect;
199 #endif
200 static BOOL gsaved = NO;
201 static BOOL ns_fake_keydown = NO;
202 #ifdef NS_IMPL_COCOA
203 static BOOL ns_menu_bar_is_hidden = NO;
204 #endif
205 /*static int debug_lock = 0; */
207 /* event loop */
208 static BOOL send_appdefined = YES;
209 #define NO_APPDEFINED_DATA (-8)
210 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
211 static NSTimer *timed_entry = 0;
212 static NSTimer *scroll_repeat_entry = nil;
213 static fd_set select_readfds, select_writefds;
214 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
215 static int select_nfds = 0, select_valid = 0;
216 static struct timespec select_timeout = { 0, 0 };
217 static int selfds[2] = { -1, -1 };
218 static pthread_mutex_t select_mutex;
219 static int apploopnr = 0;
220 static NSAutoreleasePool *outerpool;
221 static struct input_event *emacs_event = NULL;
222 static struct input_event *q_event_ptr = NULL;
223 static int n_emacs_events_pending = 0;
224 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
225   *ns_pending_service_args;
226 static BOOL ns_do_open_file = NO;
227 static BOOL ns_last_use_native_fullscreen;
229 static struct {
230   struct input_event *q;
231   int nr, cap;
232 } hold_event_q = {
233   NULL, 0, 0
236 #ifdef NS_IMPL_COCOA
238  * State for pending menu activation:
239  * MENU_NONE     Normal state
240  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
241  *               run lisp to update the menu.
242  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
243  *               will open.
244  */
245 #define MENU_NONE 0
246 #define MENU_PENDING 1
247 #define MENU_OPENING 2
248 static int menu_will_open_state = MENU_NONE;
250 /* Saved position for menu click.  */
251 static CGPoint menu_mouse_point;
252 #endif
254 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
255 #define NS_FUNCTION_KEY_MASK 0x800000
256 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
257 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
258 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
259 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
260 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
261 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
262 #define EV_MODIFIERS(e)                               \
263     ((([e modifierFlags] & NSHelpKeyMask) ?           \
264            hyper_modifier : 0)                        \
265      | (!EQ (ns_right_alternate_modifier, Qleft) && \
266         (([e modifierFlags] & NSRightAlternateKeyMask) \
267          == NSRightAlternateKeyMask) ? \
268            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
269      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
270            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
271      | (([e modifierFlags] & NSShiftKeyMask) ?     \
272            shift_modifier : 0)                        \
273      | (!EQ (ns_right_control_modifier, Qleft) && \
274         (([e modifierFlags] & NSRightControlKeyMask) \
275          == NSRightControlKeyMask) ? \
276            parse_solitary_modifier (ns_right_control_modifier) : 0) \
277      | (([e modifierFlags] & NSControlKeyMask) ?      \
278            parse_solitary_modifier (ns_control_modifier) : 0)     \
279      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
280            parse_solitary_modifier (ns_function_modifier) : 0)    \
281      | (!EQ (ns_right_command_modifier, Qleft) && \
282         (([e modifierFlags] & NSRightCommandKeyMask) \
283          == NSRightCommandKeyMask) ? \
284            parse_solitary_modifier (ns_right_command_modifier) : 0) \
285      | (([e modifierFlags] & NSCommandKeyMask) ?      \
286            parse_solitary_modifier (ns_command_modifier):0))
288 #define EV_UDMODIFIERS(e)                                      \
289     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
290      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
291      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
292      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
293      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
294      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
295      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
296      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
297      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
299 #define EV_BUTTON(e)                                                         \
300     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
301       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
302      [e buttonNumber] - 1)
304 /* Convert the time field to a timestamp in milliseconds. */
305 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
307 /* This is a piece of code which is common to all the event handling
308    methods.  Maybe it should even be a function.  */
309 #define EV_TRAILER(e)                                                   \
310   {                                                                     \
311     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
312     EV_TRAILER2 (e);                                                    \
313   }
315 #define EV_TRAILER2(e)                                                  \
316   {                                                                     \
317       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
318       if (q_event_ptr)                                                  \
319         {                                                               \
320           n_emacs_events_pending++;                                     \
321           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
322         }                                                               \
323       else                                                              \
324         hold_event (emacs_event);                                       \
325       EVENT_INIT (*emacs_event);                                        \
326       ns_send_appdefined (-1);                                          \
327     }
329 /* TODO: get rid of need for these forward declarations */
330 static void ns_condemn_scroll_bars (struct frame *f);
331 static void ns_judge_scroll_bars (struct frame *f);
332 void x_set_frame_alpha (struct frame *f);
335 /* ==========================================================================
337     Utilities
339    ========================================================================== */
341 static void
342 hold_event (struct input_event *event)
344   if (hold_event_q.nr == hold_event_q.cap)
345     {
346       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
347       else hold_event_q.cap *= 2;
348       hold_event_q.q =
349         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
350     }
352   hold_event_q.q[hold_event_q.nr++] = *event;
353   /* Make sure ns_read_socket is called, i.e. we have input.  */
354   raise (SIGIO);
355   send_appdefined = YES;
358 static Lisp_Object
359 append2 (Lisp_Object list, Lisp_Object item)
360 /* --------------------------------------------------------------------------
361    Utility to append to a list
362    -------------------------------------------------------------------------- */
364   Lisp_Object array[2];
365   array[0] = list;
366   array[1] = list1 (item);
367   return Fnconc (2, &array[0]);
371 const char *
372 ns_etc_directory (void)
373 /* If running as a self-contained app bundle, return as a string the
374    filename of the etc directory, if present; else nil.  */
376   NSBundle *bundle = [NSBundle mainBundle];
377   NSString *resourceDir = [bundle resourcePath];
378   NSString *resourcePath;
379   NSFileManager *fileManager = [NSFileManager defaultManager];
380   BOOL isDir;
382   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
383   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
384     {
385       if (isDir) return [resourcePath UTF8String];
386     }
387   return NULL;
391 const char *
392 ns_exec_path (void)
393 /* If running as a self-contained app bundle, return as a path string
394    the filenames of the libexec and bin directories, ie libexec:bin.
395    Otherwise, return nil.
396    Normally, Emacs does not add its own bin/ directory to the PATH.
397    However, a self-contained NS build has a different layout, with
398    bin/ and libexec/ subdirectories in the directory that contains
399    Emacs.app itself.
400    We put libexec first, because init_callproc_1 uses the first
401    element to initialize exec-directory.  An alternative would be
402    for init_callproc to check for invocation-directory/libexec.
405   NSBundle *bundle = [NSBundle mainBundle];
406   NSString *resourceDir = [bundle resourcePath];
407   NSString *binDir = [bundle bundlePath];
408   NSString *resourcePath, *resourcePaths;
409   NSRange range;
410   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
411   NSFileManager *fileManager = [NSFileManager defaultManager];
412   NSArray *paths;
413   NSEnumerator *pathEnum;
414   BOOL isDir;
416   range = [resourceDir rangeOfString: @"Contents"];
417   if (range.location != NSNotFound)
418     {
419       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
420 #ifdef NS_IMPL_COCOA
421       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
422 #endif
423     }
425   paths = [binDir stringsByAppendingPaths:
426                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
427   pathEnum = [paths objectEnumerator];
428   resourcePaths = @"";
430   while ((resourcePath = [pathEnum nextObject]))
431     {
432       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
433         if (isDir)
434           {
435             if ([resourcePaths length] > 0)
436               resourcePaths
437                 = [resourcePaths stringByAppendingString: pathSeparator];
438             resourcePaths
439               = [resourcePaths stringByAppendingString: resourcePath];
440           }
441     }
442   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
444   return NULL;
448 const char *
449 ns_load_path (void)
450 /* If running as a self-contained app bundle, return as a path string
451    the filenames of the site-lisp, lisp and leim directories.
452    Ie, site-lisp:lisp:leim.  Otherwise, return nil.  */
454   NSBundle *bundle = [NSBundle mainBundle];
455   NSString *resourceDir = [bundle resourcePath];
456   NSString *resourcePath, *resourcePaths;
457   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
458   NSFileManager *fileManager = [NSFileManager defaultManager];
459   BOOL isDir;
460   NSArray *paths = [resourceDir stringsByAppendingPaths:
461                               [NSArray arrayWithObjects:
462                                          @"site-lisp", @"lisp", @"leim", nil]];
463   NSEnumerator *pathEnum = [paths objectEnumerator];
464   resourcePaths = @"";
466   /* Hack to skip site-lisp.  */
467   if (no_site_lisp) resourcePath = [pathEnum nextObject];
469   while ((resourcePath = [pathEnum nextObject]))
470     {
471       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
472         if (isDir)
473           {
474             if ([resourcePaths length] > 0)
475               resourcePaths
476                 = [resourcePaths stringByAppendingString: pathSeparator];
477             resourcePaths
478               = [resourcePaths stringByAppendingString: resourcePath];
479           }
480     }
481   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
483   return NULL;
486 static void
487 ns_timeout (int usecs)
488 /* --------------------------------------------------------------------------
489      Blocking timer utility used by ns_ring_bell
490    -------------------------------------------------------------------------- */
492   struct timespec wakeup = timespec_add (current_timespec (),
493                                          make_timespec (0, usecs * 1000));
495   /* Keep waiting until past the time wakeup.  */
496   while (1)
497     {
498       struct timespec timeout, now = current_timespec ();
499       if (timespec_cmp (wakeup, now) <= 0)
500         break;
501       timeout = timespec_sub (wakeup, now);
503       /* Try to wait that long--but we might wake up sooner.  */
504       pselect (0, NULL, NULL, NULL, &timeout, NULL);
505     }
509 void
510 ns_release_object (void *obj)
511 /* --------------------------------------------------------------------------
512     Release an object (callable from C)
513    -------------------------------------------------------------------------- */
515     [(id)obj release];
519 void
520 ns_retain_object (void *obj)
521 /* --------------------------------------------------------------------------
522     Retain an object (callable from C)
523    -------------------------------------------------------------------------- */
525     [(id)obj retain];
529 void *
530 ns_alloc_autorelease_pool (void)
531 /* --------------------------------------------------------------------------
532      Allocate a pool for temporary objects (callable from C)
533    -------------------------------------------------------------------------- */
535   return [[NSAutoreleasePool alloc] init];
539 void
540 ns_release_autorelease_pool (void *pool)
541 /* --------------------------------------------------------------------------
542      Free a pool and temporary objects it refers to (callable from C)
543    -------------------------------------------------------------------------- */
545   ns_release_object (pool);
550 /* ==========================================================================
552     Focus (clipping) and screen update
554    ========================================================================== */
557 // Window constraining
558 // -------------------
560 // To ensure that the windows are not placed under the menu bar, they
561 // are typically moved by the call-back constrainFrameRect. However,
562 // by overriding it, it's possible to inhibit this, leaving the window
563 // in it's original position.
565 // It's possible to hide the menu bar. However, technically, it's only
566 // possible to hide it when the application is active. To ensure that
567 // this work properly, the menu bar and window constraining are
568 // deferred until the application becomes active.
570 // Even though it's not possible to manually move a window above the
571 // top of the screen, it is allowed if it's done programmatically,
572 // when the menu is hidden. This allows the editable area to cover the
573 // full screen height.
575 // Test cases
576 // ----------
578 // Use the following extra files:
580 //    init.el:
581 //       ;; Hide menu and place frame slightly above the top of the screen.
582 //       (setq ns-auto-hide-menu-bar t)
583 //       (set-frame-position (selected-frame) 0 -20)
585 // Test 1:
587 //    emacs -Q -l init.el
589 //    Result: No menu bar, and the title bar should be above the screen.
591 // Test 2:
593 //    emacs -Q
595 //    Result: Menu bar visible, frame placed immediately below the menu.
598 static void
599 ns_constrain_all_frames (void)
601   Lisp_Object tail, frame;
603   FOR_EACH_FRAME (tail, frame)
604     {
605       struct frame *f = XFRAME (frame);
606       if (FRAME_NS_P (f))
607         {
608           NSView *view = FRAME_NS_VIEW (f);
609           /* This no-op will trigger the default window placing
610            * constraint system. */
611           f->output_data.ns->dont_constrain = 0;
612           [[view window] setFrameOrigin:[[view window] frame].origin];
613         }
614     }
618 /* True, if the menu bar should be hidden.  */
620 static BOOL
621 ns_menu_bar_should_be_hidden (void)
623   return !NILP (ns_auto_hide_menu_bar)
624     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
628 /* Show or hide the menu bar, based on user setting.  */
630 static void
631 ns_update_auto_hide_menu_bar (void)
633 #ifdef NS_IMPL_COCOA
634 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
635   block_input ();
637   NSTRACE (ns_update_auto_hide_menu_bar);
639   if (NSApp != nil
640       && [NSApp isActive]
641       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
642     {
643       // Note, "setPresentationOptions" triggers an error unless the
644       // application is active.
645       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
647       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
648         {
649           NSApplicationPresentationOptions options
650             = NSApplicationPresentationAutoHideDock;
652           if (menu_bar_should_be_hidden)
653             options |= NSApplicationPresentationAutoHideMenuBar;
655           [NSApp setPresentationOptions: options];
657           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
659           if (!ns_menu_bar_is_hidden)
660             {
661               ns_constrain_all_frames ();
662             }
663         }
664     }
666   unblock_input ();
667 #endif
668 #endif
672 static void
673 ns_update_begin (struct frame *f)
674 /* --------------------------------------------------------------------------
675    Prepare for a grouped sequence of drawing calls
676    external (RIF) call; whole frame, called before update_window_begin
677    -------------------------------------------------------------------------- */
679   NSView *view = FRAME_NS_VIEW (f);
680   NSTRACE (ns_update_begin);
682   ns_update_auto_hide_menu_bar ();
684   ns_updating_frame = f;
685   [view lockFocus];
687   /* drawRect may have been called for say the minibuffer, and then clip path
688      is for the minibuffer.  But the display engine may draw more because
689      we have set the frame as garbaged.  So reset clip path to the whole
690      view.  */
691 #ifdef NS_IMPL_COCOA
692   {
693     NSBezierPath *bp;
694     NSRect r = [view frame];
695     NSRect cr = [[view window] frame];
696     /* If a large frame size is set, r may be larger than the window frame
697        before constrained.  In that case don't change the clip path, as we
698        will clear in to the tool bar and title bar.  */
699     if (r.size.height
700         + FRAME_NS_TITLEBAR_HEIGHT (f)
701         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
702       {
703         bp = [[NSBezierPath bezierPathWithRect: r] retain];
704         [bp setClip];
705         [bp release];
706       }
707   }
708 #endif
710 #ifdef NS_IMPL_GNUSTEP
711   uRect = NSMakeRect (0, 0, 0, 0);
712 #endif
716 static void
717 ns_update_window_begin (struct window *w)
718 /* --------------------------------------------------------------------------
719    Prepare for a grouped sequence of drawing calls
720    external (RIF) call; for one window, called after update_begin
721    -------------------------------------------------------------------------- */
723   struct frame *f = XFRAME (WINDOW_FRAME (w));
724   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
726   NSTRACE (ns_update_window_begin);
727   w->output_cursor = w->cursor;
729   block_input ();
731   if (f == hlinfo->mouse_face_mouse_frame)
732     {
733       /* Don't do highlighting for mouse motion during the update.  */
734       hlinfo->mouse_face_defer = 1;
736         /* If the frame needs to be redrawn,
737            simply forget about any prior mouse highlighting.  */
738       if (FRAME_GARBAGED_P (f))
739         hlinfo->mouse_face_window = Qnil;
741       /* (further code for mouse faces ifdef'd out in other terms elided) */
742     }
744   unblock_input ();
748 static void
749 ns_update_window_end (struct window *w, bool cursor_on_p,
750                       bool mouse_face_overwritten_p)
751 /* --------------------------------------------------------------------------
752    Finished a grouped sequence of drawing calls
753    external (RIF) call; for one window called before update_end
754    -------------------------------------------------------------------------- */
756   /* note: this fn is nearly identical in all terms */
757   if (!w->pseudo_window_p)
758     {
759       block_input ();
761       if (cursor_on_p)
762         display_and_set_cursor (w, 1,
763                                 w->output_cursor.hpos, w->output_cursor.vpos,
764                                 w->output_cursor.x, w->output_cursor.y);
766       if (draw_window_fringes (w, 1))
767         x_draw_vertical_border (w);
769       unblock_input ();
770     }
772   /* If a row with mouse-face was overwritten, arrange for
773      frame_up_to_date to redisplay the mouse highlight.  */
774   if (mouse_face_overwritten_p)
775     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
777   NSTRACE (update_window_end);
781 static void
782 ns_update_end (struct frame *f)
783 /* --------------------------------------------------------------------------
784    Finished a grouped sequence of drawing calls
785    external (RIF) call; for whole frame, called after update_window_end
786    -------------------------------------------------------------------------- */
788   EmacsView *view = FRAME_NS_VIEW (f);
790 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
791   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
793   block_input ();
795   [view unlockFocus];
796   [[view window] flushWindow];
798   unblock_input ();
799   ns_updating_frame = NULL;
800   NSTRACE (ns_update_end);
803 static void
804 ns_focus (struct frame *f, NSRect *r, int n)
805 /* --------------------------------------------------------------------------
806    Internal: Focus on given frame.  During small local updates this is used to
807      draw, however during large updates, ns_update_begin and ns_update_end are
808      called to wrap the whole thing, in which case these calls are stubbed out.
809      Except, on GNUstep, we accumulate the rectangle being drawn into, because
810      the back end won't do this automatically, and will just end up flushing
811      the entire window.
812    -------------------------------------------------------------------------- */
814 //  NSTRACE (ns_focus);
815 /* static int c =0;
816    fprintf (stderr, "focus: %d", c++);
817    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
818    fprintf (stderr, "\n"); */
820   if (f != ns_updating_frame)
821     {
822       NSView *view = FRAME_NS_VIEW (f);
823       if (view != focus_view)
824         {
825           if (focus_view != NULL)
826             {
827               [focus_view unlockFocus];
828               [[focus_view window] flushWindow];
829 /*debug_lock--; */
830             }
832           if (view)
833             [view lockFocus];
834           focus_view = view;
835 /*if (view) debug_lock++; */
836         }
837     }
839   /* clipping */
840   if (r)
841     {
842       [[NSGraphicsContext currentContext] saveGraphicsState];
843       if (n == 2)
844         NSRectClipList (r, 2);
845       else
846         NSRectClip (*r);
847       gsaved = YES;
848     }
852 static void
853 ns_unfocus (struct frame *f)
854 /* --------------------------------------------------------------------------
855      Internal: Remove focus on given frame
856    -------------------------------------------------------------------------- */
858 //  NSTRACE (ns_unfocus);
860   if (gsaved)
861     {
862       [[NSGraphicsContext currentContext] restoreGraphicsState];
863       gsaved = NO;
864     }
866   if (f != ns_updating_frame)
867     {
868       if (focus_view != NULL)
869         {
870           [focus_view unlockFocus];
871           [[focus_view window] flushWindow];
872           focus_view = NULL;
873 /*debug_lock--; */
874         }
875     }
879 static void
880 ns_clip_to_row (struct window *w, struct glyph_row *row,
881                 enum glyph_row_area area, BOOL gc)
882 /* --------------------------------------------------------------------------
883      Internal (but parallels other terms): Focus drawing on given row
884    -------------------------------------------------------------------------- */
886   struct frame *f = XFRAME (WINDOW_FRAME (w));
887   NSRect clip_rect;
888   int window_x, window_y, window_width;
890   window_box (w, area, &window_x, &window_y, &window_width, 0);
892   clip_rect.origin.x = window_x;
893   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
894   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
895   clip_rect.size.width = window_width;
896   clip_rect.size.height = row->visible_height;
898   ns_focus (f, &clip_rect, 1);
902 static void
903 ns_ring_bell (struct frame *f)
904 /* --------------------------------------------------------------------------
905      "Beep" routine
906    -------------------------------------------------------------------------- */
908   NSTRACE (ns_ring_bell);
909   if (visible_bell)
910     {
911       NSAutoreleasePool *pool;
912       struct frame *frame = SELECTED_FRAME ();
913       NSView *view;
915       block_input ();
916       pool = [[NSAutoreleasePool alloc] init];
918       view = FRAME_NS_VIEW (frame);
919       if (view != nil)
920         {
921           NSRect r, surr;
922           NSPoint dim = NSMakePoint (128, 128);
924           r = [view bounds];
925           r.origin.x += (r.size.width - dim.x) / 2;
926           r.origin.y += (r.size.height - dim.y) / 2;
927           r.size.width = dim.x;
928           r.size.height = dim.y;
929           surr = NSInsetRect (r, -2, -2);
930           ns_focus (frame, &surr, 1);
931           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
932           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
933                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
934           NSRectFill (r);
935           [[view window] flushWindow];
936           ns_timeout (150000);
937           [[view window] restoreCachedImage];
938           [[view window] flushWindow];
939           ns_unfocus (frame);
940         }
941       [pool release];
942       unblock_input ();
943     }
944   else
945     {
946       NSBeep ();
947     }
950 /* ==========================================================================
952     Frame / window manager related functions
954    ========================================================================== */
957 static void
958 ns_raise_frame (struct frame *f)
959 /* --------------------------------------------------------------------------
960      Bring window to foreground and make it active
961    -------------------------------------------------------------------------- */
963   NSView *view;
964   check_window_system (f);
965   view = FRAME_NS_VIEW (f);
966   block_input ();
967   if (FRAME_VISIBLE_P (f))
968     [[view window] makeKeyAndOrderFront: NSApp];
969   unblock_input ();
973 static void
974 ns_lower_frame (struct frame *f)
975 /* --------------------------------------------------------------------------
976      Send window to back
977    -------------------------------------------------------------------------- */
979   NSView *view;
980   check_window_system (f);
981   view = FRAME_NS_VIEW (f);
982   block_input ();
983   [[view window] orderBack: NSApp];
984   unblock_input ();
988 static void
989 ns_frame_raise_lower (struct frame *f, int raise)
990 /* --------------------------------------------------------------------------
991      External (hook)
992    -------------------------------------------------------------------------- */
994   NSTRACE (ns_frame_raise_lower);
996   if (raise)
997     ns_raise_frame (f);
998   else
999     ns_lower_frame (f);
1003 static void
1004 ns_frame_rehighlight (struct frame *frame)
1005 /* --------------------------------------------------------------------------
1006      External (hook): called on things like window switching within frame
1007    -------------------------------------------------------------------------- */
1009   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1010   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1012   NSTRACE (ns_frame_rehighlight);
1013   if (dpyinfo->x_focus_frame)
1014     {
1015       dpyinfo->x_highlight_frame
1016         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1017            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1018            : dpyinfo->x_focus_frame);
1019       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1020         {
1021           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1022           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1023         }
1024     }
1025   else
1026       dpyinfo->x_highlight_frame = 0;
1028   if (dpyinfo->x_highlight_frame &&
1029          dpyinfo->x_highlight_frame != old_highlight)
1030     {
1031       if (old_highlight)
1032         {
1033           x_update_cursor (old_highlight, 1);
1034           x_set_frame_alpha (old_highlight);
1035         }
1036       if (dpyinfo->x_highlight_frame)
1037         {
1038           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1039           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1040         }
1041     }
1045 void
1046 x_make_frame_visible (struct frame *f)
1047 /* --------------------------------------------------------------------------
1048      External: Show the window (X11 semantics)
1049    -------------------------------------------------------------------------- */
1051   NSTRACE (x_make_frame_visible);
1052   /* XXX: at some points in past this was not needed, as the only place that
1053      called this (frame.c:Fraise_frame ()) also called raise_lower;
1054      if this ends up the case again, comment this out again. */
1055   if (!FRAME_VISIBLE_P (f))
1056     {
1057       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1059       SET_FRAME_VISIBLE (f, 1);
1060       ns_raise_frame (f);
1062       /* Making a new frame from a fullscreen frame will make the new frame
1063          fullscreen also.  So skip handleFS as this will print an error.  */
1064       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1065           && [view isFullscreen])
1066         return;
1068       if (f->want_fullscreen != FULLSCREEN_NONE)
1069         {
1070           block_input ();
1071           [view handleFS];
1072           unblock_input ();
1073         }
1074     }
1078 void
1079 x_make_frame_invisible (struct frame *f)
1080 /* --------------------------------------------------------------------------
1081      External: Hide the window (X11 semantics)
1082    -------------------------------------------------------------------------- */
1084   NSView *view;
1085   NSTRACE (x_make_frame_invisible);
1086   check_window_system (f);
1087   view = FRAME_NS_VIEW (f);
1088   [[view window] orderOut: NSApp];
1089   SET_FRAME_VISIBLE (f, 0);
1090   SET_FRAME_ICONIFIED (f, 0);
1094 void
1095 x_iconify_frame (struct frame *f)
1096 /* --------------------------------------------------------------------------
1097      External: Iconify window
1098    -------------------------------------------------------------------------- */
1100   NSView *view;
1101   struct ns_display_info *dpyinfo;
1103   NSTRACE (x_iconify_frame);
1104   check_window_system (f);
1105   view = FRAME_NS_VIEW (f);
1106   dpyinfo = FRAME_DISPLAY_INFO (f);
1108   if (dpyinfo->x_highlight_frame == f)
1109     dpyinfo->x_highlight_frame = 0;
1111   if ([[view window] windowNumber] <= 0)
1112     {
1113       /* the window is still deferred.  Make it very small, bring it
1114          on screen and order it out. */
1115       NSRect s = { { 100, 100}, {0, 0} };
1116       NSRect t;
1117       t = [[view window] frame];
1118       [[view window] setFrame: s display: NO];
1119       [[view window] orderBack: NSApp];
1120       [[view window] orderOut: NSApp];
1121       [[view window] setFrame: t display: NO];
1122     }
1123   [[view window] miniaturize: NSApp];
1126 /* Free X resources of frame F.  */
1128 void
1129 x_free_frame_resources (struct frame *f)
1131   NSView *view;
1132   struct ns_display_info *dpyinfo;
1133   Mouse_HLInfo *hlinfo;
1135   NSTRACE (x_free_frame_resources);
1136   check_window_system (f);
1137   view = FRAME_NS_VIEW (f);
1138   dpyinfo = FRAME_DISPLAY_INFO (f);
1139   hlinfo = MOUSE_HL_INFO (f);
1141   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1143   block_input ();
1145   free_frame_menubar (f);
1147   if (FRAME_FACE_CACHE (f))
1148     free_frame_faces (f);
1150   if (f == dpyinfo->x_focus_frame)
1151     dpyinfo->x_focus_frame = 0;
1152   if (f == dpyinfo->x_highlight_frame)
1153     dpyinfo->x_highlight_frame = 0;
1154   if (f == hlinfo->mouse_face_mouse_frame)
1155     reset_mouse_highlight (hlinfo);
1157   if (f->output_data.ns->miniimage != nil)
1158     [f->output_data.ns->miniimage release];
1160   [[view window] close];
1161   [view release];
1163   xfree (f->output_data.ns);
1165   unblock_input ();
1168 void
1169 x_destroy_window (struct frame *f)
1170 /* --------------------------------------------------------------------------
1171      External: Delete the window
1172    -------------------------------------------------------------------------- */
1174   NSTRACE (x_destroy_window);
1175   check_window_system (f);
1176   x_free_frame_resources (f);
1177   ns_window_num--;
1181 void
1182 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1183 /* --------------------------------------------------------------------------
1184      External: Position the window
1185    -------------------------------------------------------------------------- */
1187   NSView *view = FRAME_NS_VIEW (f);
1188   NSArray *screens = [NSScreen screens];
1189   NSScreen *fscreen = [screens objectAtIndex: 0];
1190   NSScreen *screen = [[view window] screen];
1192   NSTRACE (x_set_offset);
1194   block_input ();
1196   f->left_pos = xoff;
1197   f->top_pos = yoff;
1199   if (view != nil && screen && fscreen)
1200     {
1201       f->left_pos = f->size_hint_flags & XNegative
1202         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1203         : f->left_pos;
1204       /* We use visibleFrame here to take menu bar into account.
1205          Ideally we should also adjust left/top with visibleFrame.origin.  */
1207       f->top_pos = f->size_hint_flags & YNegative
1208         ? ([screen visibleFrame].size.height + f->top_pos
1209            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1210            - FRAME_TOOLBAR_HEIGHT (f))
1211         : f->top_pos;
1212 #ifdef NS_IMPL_GNUSTEP
1213       if (f->left_pos < 100)
1214         f->left_pos = 100;  /* don't overlap menu */
1215 #endif
1216       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1217          menu bar.  */
1218       f->output_data.ns->dont_constrain = 0;
1219       [[view window] setFrameTopLeftPoint:
1220                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1221                                     SCREENMAXBOUND ([fscreen frame].size.height
1222                                                     - NS_TOP_POS (f)))];
1223       f->size_hint_flags &= ~(XNegative|YNegative);
1224     }
1226   unblock_input ();
1230 void
1231 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1232 /* --------------------------------------------------------------------------
1233      Adjust window pixel size based on given character grid size
1234      Impl is a bit more complex than other terms, need to do some
1235      internal clipping.
1236    -------------------------------------------------------------------------- */
1238   EmacsView *view = FRAME_NS_VIEW (f);
1239   NSWindow *window = [view window];
1240   NSRect wr = [window frame];
1241   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1242   int pixelwidth, pixelheight;
1244   NSTRACE (x_set_window_size);
1246   if (view == nil)
1247     return;
1249 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1251   block_input ();
1253   check_frame_size (f, &rows, &cols);
1255   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1256   compute_fringe_widths (f, 0);
1258   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1259   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1261   /* If we have a toolbar, take its height into account. */
1262   if (tb && ! [view isFullscreen])
1263     {
1264     /* NOTE: previously this would generate wrong result if toolbar not
1265              yet displayed and fixing toolbar_height=32 helped, but
1266              now (200903) seems no longer needed */
1267     FRAME_TOOLBAR_HEIGHT (f) =
1268       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1269         - FRAME_NS_TITLEBAR_HEIGHT (f);
1270 #ifdef NS_IMPL_GNUSTEP
1271       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1272 #endif
1273     }
1274   else
1275     FRAME_TOOLBAR_HEIGHT (f) = 0;
1277   wr.size.width = pixelwidth + f->border_width;
1278   wr.size.height = pixelheight;
1279   if (! [view isFullscreen])
1280     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1281       + FRAME_TOOLBAR_HEIGHT (f);
1283   /* Do not try to constrain to this screen.  We may have multiple
1284      screens, and want Emacs to span those.  Constraining to screen
1285      prevents that, and that is not nice to the user.  */
1286  if (f->output_data.ns->zooming)
1287    f->output_data.ns->zooming = 0;
1288  else
1289    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1291   [view setRows: rows andColumns: cols];
1292   [window setFrame: wr display: YES];
1294 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1296   /* This is a trick to compensate for Emacs' managing the scrollbar area
1297      as a fixed number of standard character columns.  Instead of leaving
1298      blank space for the extra, we chopped it off above.  Now for
1299      left-hand scrollbars, we shift all rendering to the left by the
1300      difference between the real width and Emacs' imagined one.  For
1301      right-hand bars, don't worry about it since the extra is never used.
1302      (Obviously doesn't work for vertically split windows tho..) */
1303   {
1304     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1305       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1306                      - NS_SCROLL_BAR_WIDTH (f), 0)
1307       : NSMakePoint (0, 0);
1308     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1309     [view setBoundsOrigin: origin];
1310   }
1312   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1313   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1314   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1315 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1317   mark_window_cursors_off (XWINDOW (f->root_window));
1318   cancel_mouse_face (f);
1320   unblock_input ();
1324 static void
1325 ns_fullscreen_hook (struct frame *f)
1327   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1329   if (!FRAME_VISIBLE_P (f))
1330     return;
1332    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1333     {
1334       /* Old style fs don't initiate correctly if created from
1335          init/default-frame alist, so use a timer (not nice...).
1336       */
1337       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1338                                      selector: @selector (handleFS)
1339                                      userInfo: nil repeats: NO];
1340       return;
1341     }
1343   block_input ();
1344   [view handleFS];
1345   unblock_input ();
1348 /* ==========================================================================
1350     Color management
1352    ========================================================================== */
1355 NSColor *
1356 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1358   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1359   if (idx < 1 || idx >= color_table->avail)
1360     return nil;
1361   return color_table->colors[idx];
1365 unsigned long
1366 ns_index_color (NSColor *color, struct frame *f)
1368   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1369   ptrdiff_t idx;
1370   ptrdiff_t i;
1372   if (!color_table->colors)
1373     {
1374       color_table->size = NS_COLOR_CAPACITY;
1375       color_table->avail = 1; /* skip idx=0 as marker */
1376       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1377       color_table->colors[0] = nil;
1378       color_table->empty_indices = [[NSMutableSet alloc] init];
1379     }
1381   /* do we already have this color ? */
1382   for (i = 1; i < color_table->avail; i++)
1383     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1384       return i;
1386   if ([color_table->empty_indices count] > 0)
1387     {
1388       NSNumber *index = [color_table->empty_indices anyObject];
1389       [color_table->empty_indices removeObject: index];
1390       idx = [index unsignedLongValue];
1391     }
1392   else
1393     {
1394       if (color_table->avail == color_table->size)
1395         color_table->colors =
1396           xpalloc (color_table->colors, &color_table->size, 1,
1397                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1398       idx = color_table->avail++;
1399     }
1401   color_table->colors[idx] = color;
1402   [color retain];
1403 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1404   return idx;
1408 void
1409 ns_free_indexed_color (unsigned long idx, struct frame *f)
1411   struct ns_color_table *color_table;
1412   NSColor *color;
1413   NSNumber *index;
1415   if (!f)
1416     return;
1418   color_table = FRAME_DISPLAY_INFO (f)->color_table;
1420   if (idx <= 0 || idx >= color_table->size) {
1421     message1 ("ns_free_indexed_color: Color index out of range.\n");
1422     return;
1423   }
1425   index = [NSNumber numberWithUnsignedInt: idx];
1426   if ([color_table->empty_indices containsObject: index]) {
1427     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1428     return;
1429   }
1431   color = color_table->colors[idx];
1432   [color release];
1433   color_table->colors[idx] = nil;
1434   [color_table->empty_indices addObject: index];
1435 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1439 static int
1440 ns_get_color (const char *name, NSColor **col)
1441 /* --------------------------------------------------------------------------
1442      Parse a color name
1443    -------------------------------------------------------------------------- */
1444 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1445    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1446    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1448   NSColor *new = nil;
1449   static char hex[20];
1450   int scaling;
1451   float r = -1.0, g, b;
1452   NSString *nsname = [NSString stringWithUTF8String: name];
1454 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1455   block_input ();
1457   if ([nsname isEqualToString: @"ns_selection_color"])
1458     {
1459       nsname = ns_selection_color;
1460       name = [ns_selection_color UTF8String];
1461     }
1463   /* First, check for some sort of numeric specification. */
1464   hex[0] = '\0';
1466   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1467     {
1468       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1469       [scanner scanFloat: &r];
1470       [scanner scanFloat: &g];
1471       [scanner scanFloat: &b];
1472     }
1473   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1474     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1475   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1476     {
1477       int len = (strlen(name) - 1);
1478       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1479       int i;
1480       scaling = strlen(name+start) / 3;
1481       for (i = 0; i < 3; i++)
1482         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1483                  name + start + i * scaling);
1484       hex[3 * (scaling + 1) - 1] = '\0';
1485     }
1487   if (hex[0])
1488     {
1489       int rr, gg, bb;
1490       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1491       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1492         {
1493           r = rr / fscale;
1494           g = gg / fscale;
1495           b = bb / fscale;
1496         }
1497     }
1499   if (r >= 0.0F)
1500     {
1501       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1502       unblock_input ();
1503       return 0;
1504     }
1506   /* Otherwise, color is expected to be from a list */
1507   {
1508     NSEnumerator *lenum, *cenum;
1509     NSString *name;
1510     NSColorList *clist;
1512 #ifdef NS_IMPL_GNUSTEP
1513     /* XXX: who is wrong, the requestor or the implementation? */
1514     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1515         == NSOrderedSame)
1516       nsname = @"highlightColor";
1517 #endif
1519     lenum = [[NSColorList availableColorLists] objectEnumerator];
1520     while ( (clist = [lenum nextObject]) && new == nil)
1521       {
1522         cenum = [[clist allKeys] objectEnumerator];
1523         while ( (name = [cenum nextObject]) && new == nil )
1524           {
1525             if ([name compare: nsname
1526                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1527               new = [clist colorWithKey: name];
1528           }
1529       }
1530   }
1532   if (new)
1533     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1534   unblock_input ();
1535   return new ? 0 : 1;
1540 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1541 /* --------------------------------------------------------------------------
1542      Convert a Lisp string object to a NS color
1543    -------------------------------------------------------------------------- */
1545   NSTRACE (ns_lisp_to_color);
1546   if (STRINGP (color))
1547     return ns_get_color (SSDATA (color), col);
1548   else if (SYMBOLP (color))
1549     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1550   return 1;
1554 Lisp_Object
1555 ns_color_to_lisp (NSColor *col)
1556 /* --------------------------------------------------------------------------
1557      Convert a color to a lisp string with the RGB equivalent
1558    -------------------------------------------------------------------------- */
1560   EmacsCGFloat red, green, blue, alpha, gray;
1561   char buf[1024];
1562   const char *str;
1563   NSTRACE (ns_color_to_lisp);
1565   block_input ();
1566   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1568       if ((str =[[col colorNameComponent] UTF8String]))
1569         {
1570           unblock_input ();
1571           return build_string ((char *)str);
1572         }
1574     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1575         getRed: &red green: &green blue: &blue alpha: &alpha];
1576   if (red ==green && red ==blue)
1577     {
1578       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1579             getWhite: &gray alpha: &alpha];
1580       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1581                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1582       unblock_input ();
1583       return build_string (buf);
1584     }
1586   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1587             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1589   unblock_input ();
1590   return build_string (buf);
1594 void
1595 ns_query_color(void *col, XColor *color_def, int setPixel)
1596 /* --------------------------------------------------------------------------
1597          Get ARGB values out of NSColor col and put them into color_def.
1598          If setPixel, set the pixel to a concatenated version.
1599          and set color_def pixel to the resulting index.
1600    -------------------------------------------------------------------------- */
1602   EmacsCGFloat r, g, b, a;
1604   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1605   color_def->red   = r * 65535;
1606   color_def->green = g * 65535;
1607   color_def->blue  = b * 65535;
1609   if (setPixel == YES)
1610     color_def->pixel
1611       = ARGB_TO_ULONG((int)(a*255),
1612                       (int)(r*255), (int)(g*255), (int)(b*255));
1616 bool
1617 ns_defined_color (struct frame *f,
1618                   const char *name,
1619                   XColor *color_def,
1620                   bool alloc,
1621                   bool makeIndex)
1622 /* --------------------------------------------------------------------------
1623          Return true if named color found, and set color_def rgb accordingly.
1624          If makeIndex and alloc are nonzero put the color in the color_table,
1625          and set color_def pixel to the resulting index.
1626          If makeIndex is zero, set color_def pixel to ARGB.
1627          Return false if not found
1628    -------------------------------------------------------------------------- */
1630   NSColor *col;
1631   NSTRACE (ns_defined_color);
1633   block_input ();
1634   if (ns_get_color (name, &col) != 0) /* Color not found  */
1635     {
1636       unblock_input ();
1637       return 0;
1638     }
1639   if (makeIndex && alloc)
1640     color_def->pixel = ns_index_color (col, f);
1641   ns_query_color (col, color_def, !makeIndex);
1642   unblock_input ();
1643   return 1;
1647 void
1648 x_set_frame_alpha (struct frame *f)
1649 /* --------------------------------------------------------------------------
1650      change the entire-frame transparency
1651    -------------------------------------------------------------------------- */
1653   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1654   double alpha = 1.0;
1655   double alpha_min = 1.0;
1657   if (dpyinfo->x_highlight_frame == f)
1658     alpha = f->alpha[0];
1659   else
1660     alpha = f->alpha[1];
1662   if (FLOATP (Vframe_alpha_lower_limit))
1663     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1664   else if (INTEGERP (Vframe_alpha_lower_limit))
1665     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1667   if (alpha < 0.0)
1668     return;
1669   else if (1.0 < alpha)
1670     alpha = 1.0;
1671   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1672     alpha = alpha_min;
1674 #ifdef NS_IMPL_COCOA
1675   {
1676     EmacsView *view = FRAME_NS_VIEW (f);
1677   [[view window] setAlphaValue: alpha];
1678   }
1679 #endif
1683 /* ==========================================================================
1685     Mouse handling
1687    ========================================================================== */
1690 void
1691 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1692 /* --------------------------------------------------------------------------
1693      Programmatically reposition mouse pointer in pixel coordinates
1694    -------------------------------------------------------------------------- */
1696   NSTRACE (x_set_mouse_pixel_position);
1697   ns_raise_frame (f);
1698 #if 0
1699   /* FIXME: this does not work, and what about GNUstep? */
1700 #ifdef NS_IMPL_COCOA
1701   [FRAME_NS_VIEW (f) lockFocus];
1702   PSsetmouse ((float)pix_x, (float)pix_y);
1703   [FRAME_NS_VIEW (f) unlockFocus];
1704 #endif
1705 #endif
1709 void
1710 x_set_mouse_position (struct frame *f, int h, int v)
1711 /* --------------------------------------------------------------------------
1712      Programmatically reposition mouse pointer in character coordinates
1713    -------------------------------------------------------------------------- */
1715   int pix_x, pix_y;
1717   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1718   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1720   if (pix_x < 0) pix_x = 0;
1721   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1723   if (pix_y < 0) pix_y = 0;
1724   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1726   x_set_mouse_pixel_position (f, pix_x, pix_y);
1730 static int
1731 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1732 /*   ------------------------------------------------------------------------
1733      Called by EmacsView on mouseMovement events.  Passes on
1734      to emacs mainstream code if we moved off of a rect of interest
1735      known as last_mouse_glyph.
1736      ------------------------------------------------------------------------ */
1738   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1739   NSRect *r;
1741 //  NSTRACE (note_mouse_movement);
1743   dpyinfo->last_mouse_motion_frame = frame;
1744   r = &dpyinfo->last_mouse_glyph;
1746   /* Note, this doesn't get called for enter/leave, since we don't have a
1747      position.  Those are taken care of in the corresponding NSView methods. */
1749   /* has movement gone beyond last rect we were tracking? */
1750   if (x < r->origin.x || x >= r->origin.x + r->size.width
1751       || y < r->origin.y || y >= r->origin.y + r->size.height)
1752     {
1753       ns_update_begin (frame);
1754       frame->mouse_moved = 1;
1755       note_mouse_highlight (frame, x, y);
1756       remember_mouse_glyph (frame, x, y, r);
1757       ns_update_end (frame);
1758       return 1;
1759     }
1761   return 0;
1765 static void
1766 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1767                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1768                    Time *time)
1769 /* --------------------------------------------------------------------------
1770     External (hook): inform emacs about mouse position and hit parts.
1771     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1772     x & y should be position in the scrollbar (the whole bar, not the handle)
1773     and length of scrollbar respectively
1774    -------------------------------------------------------------------------- */
1776   id view;
1777   NSPoint position;
1778   Lisp_Object frame, tail;
1779   struct frame *f;
1780   struct ns_display_info *dpyinfo;
1782   NSTRACE (ns_mouse_position);
1784   if (*fp == NULL)
1785     {
1786       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1787       return;
1788     }
1790   dpyinfo = FRAME_DISPLAY_INFO (*fp);
1792   block_input ();
1794   if (dpyinfo->last_mouse_scroll_bar != nil && insist == 0)
1795     {
1796       /* TODO: we do not use this path at the moment because drag events will
1797            go directly to the EmacsScroller.  Leaving code in for now. */
1798       [dpyinfo->last_mouse_scroll_bar
1799           getMouseMotionPart: (int *)part window: bar_window x: x y: y];
1800       if (time)
1801         *time = dpyinfo->last_mouse_movement_time;
1802       dpyinfo->last_mouse_scroll_bar = nil;
1803     }
1804   else
1805     {
1806       /* Clear the mouse-moved flag for every frame on this display.  */
1807       FOR_EACH_FRAME (tail, frame)
1808         if (FRAME_NS_P (XFRAME (frame))
1809             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1810           XFRAME (frame)->mouse_moved = 0;
1812       dpyinfo->last_mouse_scroll_bar = nil;
1813       if (dpyinfo->last_mouse_frame
1814           && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
1815         f = dpyinfo->last_mouse_frame;
1816       else
1817         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1818                                     : SELECTED_FRAME ();
1820       if (f && FRAME_NS_P (f))
1821         {
1822           view = FRAME_NS_VIEW (*fp);
1824           position = [[view window] mouseLocationOutsideOfEventStream];
1825           position = [view convertPoint: position fromView: nil];
1826           remember_mouse_glyph (f, position.x, position.y,
1827                                 &dpyinfo->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)
1836             *time = dpyinfo->last_mouse_movement_time;
1837           *fp = f;
1838         }
1839     }
1841   unblock_input ();
1845 static void
1846 ns_frame_up_to_date (struct frame *f)
1847 /* --------------------------------------------------------------------------
1848     External (hook): Fix up mouse highlighting right after a full update.
1849     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1850    -------------------------------------------------------------------------- */
1852   NSTRACE (ns_frame_up_to_date);
1854   if (FRAME_NS_P (f))
1855     {
1856       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1857       if (f == hlinfo->mouse_face_mouse_frame)
1858         {
1859           block_input ();
1860           ns_update_begin(f);
1861           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1862                                 hlinfo->mouse_face_mouse_x,
1863                                 hlinfo->mouse_face_mouse_y);
1864           ns_update_end(f);
1865           unblock_input ();
1866         }
1867     }
1871 static void
1872 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1873 /* --------------------------------------------------------------------------
1874     External (RIF): set frame mouse pointer type.
1875    -------------------------------------------------------------------------- */
1877   NSTRACE (ns_define_frame_cursor);
1878   if (FRAME_POINTER_TYPE (f) != cursor)
1879     {
1880       EmacsView *view = FRAME_NS_VIEW (f);
1881       FRAME_POINTER_TYPE (f) = cursor;
1882       [[view window] invalidateCursorRectsForView: view];
1883       /* Redisplay assumes this function also draws the changed frame
1884          cursor, but this function doesn't, so do it explicitly.  */
1885       x_update_cursor (f, 1);
1886     }
1891 /* ==========================================================================
1893     Keyboard handling
1895    ========================================================================== */
1898 static unsigned
1899 ns_convert_key (unsigned code)
1900 /* --------------------------------------------------------------------------
1901     Internal call used by NSView-keyDown.
1902    -------------------------------------------------------------------------- */
1904   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1905                                 / sizeof (convert_ns_to_X_keysym[0]));
1906   unsigned keysym;
1907   /* An array would be faster, but less easy to read. */
1908   for (keysym = 0; keysym < last_keysym; keysym += 2)
1909     if (code == convert_ns_to_X_keysym[keysym])
1910       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1911   return 0;
1912 /* if decide to use keyCode and Carbon table, use this line:
1913      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1917 char *
1918 x_get_keysym_name (int keysym)
1919 /* --------------------------------------------------------------------------
1920     Called by keyboard.c.  Not sure if the return val is important, except
1921     that it be unique.
1922    -------------------------------------------------------------------------- */
1924   static char value[16];
1925   NSTRACE (x_get_keysym_name);
1926   sprintf (value, "%d", keysym);
1927   return value;
1932 /* ==========================================================================
1934     Block drawing operations
1936    ========================================================================== */
1939 static void
1940 ns_redraw_scroll_bars (struct frame *f)
1942   int i;
1943   id view;
1944   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1945   NSTRACE (ns_redraw_scroll_bars);
1946   for (i =[subviews count]-1; i >= 0; i--)
1947     {
1948       view = [subviews objectAtIndex: i];
1949       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1950       [view display];
1951     }
1955 void
1956 ns_clear_frame (struct frame *f)
1957 /* --------------------------------------------------------------------------
1958       External (hook): Erase the entire frame
1959    -------------------------------------------------------------------------- */
1961   NSView *view = FRAME_NS_VIEW (f);
1962   NSRect r;
1964   NSTRACE (ns_clear_frame);
1966  /* comes on initial frame because we have
1967     after-make-frame-functions = select-frame */
1968  if (!FRAME_DEFAULT_FACE (f))
1969    return;
1971   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1973   r = [view bounds];
1975   block_input ();
1976   ns_focus (f, &r, 1);
1977   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
1978   NSRectFill (r);
1979   ns_unfocus (f);
1981   /* as of 2006/11 or so this is now needed */
1982   ns_redraw_scroll_bars (f);
1983   unblock_input ();
1987 static void
1988 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
1989 /* --------------------------------------------------------------------------
1990     External (RIF):  Clear section of frame
1991    -------------------------------------------------------------------------- */
1993   NSRect r = NSMakeRect (x, y, width, height);
1994   NSView *view = FRAME_NS_VIEW (f);
1995   struct face *face = FRAME_DEFAULT_FACE (f);
1997   if (!view || !face)
1998     return;
2000   NSTRACE (ns_clear_frame_area);
2002   r = NSIntersectionRect (r, [view frame]);
2003   ns_focus (f, &r, 1);
2004   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2006   NSRectFill (r);
2008   ns_unfocus (f);
2009   return;
2013 static void
2014 ns_scroll_run (struct window *w, struct run *run)
2015 /* --------------------------------------------------------------------------
2016     External (RIF):  Insert or delete n lines at line vpos
2017    -------------------------------------------------------------------------- */
2019   struct frame *f = XFRAME (w->frame);
2020   int x, y, width, height, from_y, to_y, bottom_y;
2022   NSTRACE (ns_scroll_run);
2024   /* begin copy from other terms */
2025   /* Get frame-relative bounding box of the text display area of W,
2026      without mode lines.  Include in this box the left and right
2027      fringe of W.  */
2028   window_box (w, ANY_AREA, &x, &y, &width, &height);
2030   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2031   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2032   bottom_y = y + height;
2034   if (to_y < from_y)
2035     {
2036       /* Scrolling up.  Make sure we don't copy part of the mode
2037          line at the bottom.  */
2038       if (from_y + run->height > bottom_y)
2039         height = bottom_y - from_y;
2040       else
2041         height = run->height;
2042     }
2043   else
2044     {
2045       /* Scrolling down.  Make sure we don't copy over the mode line.
2046          at the bottom.  */
2047       if (to_y + run->height > bottom_y)
2048         height = bottom_y - to_y;
2049       else
2050         height = run->height;
2051     }
2052   /* end copy from other terms */
2054   if (height == 0)
2055       return;
2057   block_input ();
2059   x_clear_cursor (w);
2061   {
2062     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2063     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2064     NSPoint dstOrigin = NSMakePoint (x, to_y);
2066     ns_focus (f, &dstRect, 1);
2067     NSCopyBits (0, srcRect , dstOrigin);
2068     ns_unfocus (f);
2069   }
2071   unblock_input ();
2075 static void
2076 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2077 /* --------------------------------------------------------------------------
2078     External (RIF): preparatory to fringe update after text was updated
2079    -------------------------------------------------------------------------- */
2081   struct frame *f;
2082   int width, height;
2084   NSTRACE (ns_after_update_window_line);
2086   /* begin copy from other terms */
2087   eassert (w);
2089   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2090     desired_row->redraw_fringe_bitmaps_p = 1;
2092   /* When a window has disappeared, make sure that no rest of
2093      full-width rows stays visible in the internal border.  */
2094   if (windows_or_buffers_changed
2095       && desired_row->full_width_p
2096       && (f = XFRAME (w->frame),
2097           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2098           width != 0)
2099       && (height = desired_row->visible_height,
2100           height > 0))
2101     {
2102       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2104       block_input ();
2105       ns_clear_frame_area (f, 0, y, width, height);
2106       ns_clear_frame_area (f,
2107                            FRAME_PIXEL_WIDTH (f) - width,
2108                            y, width, height);
2109       unblock_input ();
2110     }
2114 static void
2115 ns_shift_glyphs_for_insert (struct frame *f,
2116                            int x, int y, int width, int height,
2117                            int shift_by)
2118 /* --------------------------------------------------------------------------
2119     External (RIF): copy an area horizontally, don't worry about clearing src
2120    -------------------------------------------------------------------------- */
2122   NSRect srcRect = NSMakeRect (x, y, width, height);
2123   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2124   NSPoint dstOrigin = dstRect.origin;
2126   NSTRACE (ns_shift_glyphs_for_insert);
2128   ns_focus (f, &dstRect, 1);
2129   NSCopyBits (0, srcRect, dstOrigin);
2130   ns_unfocus (f);
2135 /* ==========================================================================
2137     Character encoding and metrics
2139    ========================================================================== */
2142 static void
2143 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2144 /* --------------------------------------------------------------------------
2145      External (RIF); compute left/right overhang of whole string and set in s
2146    -------------------------------------------------------------------------- */
2148   struct font *font = s->font;
2150   if (s->char2b)
2151     {
2152       struct font_metrics metrics;
2153       unsigned int codes[2];
2154       codes[0] = *(s->char2b);
2155       codes[1] = *(s->char2b + s->nchars - 1);
2157       font->driver->text_extents (font, codes, 2, &metrics);
2158       s->left_overhang = -metrics.lbearing;
2159       s->right_overhang
2160         = metrics.rbearing > metrics.width
2161         ? metrics.rbearing - metrics.width : 0;
2162     }
2163   else
2164     {
2165       s->left_overhang = 0;
2166       if (EQ (font->driver->type, Qns))
2167         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2168           FONT_HEIGHT (font) * 0.2 : 0;
2169       else
2170         s->right_overhang = 0;
2171     }
2176 /* ==========================================================================
2178     Fringe and cursor drawing
2180    ========================================================================== */
2183 extern int max_used_fringe_bitmap;
2184 static void
2185 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2186                       struct draw_fringe_bitmap_params *p)
2187 /* --------------------------------------------------------------------------
2188     External (RIF); fringe-related
2189    -------------------------------------------------------------------------- */
2191   struct frame *f = XFRAME (WINDOW_FRAME (w));
2192   struct face *face = p->face;
2193   static EmacsImage **bimgs = NULL;
2194   static int nBimgs = 0;
2196   /* grow bimgs if needed */
2197   if (nBimgs < max_used_fringe_bitmap)
2198     {
2199       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2200       memset (bimgs + nBimgs, 0,
2201               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2202       nBimgs = max_used_fringe_bitmap;
2203     }
2205   /* Must clip because of partially visible lines.  */
2206   ns_clip_to_row (w, row, ANY_AREA, YES);
2208   if (!p->overlay_p)
2209     {
2210       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2212       /* If the fringe is adjacent to the left (right) scroll bar of a
2213          leftmost (rightmost, respectively) window, then extend its
2214          background to the gap between the fringe and the bar.  */
2215       if ((WINDOW_LEFTMOST_P (w)
2216            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2217           || (WINDOW_RIGHTMOST_P (w)
2218               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2219         {
2220           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2222           if (sb_width > 0)
2223             {
2224               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2225               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2226                                     * FRAME_COLUMN_WIDTH (f));
2228               if (bx < 0)
2229                 {
2230                   /* Bitmap fills the fringe.  */
2231                   if (bar_area_x + bar_area_width == p->x)
2232                     bx = bar_area_x + sb_width;
2233                   else if (p->x + p->wd == bar_area_x)
2234                     bx = bar_area_x;
2235                   if (bx >= 0)
2236                     {
2237                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2239                       nx = bar_area_width - sb_width;
2240                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2241                                                             row->y));
2242                       ny = row->visible_height;
2243                     }
2244                 }
2245               else
2246                 {
2247                   if (bar_area_x + bar_area_width == bx)
2248                     {
2249                       bx = bar_area_x + sb_width;
2250                       nx += bar_area_width - sb_width;
2251                     }
2252                   else if (bx + nx == bar_area_x)
2253                     nx += bar_area_width - sb_width;
2254                 }
2255             }
2256         }
2258       if (bx >= 0 && nx > 0)
2259         {
2260           NSRect r = NSMakeRect (bx, by, nx, ny);
2261           NSRectClip (r);
2262           [ns_lookup_indexed_color (face->background, f) set];
2263           NSRectFill (r);
2264         }
2265     }
2267   if (p->which)
2268     {
2269       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2270       EmacsImage *img = bimgs[p->which - 1];
2272       if (!img)
2273         {
2274           unsigned short *bits = p->bits + p->dh;
2275           int len = p->h;
2276           int i;
2277           unsigned char *cbits = xmalloc (len);
2279           for (i = 0; i < len; i++)
2280             cbits[i] = ~(bits[i] & 0xff);
2281           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2282                                            flip: NO];
2283           bimgs[p->which - 1] = img;
2284           xfree (cbits);
2285         }
2287       NSRectClip (r);
2288       /* Since we composite the bitmap instead of just blitting it, we need
2289          to erase the whole background. */
2290       [ns_lookup_indexed_color(face->background, f) set];
2291       NSRectFill (r);
2292       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2293 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2294       [img drawInRect: r
2295               fromRect: NSZeroRect
2296              operation: NSCompositeSourceOver
2297               fraction: 1.0
2298            respectFlipped: YES
2299                 hints: nil];
2300 #else
2301       {
2302         NSPoint pt = r.origin;
2303         pt.y += p->h;
2304         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2305       }
2306 #endif
2307     }
2308   ns_unfocus (f);
2312 static void
2313 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2314                        int x, int y, enum text_cursor_kinds cursor_type,
2315                        int cursor_width, bool on_p, bool active_p)
2316 /* --------------------------------------------------------------------------
2317      External call (RIF): draw cursor.
2318      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2319    -------------------------------------------------------------------------- */
2321   NSRect r, s;
2322   int fx, fy, h, cursor_height;
2323   struct frame *f = WINDOW_XFRAME (w);
2324   struct glyph *phys_cursor_glyph;
2325   struct glyph *cursor_glyph;
2326   struct face *face;
2327   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2329   /* If cursor is out of bounds, don't draw garbage.  This can happen
2330      in mini-buffer windows when switching between echo area glyphs
2331      and mini-buffer.  */
2333   NSTRACE (dumpcursor);
2335   if (!on_p)
2336     return;
2338   w->phys_cursor_type = cursor_type;
2339   w->phys_cursor_on_p = on_p;
2341   if (cursor_type == NO_CURSOR)
2342     {
2343       w->phys_cursor_width = 0;
2344       return;
2345     }
2347   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2348     {
2349       if (glyph_row->exact_window_width_line_p
2350           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2351         {
2352           glyph_row->cursor_in_fringe_p = 1;
2353           draw_fringe_bitmap (w, glyph_row, 0);
2354         }
2355       return;
2356     }
2358   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2359      (other terminals do it the other way round).  We must set
2360      w->phys_cursor_width to the cursor width.  For bar cursors, that
2361      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2362   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2364   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2365      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2366   if (cursor_type == BAR_CURSOR)
2367     {
2368       if (cursor_width < 1)
2369         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2370       w->phys_cursor_width = cursor_width;
2371     }
2372   /* If we have an HBAR, "cursor_width" MAY specify height. */
2373   else if (cursor_type == HBAR_CURSOR)
2374     {
2375       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2376       fy += h - cursor_height;
2377       h = cursor_height;
2378     }
2380   r.origin.x = fx, r.origin.y = fy;
2381   r.size.height = h;
2382   r.size.width = w->phys_cursor_width;
2384   /* TODO: only needed in rare cases with last-resort font in HELLO..
2385      should we do this more efficiently? */
2386   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2389   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2390   if (face && NS_FACE_BACKGROUND (face)
2391       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2392     {
2393       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2394       hollow_color = FRAME_CURSOR_COLOR (f);
2395     }
2396   else
2397     [FRAME_CURSOR_COLOR (f) set];
2399 #ifdef NS_IMPL_COCOA
2400   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2401            atomic.  Cleaner ways of doing this should be investigated.
2402            One way would be to set a global variable DRAWING_CURSOR
2403            when making the call to draw_phys..(), don't focus in that
2404            case, then move the ns_unfocus() here after that call. */
2405   NSDisableScreenUpdates ();
2406 #endif
2408   switch (cursor_type)
2409     {
2410     case NO_CURSOR:
2411       break;
2412     case FILLED_BOX_CURSOR:
2413       NSRectFill (r);
2414       break;
2415     case HOLLOW_BOX_CURSOR:
2416       NSRectFill (r);
2417       [hollow_color set];
2418       NSRectFill (NSInsetRect (r, 1, 1));
2419       [FRAME_CURSOR_COLOR (f) set];
2420       break;
2421     case HBAR_CURSOR:
2422       NSRectFill (r);
2423       break;
2424     case BAR_CURSOR:
2425       s = r;
2426       /* If the character under cursor is R2L, draw the bar cursor
2427          on the right of its glyph, rather than on the left.  */
2428       cursor_glyph = get_phys_cursor_glyph (w);
2429       if ((cursor_glyph->resolved_level & 1) != 0)
2430         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2432       NSRectFill (s);
2433       break;
2434     }
2435   ns_unfocus (f);
2437   /* draw the character under the cursor */
2438   if (cursor_type != NO_CURSOR)
2439     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2441 #ifdef NS_IMPL_COCOA
2442   NSEnableScreenUpdates ();
2443 #endif
2448 static void
2449 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2450 /* --------------------------------------------------------------------------
2451      External (RIF): Draw a vertical line.
2452    -------------------------------------------------------------------------- */
2454   struct frame *f = XFRAME (WINDOW_FRAME (w));
2455   struct face *face;
2456   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2458   NSTRACE (ns_draw_vertical_window_border);
2460   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2461   if (face)
2462       [ns_lookup_indexed_color(face->foreground, f) set];
2464   ns_focus (f, &r, 1);
2465   NSRectFill(r);
2466   ns_unfocus (f);
2470 void
2471 show_hourglass (struct atimer *timer)
2473   if (hourglass_shown_p)
2474     return;
2476   block_input ();
2478   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2480   hourglass_shown_p = 1;
2481   unblock_input ();
2485 void
2486 hide_hourglass (void)
2488   if (!hourglass_shown_p)
2489     return;
2491   block_input ();
2493   /* TODO: remove NSProgressIndicator from all frames */
2495   hourglass_shown_p = 0;
2496   unblock_input ();
2501 /* ==========================================================================
2503     Glyph drawing operations
2505    ========================================================================== */
2507 static int
2508 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2509 /* --------------------------------------------------------------------------
2510     Wrapper utility to account for internal border width on full-width lines,
2511     and allow top full-width rows to hit the frame top.  nr should be pointer
2512     to two successive NSRects.  Number of rects actually used is returned.
2513    -------------------------------------------------------------------------- */
2515   int n = get_glyph_string_clip_rects (s, nr, 2);
2516   return n;
2519 /* --------------------------------------------------------------------
2520    Draw a wavy line under glyph string s. The wave fills wave_height
2521    pixels from y.
2523                     x          wave_length = 2
2524                                  --
2525                 y    *   *   *   *   *
2526                      |* * * * * * * * *
2527     wave_height = 3  | *   *   *   *
2528   --------------------------------------------------------------------- */
2530 static void
2531 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2533   int wave_height = 3, wave_length = 2;
2534   int y, dx, dy, odd, xmax;
2535   NSPoint a, b;
2536   NSRect waveClip;
2538   dx = wave_length;
2539   dy = wave_height - 1;
2540   y =  s->ybase - wave_height + 3;
2541   xmax = x + width;
2543   /* Find and set clipping rectangle */
2544   waveClip = NSMakeRect (x, y, width, wave_height);
2545   [[NSGraphicsContext currentContext] saveGraphicsState];
2546   NSRectClip (waveClip);
2548   /* Draw the waves */
2549   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2550   b.x = a.x + dx;
2551   odd = (int)(a.x/dx) % 2;
2552   a.y = b.y = y + 0.5;
2554   if (odd)
2555     a.y += dy;
2556   else
2557     b.y += dy;
2559   while (a.x <= xmax)
2560     {
2561       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2562       a.x = b.x, a.y = b.y;
2563       b.x += dx, b.y = y + 0.5 + odd*dy;
2564       odd = !odd;
2565     }
2567   /* Restore previous clipping rectangle(s) */
2568   [[NSGraphicsContext currentContext] restoreGraphicsState];
2573 void
2574 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2575                          NSColor *defaultCol, CGFloat width, CGFloat x)
2576 /* --------------------------------------------------------------------------
2577    Draw underline, overline, and strike-through on glyph string s.
2578    -------------------------------------------------------------------------- */
2580   if (s->for_overlaps)
2581     return;
2583   /* Do underline. */
2584   if (face->underline_p)
2585     {
2586       if (s->face->underline_type == FACE_UNDER_WAVE)
2587         {
2588           if (face->underline_defaulted_p)
2589             [defaultCol set];
2590           else
2591             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2593           ns_draw_underwave (s, width, x);
2594         }
2595       else if (s->face->underline_type == FACE_UNDER_LINE)
2596         {
2598           NSRect r;
2599           unsigned long thickness, position;
2601           /* If the prev was underlined, match its appearance. */
2602           if (s->prev && s->prev->face->underline_p
2603               && s->prev->face->underline_type == FACE_UNDER_LINE
2604               && s->prev->underline_thickness > 0)
2605             {
2606               thickness = s->prev->underline_thickness;
2607               position = s->prev->underline_position;
2608             }
2609           else
2610             {
2611               struct font *font;
2612               unsigned long descent;
2614               font=s->font;
2615               descent = s->y + s->height - s->ybase;
2617               /* Use underline thickness of font, defaulting to 1. */
2618               thickness = (font && font->underline_thickness > 0)
2619                 ? font->underline_thickness : 1;
2621               /* Determine the offset of underlining from the baseline. */
2622               if (x_underline_at_descent_line)
2623                 position = descent - thickness;
2624               else if (x_use_underline_position_properties
2625                        && font && font->underline_position >= 0)
2626                 position = font->underline_position;
2627               else if (font)
2628                 position = lround (font->descent / 2);
2629               else
2630                 position = underline_minimum_offset;
2632               position = max (position, underline_minimum_offset);
2634               /* Ensure underlining is not cropped. */
2635               if (descent <= position)
2636                 {
2637                   position = descent - 1;
2638                   thickness = 1;
2639                 }
2640               else if (descent < position + thickness)
2641                 thickness = 1;
2642             }
2644           s->underline_thickness = thickness;
2645           s->underline_position = position;
2647           r = NSMakeRect (x, s->ybase + position, width, thickness);
2649           if (face->underline_defaulted_p)
2650             [defaultCol set];
2651           else
2652             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2653           NSRectFill (r);
2654         }
2655     }
2656   /* Do overline. We follow other terms in using a thickness of 1
2657      and ignoring overline_margin. */
2658   if (face->overline_p)
2659     {
2660       NSRect r;
2661       r = NSMakeRect (x, s->y, width, 1);
2663       if (face->overline_color_defaulted_p)
2664         [defaultCol set];
2665       else
2666         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2667       NSRectFill (r);
2668     }
2670   /* Do strike-through.  We follow other terms for thickness and
2671      vertical position.*/
2672   if (face->strike_through_p)
2673     {
2674       NSRect r;
2675       unsigned long dy;
2677       dy = lrint ((s->height - 1) / 2);
2678       r = NSMakeRect (x, s->y + dy, width, 1);
2680       if (face->strike_through_color_defaulted_p)
2681         [defaultCol set];
2682       else
2683         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2684       NSRectFill (r);
2685     }
2688 static void
2689 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2690              char left_p, char right_p)
2691 /* --------------------------------------------------------------------------
2692     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2693     Note we can't just use an NSDrawRect command, because of the possibility
2694     of some sides not being drawn, and because the rect will be filled.
2695    -------------------------------------------------------------------------- */
2697   NSRect s = r;
2698   [col set];
2700   /* top, bottom */
2701   s.size.height = thickness;
2702   NSRectFill (s);
2703   s.origin.y += r.size.height - thickness;
2704   NSRectFill (s);
2706   s.size.height = r.size.height;
2707   s.origin.y = r.origin.y;
2709   /* left, right (optional) */
2710   s.size.width = thickness;
2711   if (left_p)
2712     NSRectFill (s);
2713   if (right_p)
2714     {
2715       s.origin.x += r.size.width - thickness;
2716       NSRectFill (s);
2717     }
2721 static void
2722 ns_draw_relief (NSRect r, int thickness, char raised_p,
2723                char top_p, char bottom_p, char left_p, char right_p,
2724                struct glyph_string *s)
2725 /* --------------------------------------------------------------------------
2726     Draw a relief rect inside r, optionally leaving some sides open.
2727     Note we can't just use an NSDrawBezel command, because of the possibility
2728     of some sides not being drawn, and because the rect will be filled.
2729    -------------------------------------------------------------------------- */
2731   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2732   NSColor *newBaseCol = nil;
2733   NSRect sr = r;
2735   NSTRACE (ns_draw_relief);
2737   /* set up colors */
2739   if (s->face->use_box_color_for_shadows_p)
2740     {
2741       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2742     }
2743 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2744            && s->img->pixmap
2745            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2746        {
2747          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2748        } */
2749   else
2750     {
2751       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2752     }
2754   if (newBaseCol == nil)
2755     newBaseCol = [NSColor grayColor];
2757   if (newBaseCol != baseCol)  /* TODO: better check */
2758     {
2759       [baseCol release];
2760       baseCol = [newBaseCol retain];
2761       [lightCol release];
2762       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2763       [darkCol release];
2764       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2765     }
2767   [(raised_p ? lightCol : darkCol) set];
2769   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2771   /* top */
2772   sr.size.height = thickness;
2773   if (top_p) NSRectFill (sr);
2775   /* left */
2776   sr.size.height = r.size.height;
2777   sr.size.width = thickness;
2778   if (left_p) NSRectFill (sr);
2780   [(raised_p ? darkCol : lightCol) set];
2782   /* bottom */
2783   sr.size.width = r.size.width;
2784   sr.size.height = thickness;
2785   sr.origin.y += r.size.height - thickness;
2786   if (bottom_p) NSRectFill (sr);
2788   /* right */
2789   sr.size.height = r.size.height;
2790   sr.origin.y = r.origin.y;
2791   sr.size.width = thickness;
2792   sr.origin.x += r.size.width - thickness;
2793   if (right_p) NSRectFill (sr);
2797 static void
2798 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2799 /* --------------------------------------------------------------------------
2800       Function modeled after x_draw_glyph_string_box ().
2801       Sets up parameters for drawing.
2802    -------------------------------------------------------------------------- */
2804   int right_x, last_x;
2805   char left_p, right_p;
2806   struct glyph *last_glyph;
2807   NSRect r;
2808   int thickness;
2809   struct face *face;
2811   if (s->hl == DRAW_MOUSE_FACE)
2812     {
2813       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2814       if (!face)
2815         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2816     }
2817   else
2818     face = s->face;
2820   thickness = face->box_line_width;
2822   NSTRACE (ns_dumpglyphs_box_or_relief);
2824   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2825             ? WINDOW_RIGHT_EDGE_X (s->w)
2826             : window_box_right (s->w, s->area));
2827   last_glyph = (s->cmp || s->img
2828                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2830   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2831               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2833   left_p = (s->first_glyph->left_box_line_p
2834             || (s->hl == DRAW_MOUSE_FACE
2835                 && (s->prev == NULL || s->prev->hl != s->hl)));
2836   right_p = (last_glyph->right_box_line_p
2837              || (s->hl == DRAW_MOUSE_FACE
2838                  && (s->next == NULL || s->next->hl != s->hl)));
2840   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2842   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2843   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2844     {
2845       ns_draw_box (r, abs (thickness),
2846                    ns_lookup_indexed_color (face->box_color, s->f),
2847                   left_p, right_p);
2848     }
2849   else
2850     {
2851       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2852                      1, 1, left_p, right_p, s);
2853     }
2857 static void
2858 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2859 /* --------------------------------------------------------------------------
2860       Modeled after x_draw_glyph_string_background, which draws BG in
2861       certain cases.  Others are left to the text rendering routine.
2862    -------------------------------------------------------------------------- */
2864   NSTRACE (ns_maybe_dumpglyphs_background);
2866   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2867     {
2868       int box_line_width = max (s->face->box_line_width, 0);
2869       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2870           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2871         {
2872           struct face *face;
2873           if (s->hl == DRAW_MOUSE_FACE)
2874             {
2875               face = FACE_FROM_ID (s->f,
2876                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2877               if (!face)
2878                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2879             }
2880           else
2881             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2882           if (!face->stipple)
2883             [(NS_FACE_BACKGROUND (face) != 0
2884               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2885               : FRAME_BACKGROUND_COLOR (s->f)) set];
2886           else
2887             {
2888               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
2889               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2890             }
2892           if (s->hl != DRAW_CURSOR)
2893             {
2894               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2895                                     s->background_width,
2896                                     s->height-2*box_line_width);
2897               NSRectFill (r);
2898             }
2900           s->background_filled_p = 1;
2901         }
2902     }
2906 static void
2907 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2908 /* --------------------------------------------------------------------------
2909       Renders an image and associated borders.
2910    -------------------------------------------------------------------------- */
2912   EmacsImage *img = s->img->pixmap;
2913   int box_line_vwidth = max (s->face->box_line_width, 0);
2914   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2915   int bg_x, bg_y, bg_height;
2916   int th;
2917   char raised_p;
2918   NSRect br;
2919   struct face *face;
2920   NSColor *tdCol;
2922   NSTRACE (ns_dumpglyphs_image);
2924   if (s->face->box != FACE_NO_BOX
2925       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2926     x += abs (s->face->box_line_width);
2928   bg_x = x;
2929   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2930   bg_height = s->height;
2931   /* other terms have this, but was causing problems w/tabbar mode */
2932   /* - 2 * box_line_vwidth; */
2934   if (s->slice.x == 0) x += s->img->hmargin;
2935   if (s->slice.y == 0) y += s->img->vmargin;
2937   /* Draw BG: if we need larger area than image itself cleared, do that,
2938      otherwise, since we composite the image under NS (instead of mucking
2939      with its background color), we must clear just the image area. */
2940   if (s->hl == DRAW_MOUSE_FACE)
2941     {
2942       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2943       if (!face)
2944        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2945     }
2946   else
2947     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2949   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2951   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2952       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2953     {
2954       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2955       s->background_filled_p = 1;
2956     }
2957   else
2958     {
2959       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2960     }
2962   NSRectFill (br);
2964   /* Draw the image.. do we need to draw placeholder if img ==nil? */
2965   if (img != nil)
2966     {
2967 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2968       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
2969       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
2970                               s->slice.width, s->slice.height);
2971       [img drawInRect: dr
2972              fromRect: ir
2973              operation: NSCompositeSourceOver
2974               fraction: 1.0
2975            respectFlipped: YES
2976                 hints: nil];
2977 #else
2978       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
2979                   operation: NSCompositeSourceOver];
2980 #endif
2981     }
2983   if (s->hl == DRAW_CURSOR)
2984     {
2985     [FRAME_CURSOR_COLOR (s->f) set];
2986     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
2987       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
2988     else
2989       /* Currently on NS img->mask is always 0. Since
2990          get_window_cursor_type specifies a hollow box cursor when on
2991          a non-masked image we never reach this clause. But we put it
2992          in in anticipation of better support for image masks on
2993          NS. */
2994       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
2995     }
2996   else
2997     {
2998       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
2999     }
3001   /* Draw underline, overline, strike-through. */
3002   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3004   /* Draw relief, if requested */
3005   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3006     {
3007       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3008         {
3009           th = tool_bar_button_relief >= 0 ?
3010             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3011           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3012         }
3013       else
3014         {
3015           th = abs (s->img->relief);
3016           raised_p = (s->img->relief > 0);
3017         }
3019       r.origin.x = x - th;
3020       r.origin.y = y - th;
3021       r.size.width = s->slice.width + 2*th-1;
3022       r.size.height = s->slice.height + 2*th-1;
3023       ns_draw_relief (r, th, raised_p,
3024                       s->slice.y == 0,
3025                       s->slice.y + s->slice.height == s->img->height,
3026                       s->slice.x == 0,
3027                       s->slice.x + s->slice.width == s->img->width, s);
3028     }
3030   /* If there is no mask, the background won't be seen,
3031      so draw a rectangle on the image for the cursor.
3032      Do this for all images, getting transparency right is not reliable.  */
3033   if (s->hl == DRAW_CURSOR)
3034     {
3035       int thickness = abs (s->img->relief);
3036       if (thickness == 0) thickness = 1;
3037       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3038     }
3042 static void
3043 ns_dumpglyphs_stretch (struct glyph_string *s)
3045   NSRect r[2];
3046   int n, i;
3047   struct face *face;
3048   NSColor *fgCol, *bgCol;
3050   if (!s->background_filled_p)
3051     {
3052       n = ns_get_glyph_string_clip_rect (s, r);
3053       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3055       ns_focus (s->f, r, n);
3057       if (s->hl == DRAW_MOUSE_FACE)
3058        {
3059          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3060          if (!face)
3061            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3062        }
3063       else
3064        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3066       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3067       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3069       for (i = 0; i < n; ++i)
3070         {
3071           if (!s->row->full_width_p)
3072             {
3073               int overrun, leftoverrun;
3075               /* truncate to avoid overwriting fringe and/or scrollbar */
3076               overrun = max (0, (s->x + s->background_width)
3077                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3078                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3079               r[i].size.width -= overrun;
3081               /* truncate to avoid overwriting to left of the window box */
3082               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3083                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3085               if (leftoverrun > 0)
3086                 {
3087                   r[i].origin.x += leftoverrun;
3088                   r[i].size.width -= leftoverrun;
3089                 }
3091               /* XXX: Try to work between problem where a stretch glyph on
3092                  a partially-visible bottom row will clear part of the
3093                  modeline, and another where list-buffers headers and similar
3094                  rows erroneously have visible_height set to 0.  Not sure
3095                  where this is coming from as other terms seem not to show. */
3096               r[i].size.height = min (s->height, s->row->visible_height);
3097             }
3099           [bgCol set];
3101           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3102              overwriting cursor (usually when cursor on a tab) */
3103           if (s->hl == DRAW_CURSOR)
3104             {
3105               CGFloat x, width;
3107               x = r[i].origin.x;
3108               width = s->w->phys_cursor_width;
3109               r[i].size.width -= width;
3110               r[i].origin.x += width;
3112               NSRectFill (r[i]);
3114               /* Draw overlining, etc. on the cursor. */
3115               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3116                 ns_draw_text_decoration (s, face, bgCol, width, x);
3117               else
3118                 ns_draw_text_decoration (s, face, fgCol, width, x);
3119             }
3120           else
3121             {
3122               NSRectFill (r[i]);
3123             }
3125           /* Draw overlining, etc. on the stretch glyph (or the part
3126              of the stretch glyph after the cursor). */
3127           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3128                                    r[i].origin.x);
3129         }
3130       ns_unfocus (s->f);
3131       s->background_filled_p = 1;
3132     }
3136 static void
3137 ns_draw_glyph_string (struct glyph_string *s)
3138 /* --------------------------------------------------------------------------
3139       External (RIF): Main draw-text call.
3140    -------------------------------------------------------------------------- */
3142   /* TODO (optimize): focus for box and contents draw */
3143   NSRect r[2];
3144   int n, flags;
3145   char box_drawn_p = 0;
3146   struct font *font = s->face->font;
3147   if (! font) font = FRAME_FONT (s->f);
3149   NSTRACE (ns_draw_glyph_string);
3151   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3152     {
3153       int width;
3154       struct glyph_string *next;
3156       for (width = 0, next = s->next;
3157            next && width < s->right_overhang;
3158            width += next->width, next = next->next)
3159         if (next->first_glyph->type != IMAGE_GLYPH)
3160           {
3161             if (next->first_glyph->type != STRETCH_GLYPH)
3162               {
3163                 n = ns_get_glyph_string_clip_rect (s->next, r);
3164                 ns_focus (s->f, r, n);
3165                 ns_maybe_dumpglyphs_background (s->next, 1);
3166                 ns_unfocus (s->f);
3167               }
3168             else
3169               {
3170                 ns_dumpglyphs_stretch (s->next);
3171               }
3172             next->num_clips = 0;
3173           }
3174     }
3176   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3177         && (s->first_glyph->type == CHAR_GLYPH
3178             || s->first_glyph->type == COMPOSITE_GLYPH))
3179     {
3180       n = ns_get_glyph_string_clip_rect (s, r);
3181       ns_focus (s->f, r, n);
3182       ns_maybe_dumpglyphs_background (s, 1);
3183       ns_dumpglyphs_box_or_relief (s);
3184       ns_unfocus (s->f);
3185       box_drawn_p = 1;
3186     }
3188   switch (s->first_glyph->type)
3189     {
3191     case IMAGE_GLYPH:
3192       n = ns_get_glyph_string_clip_rect (s, r);
3193       ns_focus (s->f, r, n);
3194       ns_dumpglyphs_image (s, r[0]);
3195       ns_unfocus (s->f);
3196       break;
3198     case STRETCH_GLYPH:
3199       ns_dumpglyphs_stretch (s);
3200       break;
3202     case CHAR_GLYPH:
3203     case COMPOSITE_GLYPH:
3204       n = ns_get_glyph_string_clip_rect (s, r);
3205       ns_focus (s->f, r, n);
3207       if (s->for_overlaps || (s->cmp_from > 0
3208                               && ! s->first_glyph->u.cmp.automatic))
3209         s->background_filled_p = 1;
3210       else
3211         ns_maybe_dumpglyphs_background
3212           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3214       flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3215         (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3216          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3217           NS_DUMPGLYPH_NORMAL));
3219       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3220         {
3221           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3222           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3223           NS_FACE_FOREGROUND (s->face) = tmp;
3224         }
3226       font->driver->draw
3227         (s, 0, s->nchars, s->x, s->y,
3228          (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3229          || flags == NS_DUMPGLYPH_MOUSEFACE);
3231       {
3232         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3233                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3234                                                    s->f)
3235                         : FRAME_FOREGROUND_COLOR (s->f));
3236         [col set];
3238         /* Draw underline, overline, strike-through. */
3239         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3240       }
3242       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3243         {
3244           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3245           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3246           NS_FACE_FOREGROUND (s->face) = tmp;
3247         }
3249       ns_unfocus (s->f);
3250       break;
3252     case GLYPHLESS_GLYPH:
3253       n = ns_get_glyph_string_clip_rect (s, r);
3254       ns_focus (s->f, r, n);
3256       if (s->for_overlaps || (s->cmp_from > 0
3257                               && ! s->first_glyph->u.cmp.automatic))
3258         s->background_filled_p = 1;
3259       else
3260         ns_maybe_dumpglyphs_background
3261           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3262       /* ... */
3263       /* Not yet implemented.  */
3264       /* ... */
3265       ns_unfocus (s->f);
3266       break;
3268     default:
3269       emacs_abort ();
3270     }
3272   /* Draw box if not done already. */
3273   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3274     {
3275       n = ns_get_glyph_string_clip_rect (s, r);
3276       ns_focus (s->f, r, n);
3277       ns_dumpglyphs_box_or_relief (s);
3278       ns_unfocus (s->f);
3279     }
3281   s->num_clips = 0;
3286 /* ==========================================================================
3288     Event loop
3290    ========================================================================== */
3293 static void
3294 ns_send_appdefined (int value)
3295 /* --------------------------------------------------------------------------
3296     Internal: post an appdefined event which EmacsApp-sendEvent will
3297               recognize and take as a command to halt the event loop.
3298    -------------------------------------------------------------------------- */
3300   /*NSTRACE (ns_send_appdefined); */
3302 #ifdef NS_IMPL_GNUSTEP
3303   // GNUStep needs postEvent to happen on the main thread.
3304   if (! [[NSThread currentThread] isMainThread])
3305     {
3306       EmacsApp *app = (EmacsApp *)NSApp;
3307       app->nextappdefined = value;
3308       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3309                             withObject:nil
3310                          waitUntilDone:YES];
3311       return;
3312     }
3313 #endif
3315   /* Only post this event if we haven't already posted one.  This will end
3316        the [NXApp run] main loop after having processed all events queued at
3317        this moment.  */
3318   if (send_appdefined)
3319     {
3320       NSEvent *nxev;
3322       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3323       send_appdefined = NO;
3325       /* Don't need wakeup timer any more */
3326       if (timed_entry)
3327         {
3328           [timed_entry invalidate];
3329           [timed_entry release];
3330           timed_entry = nil;
3331         }
3333       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3334                                 location: NSMakePoint (0, 0)
3335                            modifierFlags: 0
3336                                timestamp: 0
3337                             windowNumber: [[NSApp mainWindow] windowNumber]
3338                                  context: [NSApp context]
3339                                  subtype: 0
3340                                    data1: value
3341                                    data2: 0];
3343       /* Post an application defined event on the event queue.  When this is
3344          received the [NXApp run] will return, thus having processed all
3345          events which are currently queued.  */
3346       [NSApp postEvent: nxev atStart: NO];
3347     }
3350 #ifdef HAVE_NATIVE_FS
3351 static void
3352 check_native_fs ()
3354   Lisp_Object frame, tail;
3356   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3357     return;
3359   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3361   /* Clear the mouse-moved flag for every frame on this display.  */
3362   FOR_EACH_FRAME (tail, frame)
3363     {
3364       struct frame *f = XFRAME (frame);
3365       if (FRAME_NS_P (f))
3366         {
3367           EmacsView *view = FRAME_NS_VIEW (f);
3368           [view updateCollectionBehaviour];
3369         }
3370     }
3372 #endif
3374 /* GNUStep and OSX <= 10.4 does not have cancelTracking.  */
3375 #if defined (NS_IMPL_COCOA) && \
3376   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
3377 /* Check if menu open should be cancelled or continued as normal.  */
3378 void
3379 ns_check_menu_open (NSMenu *menu)
3381   /* Click in menu bar? */
3382   NSArray *a = [[NSApp mainMenu] itemArray];
3383   int i;
3384   BOOL found = NO;
3386   if (menu == nil) // Menu tracking ended.
3387     {
3388       if (menu_will_open_state == MENU_OPENING)
3389         menu_will_open_state = MENU_NONE;
3390       return;
3391     }
3393   for (i = 0; ! found && i < [a count]; i++)
3394     found = menu == [[a objectAtIndex:i] submenu];
3395   if (found)
3396     {
3397       if (menu_will_open_state == MENU_NONE && emacs_event)
3398         {
3399           NSEvent *theEvent = [NSApp currentEvent];
3400           struct frame *emacsframe = SELECTED_FRAME ();
3402           [menu cancelTracking];
3403           menu_will_open_state = MENU_PENDING;
3404           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3405           EV_TRAILER (theEvent);
3407           CGEventRef ourEvent = CGEventCreate (NULL);
3408           menu_mouse_point = CGEventGetLocation (ourEvent);
3409           CFRelease (ourEvent);
3410         }
3411       else if (menu_will_open_state == MENU_OPENING)
3412         {
3413           menu_will_open_state = MENU_NONE;
3414         }
3415     }
3418 /* Redo saved menu click if state is MENU_PENDING.  */
3419 void
3420 ns_check_pending_open_menu ()
3422   if (menu_will_open_state == MENU_PENDING)
3423     {
3424       CGEventSourceRef source
3425         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3427       CGEventRef event = CGEventCreateMouseEvent (source,
3428                                                   kCGEventLeftMouseDown,
3429                                                   menu_mouse_point,
3430                                                   kCGMouseButtonLeft);
3431       CGEventSetType (event, kCGEventLeftMouseDown);
3432       CGEventPost (kCGHIDEventTap, event);
3433       CFRelease (event);
3434       CFRelease (source);
3436       menu_will_open_state = MENU_OPENING;
3437     }
3439 #endif /* NS_IMPL_COCOA) && >= MAC_OS_X_VERSION_10_5 */
3441 static int
3442 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3443 /* --------------------------------------------------------------------------
3444      External (hook): Post an event to ourself and keep reading events until
3445      we read it back again.  In effect process all events which were waiting.
3446      From 21+ we have to manage the event buffer ourselves.
3447    -------------------------------------------------------------------------- */
3449   struct input_event ev;
3450   int nevents;
3452 /* NSTRACE (ns_read_socket); */
3454 #ifdef HAVE_NATIVE_FS
3455   check_native_fs ();
3456 #endif
3458   if ([NSApp modalWindow] != nil)
3459     return -1;
3461   if (hold_event_q.nr > 0)
3462     {
3463       int i;
3464       for (i = 0; i < hold_event_q.nr; ++i)
3465         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3466       hold_event_q.nr = 0;
3467       return i;
3468     }
3470   block_input ();
3471   n_emacs_events_pending = 0;
3472   EVENT_INIT (ev);
3473   emacs_event = &ev;
3474   q_event_ptr = hold_quit;
3476   /* we manage autorelease pools by allocate/reallocate each time around
3477      the loop; strict nesting is occasionally violated but seems not to
3478      matter.. earlier methods using full nesting caused major memory leaks */
3479   [outerpool release];
3480   outerpool = [[NSAutoreleasePool alloc] init];
3482   /* If have pending open-file requests, attend to the next one of those. */
3483   if (ns_pending_files && [ns_pending_files count] != 0
3484       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3485     {
3486       [ns_pending_files removeObjectAtIndex: 0];
3487     }
3488   /* Deal with pending service requests. */
3489   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3490     && [(EmacsApp *)
3491          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3492                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3493     {
3494       [ns_pending_service_names removeObjectAtIndex: 0];
3495       [ns_pending_service_args removeObjectAtIndex: 0];
3496     }
3497   else
3498     {
3499       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3500          to ourself, otherwise [NXApp run] will never exit.  */
3501       send_appdefined = YES;
3502       ns_send_appdefined (-1);
3504       if (++apploopnr != 1)
3505         {
3506           emacs_abort ();
3507         }
3508       [NSApp run];
3509       --apploopnr;
3510     }
3512   nevents = n_emacs_events_pending;
3513   n_emacs_events_pending = 0;
3514   emacs_event = q_event_ptr = NULL;
3515   unblock_input ();
3517   return nevents;
3522 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3523            fd_set *exceptfds, struct timespec const *timeout,
3524            sigset_t const *sigmask)
3525 /* --------------------------------------------------------------------------
3526      Replacement for select, checking for events
3527    -------------------------------------------------------------------------- */
3529   int result;
3530   int t, k, nr = 0;
3531   struct input_event event;
3532   char c;
3534 /*  NSTRACE (ns_select); */
3536 #ifdef HAVE_NATIVE_FS
3537   check_native_fs ();
3538 #endif
3540   if (hold_event_q.nr > 0)
3541     {
3542       /* We already have events pending. */
3543       raise (SIGIO);
3544       errno = EINTR;
3545       return -1;
3546     }
3548   for (k = 0; k < nfds+1; k++)
3549     {
3550       if (readfds && FD_ISSET(k, readfds)) ++nr;
3551       if (writefds && FD_ISSET(k, writefds)) ++nr;
3552     }
3554   if (NSApp == nil
3555       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3556     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3558   [outerpool release];
3559   outerpool = [[NSAutoreleasePool alloc] init];
3562   send_appdefined = YES;
3563   if (nr > 0)
3564     {
3565       pthread_mutex_lock (&select_mutex);
3566       select_nfds = nfds;
3567       select_valid = 0;
3568       if (readfds)
3569         {
3570           select_readfds = *readfds;
3571           select_valid += SELECT_HAVE_READ;
3572         }
3573       if (writefds)
3574         {
3575           select_writefds = *writefds;
3576           select_valid += SELECT_HAVE_WRITE;
3577         }
3579       if (timeout)
3580         {
3581           select_timeout = *timeout;
3582           select_valid += SELECT_HAVE_TMO;
3583         }
3585       pthread_mutex_unlock (&select_mutex);
3587       /* Inform fd_handler that select should be called */
3588       c = 'g';
3589       emacs_write_sig (selfds[1], &c, 1);
3590     }
3591   else if (nr == 0 && timeout)
3592     {
3593       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3594       double time = timespectod (*timeout);
3595       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3596                                                       target: NSApp
3597                                                     selector:
3598                                   @selector (timeout_handler:)
3599                                                     userInfo: 0
3600                                                      repeats: NO]
3601                       retain];
3602     }
3603   else /* No timeout and no file descriptors, can this happen?  */
3604     {
3605       /* Send appdefined so we exit from the loop */
3606       ns_send_appdefined (-1);
3607     }
3609   EVENT_INIT (event);
3610   block_input ();
3611   emacs_event = &event;
3612   if (++apploopnr != 1)
3613     {
3614       emacs_abort ();
3615     }
3616   [NSApp run];
3617   --apploopnr;
3618   emacs_event = NULL;
3619   if (nr > 0 && readfds)
3620     {
3621       c = 's';
3622       emacs_write_sig (selfds[1], &c, 1);
3623     }
3624   unblock_input ();
3626   t = last_appdefined_event_data;
3628   if (t != NO_APPDEFINED_DATA)
3629     {
3630       last_appdefined_event_data = NO_APPDEFINED_DATA;
3632       if (t == -2)
3633         {
3634           /* The NX_APPDEFINED event we received was a timeout. */
3635           result = 0;
3636         }
3637       else if (t == -1)
3638         {
3639           /* The NX_APPDEFINED event we received was the result of
3640              at least one real input event arriving.  */
3641           errno = EINTR;
3642           result = -1;
3643         }
3644       else
3645         {
3646           /* Received back from select () in fd_handler; copy the results */
3647           pthread_mutex_lock (&select_mutex);
3648           if (readfds) *readfds = select_readfds;
3649           if (writefds) *writefds = select_writefds;
3650           pthread_mutex_unlock (&select_mutex);
3651           result = t;
3652         }
3653     }
3654   else
3655     {
3656       errno = EINTR;
3657       result = -1;
3658     }
3660   return result;
3665 /* ==========================================================================
3667     Scrollbar handling
3669    ========================================================================== */
3672 static void
3673 ns_set_vertical_scroll_bar (struct window *window,
3674                            int portion, int whole, int position)
3675 /* --------------------------------------------------------------------------
3676       External (hook): Update or add scrollbar
3677    -------------------------------------------------------------------------- */
3679   Lisp_Object win;
3680   NSRect r, v;
3681   struct frame *f = XFRAME (WINDOW_FRAME (window));
3682   EmacsView *view = FRAME_NS_VIEW (f);
3683   int window_y, window_height;
3684   int top, left, height, width, sb_width, sb_left;
3685   EmacsScroller *bar;
3686   BOOL fringe_extended_p;
3688   /* optimization; display engine sends WAY too many of these.. */
3689   if (!NILP (window->vertical_scroll_bar))
3690     {
3691       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3692       if ([bar checkSamePosition: position portion: portion whole: whole])
3693         {
3694           if (view->scrollbarsNeedingUpdate == 0)
3695             {
3696               if (!windows_or_buffers_changed)
3697                   return;
3698             }
3699           else
3700             view->scrollbarsNeedingUpdate--;
3701         }
3702     }
3704   NSTRACE (ns_set_vertical_scroll_bar);
3706   /* Get dimensions.  */
3707   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3708   top = window_y;
3709   height = window_height;
3710   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3711   left = WINDOW_SCROLL_BAR_AREA_X (window);
3713   /* allow for displaying a skinnier scrollbar than char area allotted */
3714   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3715     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3716   sb_left = left;
3718   r = NSMakeRect (sb_left, top, sb_width, height);
3719   /* the parent view is flipped, so we need to flip y value */
3720   v = [view frame];
3721   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3723   fringe_extended_p = WINDOW_FRINGE_EXTENDED_P (window);
3725   XSETWINDOW (win, window);
3726   block_input ();
3728   /* we want at least 5 lines to display a scrollbar */
3729   if (WINDOW_TOTAL_LINES (window) < 5)
3730     {
3731       if (!NILP (window->vertical_scroll_bar))
3732         {
3733           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3734           [bar removeFromSuperview];
3735           wset_vertical_scroll_bar (window, Qnil);
3736         }
3737       ns_clear_frame_area (f, sb_left, top, width, height);
3738       unblock_input ();
3739       return;
3740     }
3742   if (NILP (window->vertical_scroll_bar))
3743     {
3744       if (width > 0 && height > 0)
3745         {
3746           if (fringe_extended_p)
3747             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3748           else
3749             ns_clear_frame_area (f, left, top, width, height);
3750         }
3752       bar = [[EmacsScroller alloc] initFrame: r window: win];
3753       wset_vertical_scroll_bar (window, make_save_ptr (bar));
3754     }
3755   else
3756     {
3757       NSRect oldRect;
3758       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3759       oldRect = [bar frame];
3760       r.size.width = oldRect.size.width;
3761       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3762         {
3763           if (oldRect.origin.x != r.origin.x)
3764               ns_clear_frame_area (f, sb_left, top, width, height);
3765           [bar setFrame: r];
3766         }
3767     }
3769   [bar setPosition: position portion: portion whole: whole];
3770   unblock_input ();
3774 static void
3775 ns_condemn_scroll_bars (struct frame *f)
3776 /* --------------------------------------------------------------------------
3777      External (hook): arrange for all frame's scrollbars to be removed
3778      at next call to judge_scroll_bars, except for those redeemed.
3779    -------------------------------------------------------------------------- */
3781   int i;
3782   id view;
3783   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3785   NSTRACE (ns_condemn_scroll_bars);
3787   for (i =[subviews count]-1; i >= 0; i--)
3788     {
3789       view = [subviews objectAtIndex: i];
3790       if ([view isKindOfClass: [EmacsScroller class]])
3791         [view condemn];
3792     }
3796 static void
3797 ns_redeem_scroll_bar (struct window *window)
3798 /* --------------------------------------------------------------------------
3799      External (hook): arrange to spare this window's scrollbar
3800      at next call to judge_scroll_bars.
3801    -------------------------------------------------------------------------- */
3803   id bar;
3804   NSTRACE (ns_redeem_scroll_bar);
3805   if (!NILP (window->vertical_scroll_bar))
3806     {
3807       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3808       [bar reprieve];
3809     }
3813 static void
3814 ns_judge_scroll_bars (struct frame *f)
3815 /* --------------------------------------------------------------------------
3816      External (hook): destroy all scrollbars on frame that weren't
3817      redeemed after call to condemn_scroll_bars.
3818    -------------------------------------------------------------------------- */
3820   int i;
3821   id view;
3822   EmacsView *eview = FRAME_NS_VIEW (f);
3823   NSArray *subviews = [[eview superview] subviews];
3824   BOOL removed = NO;
3826   NSTRACE (ns_judge_scroll_bars);
3827   for (i = [subviews count]-1; i >= 0; --i)
3828     {
3829       view = [subviews objectAtIndex: i];
3830       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3831       [view judge];
3832       removed = YES;
3833     }
3835   if (removed)
3836     [eview updateFrameSize: NO];
3839 /* ==========================================================================
3841     Initialization
3843    ========================================================================== */
3846 x_display_pixel_height (struct ns_display_info *dpyinfo)
3848   NSArray *screens = [NSScreen screens];
3849   NSEnumerator *enumerator = [screens objectEnumerator];
3850   NSScreen *screen;
3851   NSRect frame;
3853   frame = NSZeroRect;
3854   while ((screen = [enumerator nextObject]) != nil)
3855     frame = NSUnionRect (frame, [screen frame]);
3857   return NSHeight (frame);
3861 x_display_pixel_width (struct ns_display_info *dpyinfo)
3863   NSArray *screens = [NSScreen screens];
3864   NSEnumerator *enumerator = [screens objectEnumerator];
3865   NSScreen *screen;
3866   NSRect frame;
3868   frame = NSZeroRect;
3869   while ((screen = [enumerator nextObject]) != nil)
3870     frame = NSUnionRect (frame, [screen frame]);
3872   return NSWidth (frame);
3876 static Lisp_Object ns_string_to_lispmod (const char *s)
3877 /* --------------------------------------------------------------------------
3878      Convert modifier name to lisp symbol
3879    -------------------------------------------------------------------------- */
3881   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3882     return Qmeta;
3883   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3884     return Qsuper;
3885   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3886     return Qcontrol;
3887   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3888     return Qalt;
3889   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3890     return Qhyper;
3891   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3892     return Qnone;
3893   else
3894     return Qnil;
3898 static void
3899 ns_default (const char *parameter, Lisp_Object *result,
3900            Lisp_Object yesval, Lisp_Object noval,
3901            BOOL is_float, BOOL is_modstring)
3902 /* --------------------------------------------------------------------------
3903       Check a parameter value in user's preferences
3904    -------------------------------------------------------------------------- */
3906   const char *value = ns_get_defaults_value (parameter);
3908   if (value)
3909     {
3910       double f;
3911       char *pos;
3912       if (c_strcasecmp (value, "YES") == 0)
3913         *result = yesval;
3914       else if (c_strcasecmp (value, "NO") == 0)
3915         *result = noval;
3916       else if (is_float && (f = strtod (value, &pos), pos != value))
3917         *result = make_float (f);
3918       else if (is_modstring && value)
3919         *result = ns_string_to_lispmod (value);
3920       else fprintf (stderr,
3921                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3922     }
3926 static void
3927 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3928 /* --------------------------------------------------------------------------
3929       Initialize global info and storage for display.
3930    -------------------------------------------------------------------------- */
3932     NSScreen *screen = [NSScreen mainScreen];
3933     NSWindowDepth depth = [screen depth];
3935     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3936     dpyinfo->resy = 72.27;
3937     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3938                                                   NSColorSpaceFromDepth (depth)]
3939                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3940                                                  NSColorSpaceFromDepth (depth)];
3941     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3942     dpyinfo->image_cache = make_image_cache ();
3943     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
3944     dpyinfo->color_table->colors = NULL;
3945     dpyinfo->root_window = 42; /* a placeholder.. */
3946     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3947     dpyinfo->n_fonts = 0;
3948     dpyinfo->smallest_font_height = 1;
3949     dpyinfo->smallest_char_width = 1;
3951     reset_mouse_highlight (&dpyinfo->mouse_highlight);
3955 /* This and next define (many of the) public functions in this file. */
3956 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3957          with using despite presence in the "system dependent" redisplay
3958          interface.  In addition, many of the ns_ methods have code that is
3959          shared with all terms, indicating need for further refactoring. */
3960 extern frame_parm_handler ns_frame_parm_handlers[];
3961 static struct redisplay_interface ns_redisplay_interface =
3963   ns_frame_parm_handlers,
3964   x_produce_glyphs,
3965   x_write_glyphs,
3966   x_insert_glyphs,
3967   x_clear_end_of_line,
3968   ns_scroll_run,
3969   ns_after_update_window_line,
3970   ns_update_window_begin,
3971   ns_update_window_end,
3972   0, /* flush_display */
3973   x_clear_window_mouse_face,
3974   x_get_glyph_overhangs,
3975   x_fix_overlapping_area,
3976   ns_draw_fringe_bitmap,
3977   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3978   0, /* destroy_fringe_bitmap */
3979   ns_compute_glyph_string_overhangs,
3980   ns_draw_glyph_string,
3981   ns_define_frame_cursor,
3982   ns_clear_frame_area,
3983   ns_draw_window_cursor,
3984   ns_draw_vertical_window_border,
3985   ns_shift_glyphs_for_insert
3989 static void
3990 ns_delete_display (struct ns_display_info *dpyinfo)
3992   /* TODO... */
3996 /* This function is called when the last frame on a display is deleted. */
3997 static void
3998 ns_delete_terminal (struct terminal *terminal)
4000   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4002   /* Protect against recursive calls.  delete_frame in
4003      delete_terminal calls us back when it deletes our last frame.  */
4004   if (!terminal->name)
4005     return;
4007   block_input ();
4009   x_destroy_all_bitmaps (dpyinfo);
4010   ns_delete_display (dpyinfo);
4011   unblock_input ();
4015 static struct terminal *
4016 ns_create_terminal (struct ns_display_info *dpyinfo)
4017 /* --------------------------------------------------------------------------
4018       Set up use of NS before we make the first connection.
4019    -------------------------------------------------------------------------- */
4021   struct terminal *terminal;
4023   NSTRACE (ns_create_terminal);
4025   terminal = create_terminal ();
4027   terminal->type = output_ns;
4028   terminal->display_info.ns = dpyinfo;
4029   dpyinfo->terminal = terminal;
4031   terminal->rif = &ns_redisplay_interface;
4033   terminal->clear_frame_hook = ns_clear_frame;
4034   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4035   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
4036   terminal->ring_bell_hook = ns_ring_bell;
4037   terminal->reset_terminal_modes_hook = NULL;
4038   terminal->set_terminal_modes_hook = NULL;
4039   terminal->update_begin_hook = ns_update_begin;
4040   terminal->update_end_hook = ns_update_end;
4041   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4042   terminal->read_socket_hook = ns_read_socket;
4043   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4044   terminal->mouse_position_hook = ns_mouse_position;
4045   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4046   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4048   terminal->fullscreen_hook = ns_fullscreen_hook;
4050   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4051   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4052   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4053   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4055   terminal->delete_frame_hook = x_destroy_window;
4056   terminal->delete_terminal_hook = ns_delete_terminal;
4058   terminal->scroll_region_ok = 1;
4059   terminal->char_ins_del_ok = 1;
4060   terminal->line_ins_del_ok = 1;
4061   terminal->fast_clear_end_of_line = 1;
4062   terminal->memory_below_frame = 0;
4064   return terminal;
4068 struct ns_display_info *
4069 ns_term_init (Lisp_Object display_name)
4070 /* --------------------------------------------------------------------------
4071      Start the Application and get things rolling.
4072    -------------------------------------------------------------------------- */
4074   struct terminal *terminal;
4075   struct ns_display_info *dpyinfo;
4076   static int ns_initialized = 0;
4077   Lisp_Object tmp;
4079   if (ns_initialized) return x_display_list;
4080   ns_initialized = 1;
4082   NSTRACE (ns_term_init);
4084   [outerpool release];
4085   outerpool = [[NSAutoreleasePool alloc] init];
4087   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4088   /*GSDebugAllocationActive (YES); */
4089   block_input ();
4091   baud_rate = 38400;
4092   Fset_input_interrupt_mode (Qnil);
4094   if (selfds[0] == -1)
4095     {
4096       if (emacs_pipe (selfds) != 0)
4097         {
4098           fprintf (stderr, "Failed to create pipe: %s\n",
4099                    emacs_strerror (errno));
4100           emacs_abort ();
4101         }
4103       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4104       FD_ZERO (&select_readfds);
4105       FD_ZERO (&select_writefds);
4106       pthread_mutex_init (&select_mutex, NULL);
4107     }
4109   ns_pending_files = [[NSMutableArray alloc] init];
4110   ns_pending_service_names = [[NSMutableArray alloc] init];
4111   ns_pending_service_args = [[NSMutableArray alloc] init];
4113 /* Start app and create the main menu, window, view.
4114      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4115      The view will then ask the NSApp to stop and return to Emacs. */
4116   [EmacsApp sharedApplication];
4117   if (NSApp == nil)
4118     return NULL;
4119   [NSApp setDelegate: NSApp];
4121   /* Start the select thread.  */
4122   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4123                            toTarget:NSApp
4124                          withObject:nil];
4126   /* debugging: log all notifications */
4127   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4128                                          selector: @selector (logNotification:)
4129                                              name: nil object: nil]; */
4131   dpyinfo = xzalloc (sizeof *dpyinfo);
4133   ns_initialize_display_info (dpyinfo);
4134   terminal = ns_create_terminal (dpyinfo);
4136   terminal->kboard = xmalloc (sizeof *terminal->kboard);
4137   init_kboard (terminal->kboard);
4138   kset_window_system (terminal->kboard, Qns);
4139   terminal->kboard->next_kboard = all_kboards;
4140   all_kboards = terminal->kboard;
4141   /* Don't let the initial kboard remain current longer than necessary.
4142      That would cause problems if a file loaded on startup tries to
4143      prompt in the mini-buffer.  */
4144   if (current_kboard == initial_kboard)
4145     current_kboard = terminal->kboard;
4146   terminal->kboard->reference_count++;
4148   dpyinfo->next = x_display_list;
4149   x_display_list = dpyinfo;
4151   /* Put it on ns_display_name_list */
4152   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4153                                 ns_display_name_list);
4154   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4156   terminal->name = xstrdup (SSDATA (display_name));
4158   unblock_input ();
4160   if (!inhibit_x_resources)
4161     {
4162       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4163                  Qt, Qnil, NO, NO);
4164       tmp = Qnil;
4165       /* this is a standard variable */
4166       ns_default ("AppleAntiAliasingThreshold", &tmp,
4167                  make_float (10.0), make_float (6.0), YES, NO);
4168       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4169     }
4171   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4172                          stringForKey: @"AppleHighlightColor"];
4173   if (ns_selection_color == nil)
4174     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4176   {
4177     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4179     if ( cl == nil )
4180       {
4181         Lisp_Object color_file, color_map, color;
4182         unsigned long c;
4183         char *name;
4185         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4186                          Fsymbol_value (intern ("data-directory")));
4188         color_map = Fx_load_color_file (color_file);
4189         if (NILP (color_map))
4190           fatal ("Could not read %s.\n", SDATA (color_file));
4192         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4193         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4194           {
4195             color = XCAR (color_map);
4196             name = SSDATA (XCAR (color));
4197             c = XINT (XCDR (color));
4198             [cl setColor:
4199                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4200                                             green: GREEN_FROM_ULONG (c) / 255.0
4201                                              blue: BLUE_FROM_ULONG (c) / 255.0
4202                                             alpha: 1.0]
4203                   forKey: [NSString stringWithUTF8String: name]];
4204           }
4205         [cl writeToFile: nil];
4206       }
4207   }
4209   {
4210 #ifdef NS_IMPL_GNUSTEP
4211     Vwindow_system_version = build_string (gnustep_base_version);
4212 #else
4213     /*PSnextrelease (128, c); */
4214     char c[DBL_BUFSIZE_BOUND];
4215     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4216     Vwindow_system_version = make_unibyte_string (c, len);
4217 #endif
4218   }
4220   delete_keyboard_wait_descriptor (0);
4222   ns_app_name = [[NSProcessInfo processInfo] processName];
4224 /* Set up OS X app menu */
4225 #ifdef NS_IMPL_COCOA
4226   {
4227     NSMenu *appMenu;
4228     NSMenuItem *item;
4229     /* set up the application menu */
4230     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4231     [svcsMenu setAutoenablesItems: NO];
4232     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4233     [appMenu setAutoenablesItems: NO];
4234     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4235     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4237     [appMenu insertItemWithTitle: @"About Emacs"
4238                           action: @selector (orderFrontStandardAboutPanel:)
4239                    keyEquivalent: @""
4240                          atIndex: 0];
4241     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4242     [appMenu insertItemWithTitle: @"Preferences..."
4243                           action: @selector (showPreferencesWindow:)
4244                    keyEquivalent: @","
4245                          atIndex: 2];
4246     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4247     item = [appMenu insertItemWithTitle: @"Services"
4248                                  action: @selector (menuDown:)
4249                           keyEquivalent: @""
4250                                 atIndex: 4];
4251     [appMenu setSubmenu: svcsMenu forItem: item];
4252     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4253     [appMenu insertItemWithTitle: @"Hide Emacs"
4254                           action: @selector (hide:)
4255                    keyEquivalent: @"h"
4256                          atIndex: 6];
4257     item =  [appMenu insertItemWithTitle: @"Hide Others"
4258                           action: @selector (hideOtherApplications:)
4259                    keyEquivalent: @"h"
4260                          atIndex: 7];
4261     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4262     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4263     [appMenu insertItemWithTitle: @"Quit Emacs"
4264                           action: @selector (terminate:)
4265                    keyEquivalent: @"q"
4266                          atIndex: 9];
4268     item = [mainMenu insertItemWithTitle: ns_app_name
4269                                   action: @selector (menuDown:)
4270                            keyEquivalent: @""
4271                                  atIndex: 0];
4272     [mainMenu setSubmenu: appMenu forItem: item];
4273     [dockMenu insertItemWithTitle: @"New Frame"
4274                            action: @selector (newFrame:)
4275                     keyEquivalent: @""
4276                           atIndex: 0];
4278     [NSApp setMainMenu: mainMenu];
4279     [NSApp setAppleMenu: appMenu];
4280     [NSApp setServicesMenu: svcsMenu];
4281     /* Needed at least on Cocoa, to get dock menu to show windows */
4282     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4284     [[NSNotificationCenter defaultCenter]
4285       addObserver: mainMenu
4286          selector: @selector (trackingNotification:)
4287              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4288     [[NSNotificationCenter defaultCenter]
4289       addObserver: mainMenu
4290          selector: @selector (trackingNotification:)
4291              name: NSMenuDidEndTrackingNotification object: mainMenu];
4292   }
4293 #endif /* MAC OS X menu setup */
4295   /* Register our external input/output types, used for determining
4296      applicable services and also drag/drop eligibility. */
4297   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4298   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4299                       retain];
4300   ns_drag_types = [[NSArray arrayWithObjects:
4301                             NSStringPboardType,
4302                             NSTabularTextPboardType,
4303                             NSFilenamesPboardType,
4304                             NSURLPboardType,
4305                             NSColorPboardType,
4306                             NSFontPboardType, nil] retain];
4308   /* If fullscreen is in init/default-frame-alist, focus isn't set
4309      right for fullscreen windows, so set this.  */
4310   [NSApp activateIgnoringOtherApps:YES];
4312   [NSApp run];
4313   ns_do_open_file = YES;
4315 #ifdef NS_IMPL_GNUSTEP
4316   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4317      We must re-catch it so subprocess works.  */
4318   catch_child_signal ();
4319 #endif
4320   return dpyinfo;
4324 void
4325 ns_term_shutdown (int sig)
4327   [[NSUserDefaults standardUserDefaults] synchronize];
4329   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4330   if (STRINGP (Vauto_save_list_file_name))
4331     unlink (SSDATA (Vauto_save_list_file_name));
4333   if (sig == 0 || sig == SIGTERM)
4334     {
4335       [NSApp terminate: NSApp];
4336     }
4337   else // force a stack trace to happen
4338     {
4339       emacs_abort ();
4340     }
4344 /* ==========================================================================
4346     EmacsApp implementation
4348    ========================================================================== */
4351 @implementation EmacsApp
4353 - (void)logNotification: (NSNotification *)notification
4355   const char *name = [[notification name] UTF8String];
4356   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4357       && !strstr (name, "WindowNumber"))
4358     NSLog (@"notification: '%@'", [notification name]);
4362 - (void)sendEvent: (NSEvent *)theEvent
4363 /* --------------------------------------------------------------------------
4364      Called when NSApp is running for each event received.  Used to stop
4365      the loop when we choose, since there's no way to just run one iteration.
4366    -------------------------------------------------------------------------- */
4368   int type = [theEvent type];
4369   NSWindow *window = [theEvent window];
4371 /*  NSTRACE (sendEvent); */
4372 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4374 #ifdef NS_IMPL_GNUSTEP
4375   // Keyboard events aren't propagated to file dialogs for some reason.
4376   if ([NSApp modalWindow] != nil &&
4377       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4378     {
4379       [[NSApp modalWindow] sendEvent: theEvent];
4380       return;
4381     }
4382 #endif
4384   if (type == NSApplicationDefined)
4385     {
4386       switch ([theEvent data2])
4387         {
4388 #ifdef NS_IMPL_COCOA
4389         case NSAPP_DATA2_RUNASSCRIPT:
4390           ns_run_ascript ();
4391           [self stop: self];
4392           return;
4393 #endif
4394         case NSAPP_DATA2_RUNFILEDIALOG:
4395           ns_run_file_dialog ();
4396           [self stop: self];
4397           return;
4398         }
4399     }
4401   if (type == NSCursorUpdate && window == nil)
4402     {
4403       fprintf (stderr, "Dropping external cursor update event.\n");
4404       return;
4405     }
4407   if (type == NSApplicationDefined)
4408     {
4409       /* Events posted by ns_send_appdefined interrupt the run loop here.
4410          But, if a modal window is up, an appdefined can still come through,
4411          (e.g., from a makeKeyWindow event) but stopping self also stops the
4412          modal loop. Just defer it until later. */
4413       if ([NSApp modalWindow] == nil)
4414         {
4415           last_appdefined_event_data = [theEvent data1];
4416           [self stop: self];
4417         }
4418       else
4419         {
4420           send_appdefined = YES;
4421         }
4422     }
4425 #ifdef NS_IMPL_COCOA
4426   /* If no dialog and none of our frames have focus and it is a move, skip it.
4427      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4428      such as Wifi, sound, date or similar.
4429      This prevents "spooky" highlighting in the frame under the menu.  */
4430   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4431     {
4432       struct ns_display_info *di;
4433       BOOL has_focus = NO;
4434       for (di = x_display_list; ! has_focus && di; di = di->next)
4435         has_focus = di->x_focus_frame != 0;
4436       if (! has_focus)
4437         return;
4438     }
4439 #endif
4441   [super sendEvent: theEvent];
4445 - (void)showPreferencesWindow: (id)sender
4447   struct frame *emacsframe = SELECTED_FRAME ();
4448   NSEvent *theEvent = [NSApp currentEvent];
4450   if (!emacs_event)
4451     return;
4452   emacs_event->kind = NS_NONKEY_EVENT;
4453   emacs_event->code = KEY_NS_SHOW_PREFS;
4454   emacs_event->modifiers = 0;
4455   EV_TRAILER (theEvent);
4459 - (void)newFrame: (id)sender
4461   struct frame *emacsframe = SELECTED_FRAME ();
4462   NSEvent *theEvent = [NSApp currentEvent];
4464   if (!emacs_event)
4465     return;
4466   emacs_event->kind = NS_NONKEY_EVENT;
4467   emacs_event->code = KEY_NS_NEW_FRAME;
4468   emacs_event->modifiers = 0;
4469   EV_TRAILER (theEvent);
4473 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4474 - (BOOL) openFile: (NSString *)fileName
4476   struct frame *emacsframe = SELECTED_FRAME ();
4477   NSEvent *theEvent = [NSApp currentEvent];
4479   if (!emacs_event)
4480     return NO;
4482   emacs_event->kind = NS_NONKEY_EVENT;
4483   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4484   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4485   ns_input_line = Qnil; /* can be start or cons start,end */
4486   emacs_event->modifiers =0;
4487   EV_TRAILER (theEvent);
4489   return YES;
4493 /* **************************************************************************
4495       EmacsApp delegate implementation
4497    ************************************************************************** */
4499 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4500 /* --------------------------------------------------------------------------
4501      When application is loaded, terminate event loop in ns_term_init
4502    -------------------------------------------------------------------------- */
4504   NSTRACE (applicationDidFinishLaunching);
4505   [NSApp setServicesProvider: NSApp];
4506   ns_send_appdefined (-2);
4510 /* Termination sequences:
4511     C-x C-c:
4512     Cmd-Q:
4513     MenuBar | File | Exit:
4514     Select Quit from App menubar:
4515         -terminate
4516         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4517         ns_term_shutdown()
4519     Select Quit from Dock menu:
4520     Logout attempt:
4521         -appShouldTerminate
4522           Cancel -> Nothing else
4523           Accept ->
4525           -terminate
4526           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4527           ns_term_shutdown()
4531 - (void) terminate: (id)sender
4533   struct frame *emacsframe = SELECTED_FRAME ();
4535   if (!emacs_event)
4536     return;
4538   emacs_event->kind = NS_NONKEY_EVENT;
4539   emacs_event->code = KEY_NS_POWER_OFF;
4540   emacs_event->arg = Qt; /* mark as non-key event */
4541   EV_TRAILER ((id)nil);
4545 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4547   int ret;
4549   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4550     return NSTerminateNow;
4552     ret = NSRunAlertPanel(ns_app_name,
4553                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4554                           @"Save Buffers and Exit", @"Cancel", nil);
4556     if (ret == NSAlertDefaultReturn)
4557         return NSTerminateNow;
4558     else if (ret == NSAlertAlternateReturn)
4559         return NSTerminateCancel;
4560     return NSTerminateNow;  /* just in case */
4563 static int
4564 not_in_argv (NSString *arg)
4566   int k;
4567   const char *a = [arg UTF8String];
4568   for (k = 1; k < initial_argc; ++k)
4569     if (strcmp (a, initial_argv[k]) == 0) return 0;
4570   return 1;
4573 /*   Notification from the Workspace to open a file */
4574 - (BOOL)application: sender openFile: (NSString *)file
4576   if (ns_do_open_file || not_in_argv (file))
4577     [ns_pending_files addObject: file];
4578   return YES;
4582 /*   Open a file as a temporary file */
4583 - (BOOL)application: sender openTempFile: (NSString *)file
4585   if (ns_do_open_file || not_in_argv (file))
4586     [ns_pending_files addObject: file];
4587   return YES;
4591 /*   Notification from the Workspace to open a file noninteractively (?) */
4592 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4594   if (ns_do_open_file || not_in_argv (file))
4595     [ns_pending_files addObject: file];
4596   return YES;
4599 /*   Notification from the Workspace to open multiple files */
4600 - (void)application: sender openFiles: (NSArray *)fileList
4602   NSEnumerator *files = [fileList objectEnumerator];
4603   NSString *file;
4604   /* Don't open files from the command line unconditionally,
4605      Cocoa parses the command line wrong, --option value tries to open value
4606      if --option is the last option.  */
4607   while ((file = [files nextObject]) != nil)
4608     if (ns_do_open_file || not_in_argv (file))
4609       [ns_pending_files addObject: file];
4611   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4616 /* Handle dock menu requests.  */
4617 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4619   return dockMenu;
4623 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4624 - (void)applicationWillBecomeActive: (NSNotification *)notification
4626   //ns_app_active=YES;
4628 - (void)applicationDidBecomeActive: (NSNotification *)notification
4630   NSTRACE (applicationDidBecomeActive);
4632   //ns_app_active=YES;
4634   ns_update_auto_hide_menu_bar ();
4635   // No constraining takes place when the application is not active.
4636   ns_constrain_all_frames ();
4638 - (void)applicationDidResignActive: (NSNotification *)notification
4640   //ns_app_active=NO;
4641   ns_send_appdefined (-1);
4646 /* ==========================================================================
4648     EmacsApp aux handlers for managing event loop
4650    ========================================================================== */
4653 - (void)timeout_handler: (NSTimer *)timedEntry
4654 /* --------------------------------------------------------------------------
4655      The timeout specified to ns_select has passed.
4656    -------------------------------------------------------------------------- */
4658   /*NSTRACE (timeout_handler); */
4659   ns_send_appdefined (-2);
4662 #ifdef NS_IMPL_GNUSTEP
4663 - (void)sendFromMainThread:(id)unused
4665   ns_send_appdefined (nextappdefined);
4667 #endif
4669 - (void)fd_handler:(id)unused
4670 /* --------------------------------------------------------------------------
4671      Check data waiting on file descriptors and terminate if so
4672    -------------------------------------------------------------------------- */
4674   int result;
4675   int waiting = 1, nfds;
4676   char c;
4678   fd_set readfds, writefds, *wfds;
4679   struct timespec timeout, *tmo;
4680   NSAutoreleasePool *pool = nil;
4682   /* NSTRACE (fd_handler); */
4684   for (;;)
4685     {
4686       [pool release];
4687       pool = [[NSAutoreleasePool alloc] init];
4689       if (waiting)
4690         {
4691           fd_set fds;
4692           FD_ZERO (&fds);
4693           FD_SET (selfds[0], &fds);
4694           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4695           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4696             waiting = 0;
4697         }
4698       else
4699         {
4700           pthread_mutex_lock (&select_mutex);
4701           nfds = select_nfds;
4703           if (select_valid & SELECT_HAVE_READ)
4704             readfds = select_readfds;
4705           else
4706             FD_ZERO (&readfds);
4708           if (select_valid & SELECT_HAVE_WRITE)
4709             {
4710               writefds = select_writefds;
4711               wfds = &writefds;
4712             }
4713           else
4714             wfds = NULL;
4715           if (select_valid & SELECT_HAVE_TMO)
4716             {
4717               timeout = select_timeout;
4718               tmo = &timeout;
4719             }
4720           else
4721             tmo = NULL;
4723           pthread_mutex_unlock (&select_mutex);
4725           FD_SET (selfds[0], &readfds);
4726           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4728           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4730           if (result == 0)
4731             ns_send_appdefined (-2);
4732           else if (result > 0)
4733             {
4734               if (FD_ISSET (selfds[0], &readfds))
4735                 {
4736                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4737                     waiting = 1;
4738                 }
4739               else
4740                 {
4741                   pthread_mutex_lock (&select_mutex);
4742                   if (select_valid & SELECT_HAVE_READ)
4743                     select_readfds = readfds;
4744                   if (select_valid & SELECT_HAVE_WRITE)
4745                     select_writefds = writefds;
4746                   if (select_valid & SELECT_HAVE_TMO)
4747                     select_timeout = timeout;
4748                   pthread_mutex_unlock (&select_mutex);
4750                   ns_send_appdefined (result);
4751                 }
4752             }
4753           waiting = 1;
4754         }
4755     }
4760 /* ==========================================================================
4762     Service provision
4764    ========================================================================== */
4766 /* called from system: queue for next pass through event loop */
4767 - (void)requestService: (NSPasteboard *)pboard
4768               userData: (NSString *)userData
4769                  error: (NSString **)error
4771   [ns_pending_service_names addObject: userData];
4772   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4773       SSDATA (ns_string_from_pasteboard (pboard))]];
4777 /* called from ns_read_socket to clear queue */
4778 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4780   struct frame *emacsframe = SELECTED_FRAME ();
4781   NSEvent *theEvent = [NSApp currentEvent];
4783   if (!emacs_event)
4784     return NO;
4786   emacs_event->kind = NS_NONKEY_EVENT;
4787   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4788   ns_input_spi_name = build_string ([name UTF8String]);
4789   ns_input_spi_arg = build_string ([arg UTF8String]);
4790   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4791   EV_TRAILER (theEvent);
4793   return YES;
4797 @end  /* EmacsApp */
4801 /* ==========================================================================
4803     EmacsView implementation
4805    ========================================================================== */
4808 @implementation EmacsView
4810 /* needed to inform when window closed from LISP */
4811 - (void) setWindowClosing: (BOOL)closing
4813   windowClosing = closing;
4817 - (void)dealloc
4819   NSTRACE (EmacsView_dealloc);
4820   [toolbar release];
4821   if (fs_state == FULLSCREEN_BOTH)
4822     [nonfs_window release];
4823   [super dealloc];
4827 /* called on font panel selection */
4828 - (void)changeFont: (id)sender
4830   NSEvent *e = [[self window] currentEvent];
4831   struct face *face = FRAME_DEFAULT_FACE (emacsframe);
4832   struct font *font = face->font;
4833   id newFont;
4834   CGFloat size;
4835   NSFont *nsfont;
4837   NSTRACE (changeFont);
4839   if (!emacs_event)
4840     return;
4842   if (EQ (font->driver->type, Qns))
4843     nsfont = ((struct nsfont_info *)font)->nsfont;
4844 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
4845   else
4846     nsfont = (NSFont *) macfont_get_nsctfont (font);
4847 #endif
4849   if ((newFont = [sender convertFont: nsfont]))
4850     {
4851       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4853       emacs_event->kind = NS_NONKEY_EVENT;
4854       emacs_event->modifiers = 0;
4855       emacs_event->code = KEY_NS_CHANGE_FONT;
4857       size = [newFont pointSize];
4858       ns_input_fontsize = make_number (lrint (size));
4859       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4860       EV_TRAILER (e);
4861     }
4865 - (BOOL)acceptsFirstResponder
4867   NSTRACE (acceptsFirstResponder);
4868   return YES;
4872 - (void)resetCursorRects
4874   NSRect visible = [self visibleRect];
4875   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4876   NSTRACE (resetCursorRects);
4878   if (currentCursor == nil)
4879     currentCursor = [NSCursor arrowCursor];
4881   if (!NSIsEmptyRect (visible))
4882     [self addCursorRect: visible cursor: currentCursor];
4883   [currentCursor setOnMouseEntered: YES];
4888 /*****************************************************************************/
4889 /* Keyboard handling. */
4890 #define NS_KEYLOG 0
4892 - (void)keyDown: (NSEvent *)theEvent
4894   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4895   int code;
4896   unsigned fnKeysym = 0;
4897   static NSMutableArray *nsEvArray;
4898 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4899   static BOOL firstTime = YES;
4900 #endif
4901   int left_is_none;
4902   unsigned int flags = [theEvent modifierFlags];
4904   NSTRACE (keyDown);
4906   /* Rhapsody and OS X give up and down events for the arrow keys */
4907   if (ns_fake_keydown == YES)
4908     ns_fake_keydown = NO;
4909   else if ([theEvent type] != NSKeyDown)
4910     return;
4912   if (!emacs_event)
4913     return;
4915  if (![[self window] isKeyWindow]
4916      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4917      /* we must avoid an infinite loop here. */
4918      && (EmacsView *)[[theEvent window] delegate] != self)
4919    {
4920      /* XXX: There is an occasional condition in which, when Emacs display
4921          updates a different frame from the current one, and temporarily
4922          selects it, then processes some interrupt-driven input
4923          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4924          for some reason that window has its first responder set to the NSView
4925          most recently updated (I guess), which is not the correct one. */
4926      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4927      return;
4928    }
4930   if (nsEvArray == nil)
4931     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4933   [NSCursor setHiddenUntilMouseMoves: YES];
4935   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4936     {
4937       clear_mouse_face (hlinfo);
4938       hlinfo->mouse_face_hidden = 1;
4939     }
4941   if (!processingCompose)
4942     {
4943       /* When using screen sharing, no left or right information is sent,
4944          so use Left key in those cases.  */
4945       int is_left_key, is_right_key;
4947       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4948         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4950       /* (Carbon way: [theEvent keyCode]) */
4952       /* is it a "function key"? */
4953       fnKeysym = (code < 0x00ff && (flags&NSNumericPadKeyMask))
4954         ? ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask)
4955         : ns_convert_key (code);
4957       if (fnKeysym)
4958         {
4959           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4960              because Emacs treats Delete and KP-Delete same (in simple.el). */
4961           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4962 #ifdef NS_IMPL_GNUSTEP
4963               /*  GNUstep uses incompatible keycodes, even for those that are
4964                   supposed to be hardware independent.  Just check for delete.
4965                   Keypad delete does not have keysym 0xFFFF.
4966                   See http://savannah.gnu.org/bugs/?25395
4967               */
4968               || (fnKeysym == 0xFFFF && code == 127)
4969 #endif
4970             )
4971             code = 0xFF08; /* backspace */
4972           else
4973             code = fnKeysym;
4974         }
4976       /* are there modifiers? */
4977       emacs_event->modifiers = 0;
4979       if (flags & NSHelpKeyMask)
4980           emacs_event->modifiers |= hyper_modifier;
4982       if (flags & NSShiftKeyMask)
4983         emacs_event->modifiers |= shift_modifier;
4985       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
4986       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
4987         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
4989       if (is_right_key)
4990         emacs_event->modifiers |= parse_solitary_modifier
4991           (EQ (ns_right_command_modifier, Qleft)
4992            ? ns_command_modifier
4993            : ns_right_command_modifier);
4995       if (is_left_key)
4996         {
4997           emacs_event->modifiers |= parse_solitary_modifier
4998             (ns_command_modifier);
5000           /* if super (default), take input manager's word so things like
5001              dvorak / qwerty layout work */
5002           if (EQ (ns_command_modifier, Qsuper)
5003               && !fnKeysym
5004               && [[theEvent characters] length] != 0)
5005             {
5006               /* XXX: the code we get will be unshifted, so if we have
5007                  a shift modifier, must convert ourselves */
5008               if (!(flags & NSShiftKeyMask))
5009                 code = [[theEvent characters] characterAtIndex: 0];
5010 #if 0
5011               /* this is ugly and also requires linking w/Carbon framework
5012                  (for LMGetKbdType) so for now leave this rare (?) case
5013                  undealt with.. in future look into CGEvent methods */
5014               else
5015                 {
5016                   long smv = GetScriptManagerVariable (smKeyScript);
5017                   Handle uchrHandle = GetResource
5018                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5019                   UInt32 dummy = 0;
5020                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5021                                  [[theEvent characters] characterAtIndex: 0],
5022                                  kUCKeyActionDisplay,
5023                                  (flags & ~NSCommandKeyMask) >> 8,
5024                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5025                                  &dummy, 1, &dummy, &code);
5026                   code &= 0xFF;
5027                 }
5028 #endif
5029             }
5030         }
5032       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5033       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5034         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5036       if (is_right_key)
5037           emacs_event->modifiers |= parse_solitary_modifier
5038               (EQ (ns_right_control_modifier, Qleft)
5039                ? ns_control_modifier
5040                : ns_right_control_modifier);
5042       if (is_left_key)
5043         emacs_event->modifiers |= parse_solitary_modifier
5044           (ns_control_modifier);
5046       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5047           emacs_event->modifiers |=
5048             parse_solitary_modifier (ns_function_modifier);
5050       left_is_none = NILP (ns_alternate_modifier)
5051         || EQ (ns_alternate_modifier, Qnone);
5053       is_right_key = (flags & NSRightAlternateKeyMask)
5054         == NSRightAlternateKeyMask;
5055       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5056         || (! is_right_key
5057             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5059       if (is_right_key)
5060         {
5061           if ((NILP (ns_right_alternate_modifier)
5062                || EQ (ns_right_alternate_modifier, Qnone)
5063                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5064               && !fnKeysym)
5065             {   /* accept pre-interp alt comb */
5066               if ([[theEvent characters] length] > 0)
5067                 code = [[theEvent characters] characterAtIndex: 0];
5068               /*HACK: clear lone shift modifier to stop next if from firing */
5069               if (emacs_event->modifiers == shift_modifier)
5070                 emacs_event->modifiers = 0;
5071             }
5072           else
5073             emacs_event->modifiers |= parse_solitary_modifier
5074               (EQ (ns_right_alternate_modifier, Qleft)
5075                ? ns_alternate_modifier
5076                : ns_right_alternate_modifier);
5077         }
5079       if (is_left_key) /* default = meta */
5080         {
5081           if (left_is_none && !fnKeysym)
5082             {   /* accept pre-interp alt comb */
5083               if ([[theEvent characters] length] > 0)
5084                 code = [[theEvent characters] characterAtIndex: 0];
5085               /*HACK: clear lone shift modifier to stop next if from firing */
5086               if (emacs_event->modifiers == shift_modifier)
5087                 emacs_event->modifiers = 0;
5088             }
5089           else
5090               emacs_event->modifiers |=
5091                 parse_solitary_modifier (ns_alternate_modifier);
5092         }
5094   if (NS_KEYLOG)
5095     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5096              code, fnKeysym, flags, emacs_event->modifiers);
5098       /* if it was a function key or had modifiers, pass it directly to emacs */
5099       if (fnKeysym || (emacs_event->modifiers
5100                        && (emacs_event->modifiers != shift_modifier)
5101                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5102 /*[[theEvent characters] length] */
5103         {
5104           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5105           if (code < 0x20)
5106             code |= (1<<28)|(3<<16);
5107           else if (code == 0x7f)
5108             code |= (1<<28)|(3<<16);
5109           else if (!fnKeysym)
5110             emacs_event->kind = code > 0xFF
5111               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5113           emacs_event->code = code;
5114           EV_TRAILER (theEvent);
5115           processingCompose = NO;
5116           return;
5117         }
5118     }
5121 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5122   /* if we get here we should send the key for input manager processing */
5123   /* Disable warning, there is nothing a user can do about it anyway, and
5124      it does not seem to matter.  */
5125 #if 0
5126   if (firstTime && [[NSInputManager currentInputManager]
5127                      wantsToDelayTextChangeNotifications] == NO)
5128     fprintf (stderr,
5129           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5130 #endif
5131   firstTime = NO;
5132 #endif
5133   if (NS_KEYLOG && !processingCompose)
5134     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5136   processingCompose = YES;
5137   [nsEvArray addObject: theEvent];
5138   [self interpretKeyEvents: nsEvArray];
5139   [nsEvArray removeObject: theEvent];
5143 #ifdef NS_IMPL_COCOA
5144 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5145    decided not to send key-down for.
5146    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5147    This only applies on Tiger and earlier.
5148    If it matches one of these, send it on to keyDown. */
5149 -(void)keyUp: (NSEvent *)theEvent
5151   int flags = [theEvent modifierFlags];
5152   int code = [theEvent keyCode];
5153   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5154       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5155     {
5156       if (NS_KEYLOG)
5157         fprintf (stderr, "keyUp: passed test");
5158       ns_fake_keydown = YES;
5159       [self keyDown: theEvent];
5160     }
5162 #endif
5165 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5168 /* <NSTextInput>: called when done composing;
5169    NOTE: also called when we delete over working text, followed immed.
5170          by doCommandBySelector: deleteBackward: */
5171 - (void)insertText: (id)aString
5173   int code;
5174   int len = [(NSString *)aString length];
5175   int i;
5177   if (NS_KEYLOG)
5178     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5179   processingCompose = NO;
5181   if (!emacs_event)
5182     return;
5184   /* first, clear any working text */
5185   if (workingText != nil)
5186     [self deleteWorkingText];
5188   /* now insert the string as keystrokes */
5189   for (i =0; i<len; i++)
5190     {
5191       code = [aString characterAtIndex: i];
5192       /* TODO: still need this? */
5193       if (code == 0x2DC)
5194         code = '~'; /* 0x7E */
5195       if (code != 32) /* Space */
5196         emacs_event->modifiers = 0;
5197       emacs_event->kind
5198         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5199       emacs_event->code = code;
5200       EV_TRAILER ((id)nil);
5201     }
5205 /* <NSTextInput>: inserts display of composing characters */
5206 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5208   NSString *str = [aString respondsToSelector: @selector (string)] ?
5209     [aString string] : aString;
5210   if (NS_KEYLOG)
5211     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5212            str, (unsigned long)[str length],
5213            (unsigned long)selRange.length,
5214            (unsigned long)selRange.location);
5216   if (workingText != nil)
5217     [self deleteWorkingText];
5218   if ([str length] == 0)
5219     return;
5221   if (!emacs_event)
5222     return;
5224   processingCompose = YES;
5225   workingText = [str copy];
5226   ns_working_text = build_string ([workingText UTF8String]);
5228   emacs_event->kind = NS_TEXT_EVENT;
5229   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5230   EV_TRAILER ((id)nil);
5234 /* delete display of composing characters [not in <NSTextInput>] */
5235 - (void)deleteWorkingText
5237   if (workingText == nil)
5238     return;
5239   if (NS_KEYLOG)
5240     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5241   [workingText release];
5242   workingText = nil;
5243   processingCompose = NO;
5245   if (!emacs_event)
5246     return;
5248   emacs_event->kind = NS_TEXT_EVENT;
5249   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5250   EV_TRAILER ((id)nil);
5254 - (BOOL)hasMarkedText
5256   return workingText != nil;
5260 - (NSRange)markedRange
5262   NSRange rng = workingText != nil
5263     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5264   if (NS_KEYLOG)
5265     NSLog (@"markedRange request");
5266   return rng;
5270 - (void)unmarkText
5272   if (NS_KEYLOG)
5273     NSLog (@"unmark (accept) text");
5274   [self deleteWorkingText];
5275   processingCompose = NO;
5279 /* used to position char selection windows, etc. */
5280 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5282   NSRect rect;
5283   NSPoint pt;
5284   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5285   if (NS_KEYLOG)
5286     NSLog (@"firstRectForCharRange request");
5288   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5289   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5290   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5291   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5292                                        +FRAME_LINE_HEIGHT (emacsframe));
5294   pt = [self convertPoint: pt toView: nil];
5295   pt = [[self window] convertBaseToScreen: pt];
5296   rect.origin = pt;
5297   return rect;
5301 - (NSInteger)conversationIdentifier
5303   return (NSInteger)self;
5307 - (void)doCommandBySelector: (SEL)aSelector
5309   if (NS_KEYLOG)
5310     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5312   processingCompose = NO;
5313   if (aSelector == @selector (deleteBackward:))
5314     {
5315       /* happens when user backspaces over an ongoing composition:
5316          throw a 'delete' into the event queue */
5317       if (!emacs_event)
5318         return;
5319       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5320       emacs_event->code = 0xFF08;
5321       EV_TRAILER ((id)nil);
5322     }
5325 - (NSArray *)validAttributesForMarkedText
5327   static NSArray *arr = nil;
5328   if (arr == nil) arr = [NSArray new];
5329  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5330   return arr;
5333 - (NSRange)selectedRange
5335   if (NS_KEYLOG)
5336     NSLog (@"selectedRange request");
5337   return NSMakeRange (NSNotFound, 0);
5340 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5341     GNUSTEP_GUI_MINOR_VERSION > 22
5342 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5343 #else
5344 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5345 #endif
5347   if (NS_KEYLOG)
5348     NSLog (@"characterIndexForPoint request");
5349   return 0;
5352 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5354   static NSAttributedString *str = nil;
5355   if (str == nil) str = [NSAttributedString new];
5356   if (NS_KEYLOG)
5357     NSLog (@"attributedSubstringFromRange request");
5358   return str;
5361 /* End <NSTextInput> impl. */
5362 /*****************************************************************************/
5365 /* This is what happens when the user presses a mouse button.  */
5366 - (void)mouseDown: (NSEvent *)theEvent
5368   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5369   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5371   NSTRACE (mouseDown);
5373   [self deleteWorkingText];
5375   if (!emacs_event)
5376     return;
5378   dpyinfo->last_mouse_frame = emacsframe;
5379   /* appears to be needed to prevent spurious movement events generated on
5380      button clicks */
5381   emacsframe->mouse_moved = 0;
5383   if ([theEvent type] == NSScrollWheel)
5384     {
5385       CGFloat delta = [theEvent deltaY];
5386       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5387       if (delta == 0)
5388         return;
5389       emacs_event->kind = WHEEL_EVENT;
5390       emacs_event->code = 0;
5391       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5392         ((delta > 0) ? up_modifier : down_modifier);
5393     }
5394   else
5395     {
5396       emacs_event->kind = MOUSE_CLICK_EVENT;
5397       emacs_event->code = EV_BUTTON (theEvent);
5398       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5399                              | EV_UDMODIFIERS (theEvent);
5400     }
5401   XSETINT (emacs_event->x, lrint (p.x));
5402   XSETINT (emacs_event->y, lrint (p.y));
5403   EV_TRAILER (theEvent);
5407 - (void)rightMouseDown: (NSEvent *)theEvent
5409   NSTRACE (rightMouseDown);
5410   [self mouseDown: theEvent];
5414 - (void)otherMouseDown: (NSEvent *)theEvent
5416   NSTRACE (otherMouseDown);
5417   [self mouseDown: theEvent];
5421 - (void)mouseUp: (NSEvent *)theEvent
5423   NSTRACE (mouseUp);
5424   [self mouseDown: theEvent];
5428 - (void)rightMouseUp: (NSEvent *)theEvent
5430   NSTRACE (rightMouseUp);
5431   [self mouseDown: theEvent];
5435 - (void)otherMouseUp: (NSEvent *)theEvent
5437   NSTRACE (otherMouseUp);
5438   [self mouseDown: theEvent];
5442 - (void) scrollWheel: (NSEvent *)theEvent
5444   NSTRACE (scrollWheel);
5445   [self mouseDown: theEvent];
5449 /* Tell emacs the mouse has moved. */
5450 - (void)mouseMoved: (NSEvent *)e
5452   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5453   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5454   Lisp_Object frame;
5455   NSPoint pt;
5457 //  NSTRACE (mouseMoved);
5459   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
5460   pt = [self convertPoint: [e locationInWindow] fromView: nil];
5461   dpyinfo->last_mouse_motion_x = pt.x;
5462   dpyinfo->last_mouse_motion_y = pt.y;
5464   /* update any mouse face */
5465   if (hlinfo->mouse_face_hidden)
5466     {
5467       hlinfo->mouse_face_hidden = 0;
5468       clear_mouse_face (hlinfo);
5469     }
5471   /* tooltip handling */
5472   previous_help_echo_string = help_echo_string;
5473   help_echo_string = Qnil;
5475   if (!NILP (Vmouse_autoselect_window))
5476     {
5477       NSTRACE (mouse_autoselect_window);
5478       static Lisp_Object last_mouse_window;
5479       Lisp_Object window
5480         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
5482       if (WINDOWP (window)
5483           && !EQ (window, last_mouse_window)
5484           && !EQ (window, selected_window)
5485           && (focus_follows_mouse
5486               || (EQ (XWINDOW (window)->frame,
5487                       XWINDOW (selected_window)->frame))))
5488         {
5489           NSTRACE (in_window);
5490           emacs_event->kind = SELECT_WINDOW_EVENT;
5491           emacs_event->frame_or_window = window;
5492           EV_TRAILER2 (e);
5493         }
5494       /* Remember the last window where we saw the mouse.  */
5495       last_mouse_window = window;
5496     }
5498   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
5499     help_echo_string = previous_help_echo_string;
5501   XSETFRAME (frame, emacsframe);
5502   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5503     {
5504       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5505          (note_mouse_highlight), which is called through the
5506          note_mouse_movement () call above */
5507       gen_help_event (help_echo_string, frame, help_echo_window,
5508                       help_echo_object, help_echo_pos);
5509     }
5510   else
5511     {
5512       help_echo_string = Qnil;
5513       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5514     }
5516   if (emacsframe->mouse_moved && send_appdefined)
5517     ns_send_appdefined (-1);
5521 - (void)mouseDragged: (NSEvent *)e
5523   NSTRACE (mouseDragged);
5524   [self mouseMoved: e];
5528 - (void)rightMouseDragged: (NSEvent *)e
5530   NSTRACE (rightMouseDragged);
5531   [self mouseMoved: e];
5535 - (void)otherMouseDragged: (NSEvent *)e
5537   NSTRACE (otherMouseDragged);
5538   [self mouseMoved: e];
5542 - (BOOL)windowShouldClose: (id)sender
5544   NSEvent *e =[[self window] currentEvent];
5546   NSTRACE (windowShouldClose);
5547   windowClosing = YES;
5548   if (!emacs_event)
5549     return NO;
5550   emacs_event->kind = DELETE_WINDOW_EVENT;
5551   emacs_event->modifiers = 0;
5552   emacs_event->code = 0;
5553   EV_TRAILER (e);
5554   /* Don't close this window, let this be done from lisp code.  */
5555   return NO;
5558 - (void) updateFrameSize: (BOOL) delay;
5560   NSWindow *window = [self window];
5561   NSRect wr = [window frame];
5562   int extra = 0;
5563   int gsextra = 0;
5564 #ifdef NS_IMPL_GNUSTEP
5565   gsextra = 3;
5566 #endif
5568   int oldc = cols, oldr = rows;
5569   int oldw = FRAME_PIXEL_WIDTH (emacsframe),
5570     oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5571   int neww, newh;
5573   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, wr.size.width + gsextra);
5575   if (cols < MINWIDTH)
5576     cols = MINWIDTH;
5578   if (! [self isFullscreen])
5579     {
5580       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5581         + FRAME_TOOLBAR_HEIGHT (emacsframe) - gsextra;
5582     }
5584   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, wr.size.height - extra);
5586   if (rows < MINHEIGHT)
5587     rows = MINHEIGHT;
5589   neww = (int)wr.size.width - emacsframe->border_width;
5590   newh = (int)wr.size.height - extra;
5592   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5593     {
5594       NSView *view = FRAME_NS_VIEW (emacsframe);
5595       NSWindow *win = [view window];
5596       NSSize sz = [win resizeIncrements];
5598       FRAME_PIXEL_WIDTH (emacsframe) = neww;
5599       FRAME_PIXEL_HEIGHT (emacsframe) = newh;
5600       change_frame_size (emacsframe, rows, cols, 0, delay, 0);
5601       SET_FRAME_GARBAGED (emacsframe);
5602       cancel_mouse_face (emacsframe);
5604       // Did resize increments change because of a font change?
5605       if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5606           sz.height != FRAME_LINE_HEIGHT (emacsframe))
5607         {
5608           sz.width = FRAME_COLUMN_WIDTH (emacsframe);
5609           sz.height = FRAME_LINE_HEIGHT (emacsframe);
5610           [win setResizeIncrements: sz];
5611         }
5613       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5614       [self windowDidMove:nil];   // Update top/left.
5615     }
5618 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5619 /* normalize frame to gridded text size */
5621   int extra = 0;
5622   int gsextra = 0;
5623 #ifdef NS_IMPL_GNUSTEP
5624   gsextra = 3;
5625 #endif
5627   NSTRACE (windowWillResize);
5628 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5630   if (fs_state == FULLSCREEN_MAXIMIZED
5631       && (maximized_width != (int)frameSize.width
5632           || maximized_height != (int)frameSize.height))
5633     [self setFSValue: FULLSCREEN_NONE];
5634   else if (fs_state == FULLSCREEN_WIDTH
5635            && maximized_width != (int)frameSize.width)
5636     [self setFSValue: FULLSCREEN_NONE];
5637   else if (fs_state == FULLSCREEN_HEIGHT
5638            && maximized_height != (int)frameSize.height)
5639     [self setFSValue: FULLSCREEN_NONE];
5640   if (fs_state == FULLSCREEN_NONE)
5641     maximized_width = maximized_height = -1;
5643   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5644                                          frameSize.width + gsextra);
5645   if (cols < MINWIDTH)
5646     cols = MINWIDTH;
5648   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5649                                            frameSize.height - extra);
5650   if (rows < MINHEIGHT)
5651     rows = MINHEIGHT;
5652 #ifdef NS_IMPL_COCOA
5653   {
5654     /* this sets window title to have size in it; the wm does this under GS */
5655     NSRect r = [[self window] frame];
5656     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5657       {
5658         if (old_title != 0)
5659           {
5660             xfree (old_title);
5661             old_title = 0;
5662           }
5663       }
5664     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5665       {
5666         char *size_title;
5667         NSWindow *window = [self window];
5668         if (old_title == 0)
5669           {
5670             char *t = strdup ([[[self window] title] UTF8String]);
5671             char *pos = strstr (t, "  â€”  ");
5672             if (pos)
5673               *pos = '\0';
5674             old_title = t;
5675           }
5676         size_title = xmalloc (strlen (old_title) + 40);
5677         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5678         [window setTitle: [NSString stringWithUTF8String: size_title]];
5679         [window display];
5680         xfree (size_title);
5681       }
5682   }
5683 #endif /* NS_IMPL_COCOA */
5684 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5686   return frameSize;
5690 - (void)windowDidResize: (NSNotification *)notification
5692   if (! [self fsIsNative])
5693     {
5694       NSWindow *theWindow = [notification object];
5695       /* We can get notification on the non-FS window when in
5696          fullscreen mode.  */
5697       if ([self window] != theWindow) return;
5698     }
5700 #ifdef NS_IMPL_GNUSTEP
5701   NSWindow *theWindow = [notification object];
5703    /* In GNUstep, at least currently, it's possible to get a didResize
5704       without getting a willResize.. therefore we need to act as if we got
5705       the willResize now */
5706   NSSize sz = [theWindow frame].size;
5707   sz = [self windowWillResize: theWindow toSize: sz];
5708 #endif /* NS_IMPL_GNUSTEP */
5710   NSTRACE (windowDidResize);
5711 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5713 if (cols > 0 && rows > 0)
5714     {
5715       [self updateFrameSize: YES];
5716     }
5718   ns_send_appdefined (-1);
5721 #ifdef NS_IMPL_COCOA
5722 - (void)viewDidEndLiveResize
5724   [super viewDidEndLiveResize];
5725   if (old_title != 0)
5726     {
5727       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
5728       xfree (old_title);
5729       old_title = 0;
5730     }
5731   maximizing_resize = NO;
5733 #endif /* NS_IMPL_COCOA */
5736 - (void)windowDidBecomeKey: (NSNotification *)notification
5737 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5739   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5740   struct frame *old_focus = dpyinfo->x_focus_frame;
5742   NSTRACE (windowDidBecomeKey);
5744   if (emacsframe != old_focus)
5745     dpyinfo->x_focus_frame = emacsframe;
5747   ns_frame_rehighlight (emacsframe);
5749   if (emacs_event)
5750     {
5751       emacs_event->kind = FOCUS_IN_EVENT;
5752       EV_TRAILER ((id)nil);
5753     }
5757 - (void)windowDidResignKey: (NSNotification *)notification
5758 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5760   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5761   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
5762   NSTRACE (windowDidResignKey);
5764   if (is_focus_frame)
5765     dpyinfo->x_focus_frame = 0;
5767   ns_frame_rehighlight (emacsframe);
5769   /* FIXME: for some reason needed on second and subsequent clicks away
5770             from sole-frame Emacs to get hollow box to show */
5771   if (!windowClosing && [[self window] isVisible] == YES)
5772     {
5773       x_update_cursor (emacsframe, 1);
5774       x_set_frame_alpha (emacsframe);
5775     }
5777   if (emacs_event && is_focus_frame)
5778     {
5779       [self deleteWorkingText];
5780       emacs_event->kind = FOCUS_OUT_EVENT;
5781       EV_TRAILER ((id)nil);
5782     }
5786 - (void)windowWillMiniaturize: sender
5788   NSTRACE (windowWillMiniaturize);
5792 - (BOOL)isFlipped
5794   return YES;
5798 - (BOOL)isOpaque
5800   return NO;
5804 - initFrameFromEmacs: (struct frame *)f
5806   NSRect r, wr;
5807   Lisp_Object tem;
5808   NSWindow *win;
5809   NSSize sz;
5810   NSColor *col;
5811   NSString *name;
5813   NSTRACE (initFrameFromEmacs);
5815   windowClosing = NO;
5816   processingCompose = NO;
5817   scrollbarsNeedingUpdate = 0;
5818   fs_state = FULLSCREEN_NONE;
5819   fs_before_fs = next_maximized = -1;
5820 #ifdef HAVE_NATIVE_FS
5821   fs_is_native = ns_use_native_fullscreen;
5822 #else
5823   fs_is_native = NO;
5824 #endif
5825   maximized_width = maximized_height = -1;
5826   nonfs_window = nil;
5828 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5830   ns_userRect = NSMakeRect (0, 0, 0, 0);
5831   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5832                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5833   [self initWithFrame: r];
5834   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5836   FRAME_NS_VIEW (f) = self;
5837   emacsframe = f;
5838 #ifdef NS_IMPL_COCOA
5839   old_title = 0;
5840   maximizing_resize = NO;
5841 #endif
5843   win = [[EmacsWindow alloc]
5844             initWithContentRect: r
5845                       styleMask: (NSResizableWindowMask |
5846 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5847                                   NSTitledWindowMask |
5848 #endif
5849                                   NSMiniaturizableWindowMask |
5850                                   NSClosableWindowMask)
5851                         backing: NSBackingStoreBuffered
5852                           defer: YES];
5854 #ifdef HAVE_NATIVE_FS
5855     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
5856 #endif
5858   wr = [win frame];
5859   bwidth = f->border_width = wr.size.width - r.size.width;
5860   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5862   [win setAcceptsMouseMovedEvents: YES];
5863   [win setDelegate: self];
5864   [win useOptimizedDrawing: YES];
5866   sz.width = FRAME_COLUMN_WIDTH (f);
5867   sz.height = FRAME_LINE_HEIGHT (f);
5868   [win setResizeIncrements: sz];
5870   [[win contentView] addSubview: self];
5872   if (ns_drag_types)
5873     [self registerForDraggedTypes: ns_drag_types];
5875   tem = f->name;
5876   name = [NSString stringWithUTF8String:
5877                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5878   [win setTitle: name];
5880   /* toolbar support */
5881   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5882                          [NSString stringWithFormat: @"Emacs Frame %d",
5883                                    ns_window_num]];
5884   [win setToolbar: toolbar];
5885   [toolbar setVisible: NO];
5886 #ifdef NS_IMPL_COCOA
5887   {
5888     NSButton *toggleButton;
5889   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5890   [toggleButton setTarget: self];
5891   [toggleButton setAction: @selector (toggleToolbar: )];
5892   }
5893 #endif
5894   FRAME_TOOLBAR_HEIGHT (f) = 0;
5896   tem = f->icon_name;
5897   if (!NILP (tem))
5898     [win setMiniwindowTitle:
5899            [NSString stringWithUTF8String: SSDATA (tem)]];
5901   {
5902     NSScreen *screen = [win screen];
5904     if (screen != 0)
5905       [win setFrameTopLeftPoint: NSMakePoint
5906            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5907             IN_BOUND (-SCREENMAX,
5908                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5909   }
5911   [win makeFirstResponder: self];
5913   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5914                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5915   [win setBackgroundColor: col];
5916   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
5917     [win setOpaque: NO];
5919   [self allocateGState];
5921   [NSApp registerServicesMenuSendTypes: ns_send_types
5922                            returnTypes: nil];
5924   ns_window_num++;
5925   return self;
5929 - (void)windowDidMove: sender
5931   NSWindow *win = [self window];
5932   NSRect r = [win frame];
5933   NSArray *screens = [NSScreen screens];
5934   NSScreen *screen = [screens objectAtIndex: 0];
5936   NSTRACE (windowDidMove);
5938   if (!emacsframe->output_data.ns)
5939     return;
5940   if (screen != nil)
5941     {
5942       emacsframe->left_pos = r.origin.x;
5943       emacsframe->top_pos =
5944         [screen frame].size.height - (r.origin.y + r.size.height);
5945     }
5949 /* Called AFTER method below, but before our windowWillResize call there leads
5950    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5951    location so set_window_size moves the frame. */
5952 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5954   emacsframe->output_data.ns->zooming = 1;
5955   return YES;
5959 /* Override to do something slightly nonstandard, but nice.  First click on
5960    zoom button will zoom vertically.  Second will zoom completely.  Third
5961    returns to original. */
5962 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5963                         defaultFrame:(NSRect)defaultFrame
5965   NSRect result = [sender frame];
5967   NSTRACE (windowWillUseStandardFrame);
5969   if (fs_before_fs != -1) /* Entering fullscreen */
5970       {
5971         result = defaultFrame;
5972       }
5973   else if (next_maximized == FULLSCREEN_HEIGHT
5974       || (next_maximized == -1
5975           && abs (defaultFrame.size.height - result.size.height)
5976           > FRAME_LINE_HEIGHT (emacsframe)))
5977     {
5978       /* first click */
5979       ns_userRect = result;
5980       maximized_height = result.size.height = defaultFrame.size.height;
5981       maximized_width = -1;
5982       result.origin.y = defaultFrame.origin.y;
5983       [self setFSValue: FULLSCREEN_HEIGHT];
5984 #ifdef NS_IMPL_COCOA
5985       maximizing_resize = YES;
5986 #endif
5987     }
5988   else if (next_maximized == FULLSCREEN_WIDTH)
5989     {
5990       ns_userRect = result;
5991       maximized_width = result.size.width = defaultFrame.size.width;
5992       maximized_height = -1;
5993       result.origin.x = defaultFrame.origin.x;
5994       [self setFSValue: FULLSCREEN_WIDTH];
5995     }
5996   else if (next_maximized == FULLSCREEN_MAXIMIZED
5997            || (next_maximized == -1
5998                && abs (defaultFrame.size.width - result.size.width)
5999                > FRAME_COLUMN_WIDTH (emacsframe)))
6000     {
6001       result = defaultFrame;  /* second click */
6002       maximized_width = result.size.width;
6003       maximized_height = result.size.height;
6004       [self setFSValue: FULLSCREEN_MAXIMIZED];
6005 #ifdef NS_IMPL_COCOA
6006       maximizing_resize = YES;
6007 #endif
6008     }
6009   else
6010     {
6011       /* restore */
6012       result = ns_userRect.size.height ? ns_userRect : result;
6013       ns_userRect = NSMakeRect (0, 0, 0, 0);
6014 #ifdef NS_IMPL_COCOA
6015       maximizing_resize = fs_state != FULLSCREEN_NONE;
6016 #endif
6017       [self setFSValue: FULLSCREEN_NONE];
6018       maximized_width = maximized_height = -1;
6019     }
6021   if (fs_before_fs == -1) next_maximized = -1;
6022   [self windowWillResize: sender toSize: result.size];
6023   return result;
6027 - (void)windowDidDeminiaturize: sender
6029   NSTRACE (windowDidDeminiaturize);
6030   if (!emacsframe->output_data.ns)
6031     return;
6033   SET_FRAME_ICONIFIED (emacsframe, 0);
6034   SET_FRAME_VISIBLE (emacsframe, 1);
6035   windows_or_buffers_changed++;
6037   if (emacs_event)
6038     {
6039       emacs_event->kind = DEICONIFY_EVENT;
6040       EV_TRAILER ((id)nil);
6041     }
6045 - (void)windowDidExpose: sender
6047   NSTRACE (windowDidExpose);
6048   if (!emacsframe->output_data.ns)
6049     return;
6051   SET_FRAME_VISIBLE (emacsframe, 1);
6052   SET_FRAME_GARBAGED (emacsframe);
6054   if (send_appdefined)
6055     ns_send_appdefined (-1);
6059 - (void)windowDidMiniaturize: sender
6061   NSTRACE (windowDidMiniaturize);
6062   if (!emacsframe->output_data.ns)
6063     return;
6065   SET_FRAME_ICONIFIED (emacsframe, 1);
6066   SET_FRAME_VISIBLE (emacsframe, 0);
6068   if (emacs_event)
6069     {
6070       emacs_event->kind = ICONIFY_EVENT;
6071       EV_TRAILER ((id)nil);
6072     }
6075 #ifdef HAVE_NATIVE_FS
6076 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6077       willUseFullScreenPresentationOptions:
6078   (NSApplicationPresentationOptions)proposedOptions
6080   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6082 #endif
6084 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6086   fs_before_fs = fs_state;
6089 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6091   [self setFSValue: FULLSCREEN_BOTH];
6092   if (! [self fsIsNative])
6093     {
6094       [self windowDidBecomeKey:notification];
6095       [nonfs_window orderOut:self];
6096     }
6097   else if (! FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6098     [toolbar setVisible:NO];
6101 - (void)windowWillExitFullScreen:(NSNotification *)notification
6103   if (next_maximized != -1)
6104     fs_before_fs = next_maximized;
6107 - (void)windowDidExitFullScreen:(NSNotification *)notification
6109   [self setFSValue: fs_before_fs];
6110   fs_before_fs = -1;
6111 #ifdef NS_IMPL_COCOA
6112   [self updateCollectionBehaviour];
6113 #endif
6114   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6115     {
6116       [toolbar setVisible:YES];
6117       update_frame_tool_bar (emacsframe);
6118       [self updateFrameSize:YES];
6119       [[self window] display];
6120     }
6121   else
6122     [toolbar setVisible:NO];
6124   if (next_maximized != -1)
6125     [[self window] performZoom:self];
6128 - (BOOL)fsIsNative
6130   return fs_is_native;
6133 - (BOOL)isFullscreen
6135   if (! fs_is_native) return nonfs_window != nil;
6136 #ifdef HAVE_NATIVE_FS
6137   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6138 #else
6139   return NO;
6140 #endif
6143 #ifdef HAVE_NATIVE_FS
6144 - (void)updateCollectionBehaviour
6146   if (! [self isFullscreen])
6147     {
6148       NSWindow *win = [self window];
6149       NSWindowCollectionBehavior b = [win collectionBehavior];
6150       if (ns_use_native_fullscreen)
6151         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6152       else
6153         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6155       [win setCollectionBehavior: b];
6156       fs_is_native = ns_use_native_fullscreen;
6157     }
6159 #endif
6161 - (void)toggleFullScreen: (id)sender
6163   NSWindow *w, *fw;
6164   BOOL onFirstScreen;
6165   struct frame *f;
6166   NSSize sz;
6167   NSRect r, wr;
6168   NSColor *col;
6170   if (fs_is_native)
6171     {
6172 #ifdef NS_IMPL_COCOA
6173       [[self window] toggleFullScreen:sender];
6174 #endif
6175       return;
6176     }
6178   w = [self window];
6179   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6180   f = emacsframe;
6181   wr = [w frame];
6182   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6183                                  (FRAME_DEFAULT_FACE (f)),
6184                                  f);
6186   sz.width = FRAME_COLUMN_WIDTH (f);
6187   sz.height = FRAME_LINE_HEIGHT (f);
6189   if (fs_state != FULLSCREEN_BOTH)
6190     {
6191       /* Hide dock and menubar if we are on the primary screen.  */
6192       if (onFirstScreen)
6193         {
6194 #if defined (NS_IMPL_COCOA) && \
6195   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6196           NSApplicationPresentationOptions options
6197             = NSApplicationPresentationAutoHideDock
6198             | NSApplicationPresentationAutoHideMenuBar;
6200           [NSApp setPresentationOptions: options];
6201 #else
6202           [NSMenu setMenuBarVisible:NO];
6203 #endif
6204         }
6206       fw = [[EmacsFSWindow alloc]
6207                        initWithContentRect:[w contentRectForFrameRect:wr]
6208                                  styleMask:NSBorderlessWindowMask
6209                                    backing:NSBackingStoreBuffered
6210                                      defer:YES
6211                                     screen:[w screen]];
6213       [fw setContentView:[w contentView]];
6214       [fw setTitle:[w title]];
6215       [fw setDelegate:self];
6216       [fw setAcceptsMouseMovedEvents: YES];
6217       [fw useOptimizedDrawing: YES];
6218       [fw setResizeIncrements: sz];
6219       [fw setBackgroundColor: col];
6220       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6221         [fw setOpaque: NO];
6223       f->border_width = 0;
6224       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6225       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6226       FRAME_TOOLBAR_HEIGHT (f) = 0;
6228       nonfs_window = w;
6230       [self windowWillEnterFullScreen:nil];
6231       [fw makeKeyAndOrderFront:NSApp];
6232       [fw makeFirstResponder:self];
6233       [w orderOut:self];
6234       r = [fw frameRectForContentRect:[[fw screen] frame]];
6235       [fw setFrame: r display:YES animate:YES];
6236       [self windowDidEnterFullScreen:nil];
6237       [fw display];
6238     }
6239   else
6240     {
6241       fw = w;
6242       w = nonfs_window;
6243       nonfs_window = nil;
6245       if (onFirstScreen)
6246         {
6247 #if defined (NS_IMPL_COCOA) && \
6248   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6249           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6250 #else
6251           [NSMenu setMenuBarVisible:YES];
6252 #endif
6253         }
6255       [w setContentView:[fw contentView]];
6256       [w setResizeIncrements: sz];
6257       [w setBackgroundColor: col];
6258       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6259         [w setOpaque: NO];
6261       f->border_width = bwidth;
6262       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6263       if (FRAME_EXTERNAL_TOOL_BAR (f))
6264         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6266       [self windowWillExitFullScreen:nil];
6267       [fw setFrame: [w frame] display:YES animate:YES];
6268       [fw close];
6269       [w makeKeyAndOrderFront:NSApp];
6270       [self windowDidExitFullScreen:nil];
6271       [self updateFrameSize:YES];
6272     }
6275 - (void)handleFS
6277   if (fs_state != emacsframe->want_fullscreen)
6278     {
6279       if (fs_state == FULLSCREEN_BOTH)
6280         {
6281           [self toggleFullScreen:self];
6282         }
6284       switch (emacsframe->want_fullscreen)
6285         {
6286         case FULLSCREEN_BOTH:
6287           [self toggleFullScreen:self];
6288           break;
6289         case FULLSCREEN_WIDTH:
6290           next_maximized = FULLSCREEN_WIDTH;
6291           if (fs_state != FULLSCREEN_BOTH)
6292             [[self window] performZoom:self];
6293           break;
6294         case FULLSCREEN_HEIGHT:
6295           next_maximized = FULLSCREEN_HEIGHT;
6296           if (fs_state != FULLSCREEN_BOTH)
6297             [[self window] performZoom:self];
6298           break;
6299         case FULLSCREEN_MAXIMIZED:
6300           next_maximized = FULLSCREEN_MAXIMIZED;
6301           if (fs_state != FULLSCREEN_BOTH)
6302             [[self window] performZoom:self];
6303           break;
6304         case FULLSCREEN_NONE:
6305           if (fs_state != FULLSCREEN_BOTH)
6306             {
6307               next_maximized = FULLSCREEN_NONE;
6308               [[self window] performZoom:self];
6309             }
6310           break;
6311         }
6313       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6314     }
6318 - (void) setFSValue: (int)value
6320   Lisp_Object lval = Qnil;
6321   switch (value)
6322     {
6323     case FULLSCREEN_BOTH:
6324       lval = Qfullboth;
6325       break;
6326     case FULLSCREEN_WIDTH:
6327       lval = Qfullwidth;
6328       break;
6329     case FULLSCREEN_HEIGHT:
6330       lval = Qfullheight;
6331       break;
6332     case FULLSCREEN_MAXIMIZED:
6333       lval = Qmaximized;
6334       break;
6335     }
6336   store_frame_param (emacsframe, Qfullscreen, lval);
6337   fs_state = value;
6340 - (void)mouseEntered: (NSEvent *)theEvent
6342   NSTRACE (mouseEntered);
6343   if (emacsframe)
6344     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6345       = EV_TIMESTAMP (theEvent);
6349 - (void)mouseExited: (NSEvent *)theEvent
6351   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6353   NSTRACE (mouseExited);
6355   if (!hlinfo)
6356     return;
6358   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6359     = EV_TIMESTAMP (theEvent);
6361   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6362     {
6363       clear_mouse_face (hlinfo);
6364       hlinfo->mouse_face_mouse_frame = 0;
6365     }
6369 - menuDown: sender
6371   NSTRACE (menuDown);
6372   if (context_menu_value == -1)
6373     context_menu_value = [sender tag];
6374   else
6375     {
6376       NSInteger tag = [sender tag];
6377       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6378                                     emacsframe->menu_bar_vector,
6379                                     (void *)tag);
6380     }
6382   ns_send_appdefined (-1);
6383   return self;
6387 - (EmacsToolbar *)toolbar
6389   return toolbar;
6393 /* this gets called on toolbar button click */
6394 - toolbarClicked: (id)item
6396   NSEvent *theEvent;
6397   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6399   NSTRACE (toolbarClicked);
6401   if (!emacs_event)
6402     return self;
6404   /* send first event (for some reason two needed) */
6405   theEvent = [[self window] currentEvent];
6406   emacs_event->kind = TOOL_BAR_EVENT;
6407   XSETFRAME (emacs_event->arg, emacsframe);
6408   EV_TRAILER (theEvent);
6410   emacs_event->kind = TOOL_BAR_EVENT;
6411 /*   XSETINT (emacs_event->code, 0); */
6412   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6413                            idx + TOOL_BAR_ITEM_KEY);
6414   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6415   EV_TRAILER (theEvent);
6416   return self;
6420 - toggleToolbar: (id)sender
6422   if (!emacs_event)
6423     return self;
6425   emacs_event->kind = NS_NONKEY_EVENT;
6426   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6427   EV_TRAILER ((id)nil);
6428   return self;
6432 - (void)drawRect: (NSRect)rect
6434   int x = NSMinX (rect), y = NSMinY (rect);
6435   int width = NSWidth (rect), height = NSHeight (rect);
6437   NSTRACE (drawRect);
6439   if (!emacsframe || !emacsframe->output_data.ns)
6440     return;
6442   ns_clear_frame_area (emacsframe, x, y, width, height);
6443   expose_frame (emacsframe, x, y, width, height);
6445   /*
6446     drawRect: may be called (at least in OS X 10.5) for invisible
6447     views as well for some reason.  Thus, do not infer visibility
6448     here.
6450     emacsframe->async_visible = 1;
6451     emacsframe->async_iconified = 0;
6452   */
6456 /* NSDraggingDestination protocol methods.  Actually this is not really a
6457    protocol, but a category of Object.  O well...  */
6459 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6461   NSTRACE (draggingEntered);
6462   return NSDragOperationGeneric;
6466 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6468   return YES;
6472 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6474   id pb;
6475   int x, y;
6476   NSString *type;
6477   NSEvent *theEvent = [[self window] currentEvent];
6478   NSPoint position;
6480   NSTRACE (performDragOperation);
6482   if (!emacs_event)
6483     return NO;
6485   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6486   x = lrint (position.x);  y = lrint (position.y);
6488   pb = [sender draggingPasteboard];
6489   type = [pb availableTypeFromArray: ns_drag_types];
6490   if (type == 0)
6491     {
6492       return NO;
6493     }
6494   else if ([type isEqualToString: NSFilenamesPboardType])
6495     {
6496       NSArray *files;
6497       NSEnumerator *fenum;
6498       NSString *file;
6500       if (!(files = [pb propertyListForType: type]))
6501         return NO;
6503       fenum = [files objectEnumerator];
6504       while ( (file = [fenum nextObject]) )
6505         {
6506           emacs_event->kind = NS_NONKEY_EVENT;
6507           emacs_event->code = KEY_NS_DRAG_FILE;
6508           XSETINT (emacs_event->x, x);
6509           XSETINT (emacs_event->y, y);
6510           ns_input_file = append2 (ns_input_file,
6511                                    build_string ([file UTF8String]));
6512           emacs_event->modifiers = EV_MODIFIERS (theEvent);
6513           EV_TRAILER (theEvent);
6514         }
6515       return YES;
6516     }
6517   else if ([type isEqualToString: NSURLPboardType])
6518     {
6519       NSString *file;
6520       NSURL *fileURL;
6522       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6523           [fileURL isFileURL] == NO)
6524         return NO;
6526       file = [fileURL path];
6527       emacs_event->kind = NS_NONKEY_EVENT;
6528       emacs_event->code = KEY_NS_DRAG_FILE;
6529       XSETINT (emacs_event->x, x);
6530       XSETINT (emacs_event->y, y);
6531       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6532       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6533       EV_TRAILER (theEvent);
6534       return YES;
6535     }
6536   else if ([type isEqualToString: NSStringPboardType]
6537            || [type isEqualToString: NSTabularTextPboardType])
6538     {
6539       NSString *data;
6541       if (! (data = [pb stringForType: type]))
6542         return NO;
6544       emacs_event->kind = NS_NONKEY_EVENT;
6545       emacs_event->code = KEY_NS_DRAG_TEXT;
6546       XSETINT (emacs_event->x, x);
6547       XSETINT (emacs_event->y, y);
6548       ns_input_text = build_string ([data UTF8String]);
6549       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6550       EV_TRAILER (theEvent);
6551       return YES;
6552     }
6553   else if ([type isEqualToString: NSColorPboardType])
6554     {
6555       NSColor *c = [NSColor colorFromPasteboard: pb];
6556       emacs_event->kind = NS_NONKEY_EVENT;
6557       emacs_event->code = KEY_NS_DRAG_COLOR;
6558       XSETINT (emacs_event->x, x);
6559       XSETINT (emacs_event->y, y);
6560       ns_input_color = ns_color_to_lisp (c);
6561       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6562       EV_TRAILER (theEvent);
6563       return YES;
6564     }
6565   else if ([type isEqualToString: NSFontPboardType])
6566     {
6567       /* impl based on GNUstep NSTextView.m */
6568       NSData *data = [pb dataForType: NSFontPboardType];
6569       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6570       NSFont *font = [dict objectForKey: NSFontAttributeName];
6571       char fontSize[10];
6573       if (font == nil)
6574         return NO;
6576       emacs_event->kind = NS_NONKEY_EVENT;
6577       emacs_event->code = KEY_NS_CHANGE_FONT;
6578       XSETINT (emacs_event->x, x);
6579       XSETINT (emacs_event->y, y);
6580       ns_input_font = build_string ([[font fontName] UTF8String]);
6581       snprintf (fontSize, 10, "%f", [font pointSize]);
6582       ns_input_fontsize = build_string (fontSize);
6583       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6584       EV_TRAILER (theEvent);
6585       return YES;
6586     }
6587   else
6588     {
6589       error ("Invalid data type in dragging pasteboard.");
6590       return NO;
6591     }
6595 - (id) validRequestorForSendType: (NSString *)typeSent
6596                       returnType: (NSString *)typeReturned
6598   NSTRACE (validRequestorForSendType);
6599   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6600       && typeReturned == nil)
6601     {
6602       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6603         return self;
6604     }
6606   return [super validRequestorForSendType: typeSent
6607                                returnType: typeReturned];
6611 /* The next two methods are part of NSServicesRequests informal protocol,
6612    supposedly called when a services menu item is chosen from this app.
6613    But this should not happen because we override the services menu with our
6614    own entries which call ns-perform-service.
6615    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6616    So let's at least stub them out until further investigation can be done. */
6618 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6620   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6621      be written into the buffer in place of the existing selection..
6622      ordinary service calls go through functions defined in ns-win.el */
6623   return NO;
6626 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6628   NSArray *typesDeclared;
6629   Lisp_Object val;
6631   /* We only support NSStringPboardType */
6632   if ([types containsObject:NSStringPboardType] == NO) {
6633     return NO;
6634   }
6636   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6637   if (CONSP (val) && SYMBOLP (XCAR (val)))
6638     {
6639       val = XCDR (val);
6640       if (CONSP (val) && NILP (XCDR (val)))
6641         val = XCAR (val);
6642     }
6643   if (! STRINGP (val))
6644     return NO;
6646   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6647   [pb declareTypes:typesDeclared owner:nil];
6648   ns_string_to_pasteboard (pb, val);
6649   return YES;
6653 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6654    (gives a miniaturized version of the window); currently we use the latter for
6655    frames whose active buffer doesn't correspond to any file
6656    (e.g., '*scratch*') */
6657 - setMiniwindowImage: (BOOL) setMini
6659   id image = [[self window] miniwindowImage];
6660   NSTRACE (setMiniwindowImage);
6662   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6663      about "AppleDockIconEnabled" notwithstanding, however the set message
6664      below has its effect nonetheless. */
6665   if (image != emacsframe->output_data.ns->miniimage)
6666     {
6667       if (image && [image isKindOfClass: [EmacsImage class]])
6668         [image release];
6669       [[self window] setMiniwindowImage:
6670                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6671     }
6673   return self;
6677 - (void) setRows: (int) r andColumns: (int) c
6679   rows = r;
6680   cols = c;
6683 @end  /* EmacsView */
6687 /* ==========================================================================
6689     EmacsWindow implementation
6691    ========================================================================== */
6693 @implementation EmacsWindow
6695 #ifdef NS_IMPL_COCOA
6696 - (id)accessibilityAttributeValue:(NSString *)attribute
6698   Lisp_Object str = Qnil;
6699   struct frame *f = SELECTED_FRAME ();
6700   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
6702   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6703     return NSAccessibilityTextFieldRole;
6705   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6706       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6707     {
6708       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6709     }
6710   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6711     {
6712       if (! NILP (BVAR (curbuf, mark_active)))
6713           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6715       if (NILP (str))
6716         {
6717           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6718           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6719           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6721           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6722             str = make_uninit_multibyte_string (range, byte_range);
6723           else
6724             str = make_uninit_string (range);
6725           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6726              Is this a problem?  */
6727           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6728         }
6729     }
6732   if (! NILP (str))
6733     {
6734       if (CONSP (str) && SYMBOLP (XCAR (str)))
6735         {
6736           str = XCDR (str);
6737           if (CONSP (str) && NILP (XCDR (str)))
6738             str = XCAR (str);
6739         }
6740       if (STRINGP (str))
6741         {
6742           const char *utfStr = SSDATA (str);
6743           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6744           return nsStr;
6745         }
6746     }
6748   return [super accessibilityAttributeValue:attribute];
6750 #endif /* NS_IMPL_COCOA */
6752 /* If we have multiple monitors, one above the other, we don't want to
6753    restrict the height to just one monitor.  So we override this.  */
6754 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6756   /* When making the frame visible for the first time or if there is just
6757      one screen, we want to constrain.  Other times not.  */
6758   NSUInteger nr_screens = [[NSScreen screens] count];
6759   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6760   NSTRACE (constrainFrameRect);
6762   if (nr_screens == 1)
6763     {
6764       NSRect r = [super constrainFrameRect:frameRect toScreen:screen];
6765       return r;
6766     }
6768   if (f->output_data.ns->dont_constrain
6769       || ns_menu_bar_should_be_hidden ())
6770     return frameRect;
6772   f->output_data.ns->dont_constrain = 1;
6773   return [super constrainFrameRect:frameRect toScreen:screen];
6776 @end /* EmacsWindow */
6779 @implementation EmacsFSWindow
6781 - (BOOL)canBecomeKeyWindow
6783   return YES;
6786 - (BOOL)canBecomeMainWindow
6788   return YES;
6791 @end
6793 /* ==========================================================================
6795     EmacsScroller implementation
6797    ========================================================================== */
6800 @implementation EmacsScroller
6802 /* for repeat button push */
6803 #define SCROLL_BAR_FIRST_DELAY 0.5
6804 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6806 + (CGFloat) scrollerWidth
6808   /* TODO: if we want to allow variable widths, this is the place to do it,
6809            however neither GNUstep nor Cocoa support it very well */
6810   return [NSScroller scrollerWidth];
6814 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6816   NSTRACE (EmacsScroller_initFrame);
6818   r.size.width = [EmacsScroller scrollerWidth];
6819   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6820   [self setContinuous: YES];
6821   [self setEnabled: YES];
6823   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6824      locked against the top and bottom edges, and right edge on OS X, where
6825      scrollers are on right. */
6826 #ifdef NS_IMPL_GNUSTEP
6827   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6828 #else
6829   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6830 #endif
6832   win = nwin;
6833   condemned = NO;
6834   pixel_height = NSHeight (r);
6835   if (pixel_height == 0) pixel_height = 1;
6836   min_portion = 20 / pixel_height;
6838   frame = XFRAME (XWINDOW (win)->frame);
6839   if (FRAME_LIVE_P (frame))
6840     {
6841       int i;
6842       EmacsView *view = FRAME_NS_VIEW (frame);
6843       NSView *sview = [[view window] contentView];
6844       NSArray *subs = [sview subviews];
6846       /* disable optimization stopping redraw of other scrollbars */
6847       view->scrollbarsNeedingUpdate = 0;
6848       for (i =[subs count]-1; i >= 0; i--)
6849         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6850           view->scrollbarsNeedingUpdate++;
6851       [sview addSubview: self];
6852     }
6854 /*  [self setFrame: r]; */
6856   return self;
6860 - (void)setFrame: (NSRect)newRect
6862   NSTRACE (EmacsScroller_setFrame);
6863 /*  block_input (); */
6864   pixel_height = NSHeight (newRect);
6865   if (pixel_height == 0) pixel_height = 1;
6866   min_portion = 20 / pixel_height;
6867   [super setFrame: newRect];
6868   [self display];
6869 /*  unblock_input (); */
6873 - (void)dealloc
6875   NSTRACE (EmacsScroller_dealloc);
6876   if (!NILP (win))
6877     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
6878   [super dealloc];
6882 - condemn
6884   NSTRACE (condemn);
6885   condemned =YES;
6886   return self;
6890 - reprieve
6892   NSTRACE (reprieve);
6893   condemned =NO;
6894   return self;
6898 - judge
6900   NSTRACE (judge);
6901   if (condemned)
6902     {
6903       EmacsView *view;
6904       block_input ();
6905       /* ensure other scrollbar updates after deletion */
6906       view = (EmacsView *)FRAME_NS_VIEW (frame);
6907       if (view != nil)
6908         view->scrollbarsNeedingUpdate++;
6909       [self removeFromSuperview];
6910       [self release];
6911       unblock_input ();
6912     }
6913   return self;
6917 - (void)resetCursorRects
6919   NSRect visible = [self visibleRect];
6920   NSTRACE (resetCursorRects);
6922   if (!NSIsEmptyRect (visible))
6923     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6924   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6928 - (int) checkSamePosition: (int) position portion: (int) portion
6929                     whole: (int) whole
6931   return em_position ==position && em_portion ==portion && em_whole ==whole
6932     && portion != whole; /* needed for resize empty buf */
6936 - setPosition: (int)position portion: (int)portion whole: (int)whole
6938   NSTRACE (setPosition);
6940   em_position = position;
6941   em_portion = portion;
6942   em_whole = whole;
6944   if (portion >= whole)
6945     {
6946 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6947       [self setKnobProportion: 1.0];
6948       [self setDoubleValue: 1.0];
6949 #else
6950       [self setFloatValue: 0.0 knobProportion: 1.0];
6951 #endif
6952     }
6953   else
6954     {
6955       float pos;
6956       CGFloat por;
6957       portion = max ((float)whole*min_portion/pixel_height, portion);
6958       pos = (float)position / (whole - portion);
6959       por = (CGFloat)portion/whole;
6960 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6961       [self setKnobProportion: por];
6962       [self setDoubleValue: pos];
6963 #else
6964       [self setFloatValue: pos knobProportion: por];
6965 #endif
6966     }
6968   /* Events may come here even if the event loop is not running.
6969      If we don't enter the event loop, the scroll bar will not update.
6970      So send SIGIO to ourselves.  */
6971   if (apploopnr == 0) raise (SIGIO);
6973   return self;
6976 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6977      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6978 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6979                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6981   *part = last_hit_part;
6982   *window = win;
6983   XSETINT (*y, pixel_height);
6984   if ([self floatValue] > 0.999F)
6985     XSETINT (*x, pixel_height);
6986   else
6987     XSETINT (*x, pixel_height * [self floatValue]);
6991 /* set up emacs_event */
6992 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6994   if (!emacs_event)
6995     return;
6997   emacs_event->part = last_hit_part;
6998   emacs_event->code = 0;
6999   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
7000   emacs_event->frame_or_window = win;
7001   emacs_event->timestamp = EV_TIMESTAMP (e);
7002   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
7003   emacs_event->arg = Qnil;
7004   XSETINT (emacs_event->x, loc * pixel_height);
7005   XSETINT (emacs_event->y, pixel_height-20);
7007   if (q_event_ptr)
7008     {
7009       n_emacs_events_pending++;
7010       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7011     }
7012   else
7013     hold_event (emacs_event);
7014   EVENT_INIT (*emacs_event);
7015   ns_send_appdefined (-1);
7019 /* called manually thru timer to implement repeated button action w/hold-down */
7020 - repeatScroll: (NSTimer *)scrollEntry
7022   NSEvent *e = [[self window] currentEvent];
7023   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
7024   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7026   /* clear timer if need be */
7027   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7028     {
7029         [scroll_repeat_entry invalidate];
7030         [scroll_repeat_entry release];
7031         scroll_repeat_entry = nil;
7033         if (inKnob)
7034           return self;
7036         scroll_repeat_entry
7037           = [[NSTimer scheduledTimerWithTimeInterval:
7038                         SCROLL_BAR_CONTINUOUS_DELAY
7039                                             target: self
7040                                           selector: @selector (repeatScroll:)
7041                                           userInfo: 0
7042                                            repeats: YES]
7043               retain];
7044     }
7046   [self sendScrollEventAtLoc: 0 fromEvent: e];
7047   return self;
7051 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
7052    mouseDragged events without going into a modal loop. */
7053 - (void)mouseDown: (NSEvent *)e
7055   NSRect sr, kr;
7056   /* hitPart is only updated AFTER event is passed on */
7057   NSScrollerPart part = [self testPart: [e locationInWindow]];
7058   CGFloat inc = 0.0, loc, kloc, pos;
7059   int edge = 0;
7061   NSTRACE (EmacsScroller_mouseDown);
7063   switch (part)
7064     {
7065     case NSScrollerDecrementPage:
7066         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7067     case NSScrollerIncrementPage:
7068         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7069     case NSScrollerDecrementLine:
7070       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7071     case NSScrollerIncrementLine:
7072       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7073     case NSScrollerKnob:
7074       last_hit_part = scroll_bar_handle; break;
7075     case NSScrollerKnobSlot:  /* GNUstep-only */
7076       last_hit_part = scroll_bar_move_ratio; break;
7077     default:  /* NSScrollerNoPart? */
7078       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7079                (long) part);
7080       return;
7081     }
7083   if (inc != 0.0)
7084     {
7085       pos = 0;      /* ignored */
7087       /* set a timer to repeat, as we can't let superclass do this modally */
7088       scroll_repeat_entry
7089         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7090                                             target: self
7091                                           selector: @selector (repeatScroll:)
7092                                           userInfo: 0
7093                                            repeats: YES]
7094             retain];
7095     }
7096   else
7097     {
7098       /* handle, or on GNUstep possibly slot */
7099       NSEvent *fake_event;
7101       /* compute float loc in slot and mouse offset on knob */
7102       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7103                       toView: nil];
7104       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7105       if (loc <= 0.0)
7106         {
7107           loc = 0.0;
7108           edge = -1;
7109         }
7110       else if (loc >= NSHeight (sr))
7111         {
7112           loc = NSHeight (sr);
7113           edge = 1;
7114         }
7116       if (edge)
7117         kloc = 0.5 * edge;
7118       else
7119         {
7120           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7121                           toView: nil];
7122           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7123         }
7124       last_mouse_offset = kloc;
7126       /* if knob, tell emacs a location offset by knob pos
7127          (to indicate top of handle) */
7128       if (part == NSScrollerKnob)
7129           pos = (loc - last_mouse_offset) / NSHeight (sr);
7130       else
7131         /* else this is a slot click on GNUstep: go straight there */
7132         pos = loc / NSHeight (sr);
7134       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7135       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7136                                       location: [e locationInWindow]
7137                                  modifierFlags: [e modifierFlags]
7138                                      timestamp: [e timestamp]
7139                                   windowNumber: [e windowNumber]
7140                                        context: [e context]
7141                                    eventNumber: [e eventNumber]
7142                                     clickCount: [e clickCount]
7143                                       pressure: [e pressure]];
7144       [super mouseUp: fake_event];
7145     }
7147   if (part != NSScrollerKnob)
7148     [self sendScrollEventAtLoc: pos fromEvent: e];
7152 /* Called as we manually track scroller drags, rather than superclass. */
7153 - (void)mouseDragged: (NSEvent *)e
7155     NSRect sr;
7156     double loc, pos;
7158     NSTRACE (EmacsScroller_mouseDragged);
7160       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7161                       toView: nil];
7162       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7164       if (loc <= 0.0)
7165         {
7166           loc = 0.0;
7167         }
7168       else if (loc >= NSHeight (sr) + last_mouse_offset)
7169         {
7170           loc = NSHeight (sr) + last_mouse_offset;
7171         }
7173       pos = (loc - last_mouse_offset) / NSHeight (sr);
7174       [self sendScrollEventAtLoc: pos fromEvent: e];
7178 - (void)mouseUp: (NSEvent *)e
7180   if (scroll_repeat_entry)
7181     {
7182       [scroll_repeat_entry invalidate];
7183       [scroll_repeat_entry release];
7184       scroll_repeat_entry = nil;
7185     }
7186   last_hit_part = 0;
7190 /* treat scrollwheel events in the bar as though they were in the main window */
7191 - (void) scrollWheel: (NSEvent *)theEvent
7193   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7194   [view mouseDown: theEvent];
7197 @end  /* EmacsScroller */
7200 #ifdef NS_IMPL_GNUSTEP
7201 /* Dummy class to get rid of startup warnings.  */
7202 @implementation EmacsDocument
7204 @end
7205 #endif
7208 /* ==========================================================================
7210    Font-related functions; these used to be in nsfaces.m
7212    ========================================================================== */
7215 Lisp_Object
7216 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7218   struct font *font = XFONT_OBJECT (font_object);
7220   if (fontset < 0)
7221     fontset = fontset_from_font (font_object);
7222   FRAME_FONTSET (f) = fontset;
7224   if (FRAME_FONT (f) == font)
7225     /* This font is already set in frame F.  There's nothing more to
7226        do.  */
7227     return font_object;
7229   FRAME_FONT (f) = font;
7231   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7232   FRAME_COLUMN_WIDTH (f) = font->average_width;
7233   FRAME_LINE_HEIGHT (f) = font->height;
7235   compute_fringe_widths (f, 1);
7237   /* Compute the scroll bar width in character columns.  */
7238   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7239     {
7240       int wid = FRAME_COLUMN_WIDTH (f);
7241       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7242         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7243     }
7244   else
7245     {
7246       int wid = FRAME_COLUMN_WIDTH (f);
7247       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7248     }
7250   /* Now make the frame display the given font.  */
7251   if (FRAME_NS_WINDOW (f) != 0)
7252         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
7254   return font_object;
7258 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7259 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7260          in 1.43. */
7262 const char *
7263 ns_xlfd_to_fontname (const char *xlfd)
7264 /* --------------------------------------------------------------------------
7265     Convert an X font name (XLFD) to an NS font name.
7266     Only family is used.
7267     The string returned is temporarily allocated.
7268    -------------------------------------------------------------------------- */
7270   char *name = xmalloc (180);
7271   int i, len;
7272   const char *ret;
7274   if (!strncmp (xlfd, "--", 2))
7275     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7276   else
7277     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7279   /* stopgap for malformed XLFD input */
7280   if (strlen (name) == 0)
7281     strcpy (name, "Monaco");
7283   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7284      also uppercase after '-' or ' ' */
7285   name[0] = c_toupper (name[0]);
7286   for (len =strlen (name), i =0; i<len; i++)
7287     {
7288       if (name[i] == '$')
7289         {
7290           name[i] = '-';
7291           if (i+1<len)
7292             name[i+1] = c_toupper (name[i+1]);
7293         }
7294       else if (name[i] == '_')
7295         {
7296           name[i] = ' ';
7297           if (i+1<len)
7298             name[i+1] = c_toupper (name[i+1]);
7299         }
7300     }
7301 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7302   ret = [[NSString stringWithUTF8String: name] UTF8String];
7303   xfree (name);
7304   return ret;
7308 void
7309 syms_of_nsterm (void)
7311   NSTRACE (syms_of_nsterm);
7313   ns_antialias_threshold = 10.0;
7315   /* from 23+ we need to tell emacs what modifiers there are.. */
7316   DEFSYM (Qmodifier_value, "modifier-value");
7317   DEFSYM (Qalt, "alt");
7318   DEFSYM (Qhyper, "hyper");
7319   DEFSYM (Qmeta, "meta");
7320   DEFSYM (Qsuper, "super");
7321   DEFSYM (Qcontrol, "control");
7322   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7324   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7325   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7326   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7327   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7328   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7330   DEFVAR_LISP ("ns-input-file", ns_input_file,
7331               "The file specified in the last NS event.");
7332   ns_input_file =Qnil;
7334   DEFVAR_LISP ("ns-input-text", ns_input_text,
7335               "The data received in the last NS text drag event.");
7336   ns_input_text =Qnil;
7338   DEFVAR_LISP ("ns-working-text", ns_working_text,
7339               "String for visualizing working composition sequence.");
7340   ns_working_text =Qnil;
7342   DEFVAR_LISP ("ns-input-font", ns_input_font,
7343               "The font specified in the last NS event.");
7344   ns_input_font =Qnil;
7346   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7347               "The fontsize specified in the last NS event.");
7348   ns_input_fontsize =Qnil;
7350   DEFVAR_LISP ("ns-input-line", ns_input_line,
7351                "The line specified in the last NS event.");
7352   ns_input_line =Qnil;
7354   DEFVAR_LISP ("ns-input-color", ns_input_color,
7355                "The color specified in the last NS event.");
7356   ns_input_color =Qnil;
7358   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7359                "The service name specified in the last NS event.");
7360   ns_input_spi_name =Qnil;
7362   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7363                "The service argument specified in the last NS event.");
7364   ns_input_spi_arg =Qnil;
7366   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7367                "This variable describes the behavior of the alternate or option key.\n\
7368 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7369 Set to 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_alternate_modifier = Qmeta;
7373   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7374                "This variable describes the behavior of the right alternate or option key.\n\
7375 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7376 Set to left means be the same key as `ns-alternate-modifier'.\n\
7377 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7378 at all, allowing it to be used at a lower level for accented character entry.");
7379   ns_right_alternate_modifier = Qleft;
7381   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7382                "This variable describes the behavior of the command key.\n\
7383 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7384   ns_command_modifier = Qsuper;
7386   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7387                "This variable describes the behavior of the right command key.\n\
7388 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7389 Set to left means be the same key as `ns-command-modifier'.\n\
7390 Set to none means that the command / option key is not interpreted by Emacs\n\
7391 at all, allowing it to be used at a lower level for accented character entry.");
7392   ns_right_command_modifier = Qleft;
7394   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7395                "This variable describes the behavior of the control key.\n\
7396 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7397   ns_control_modifier = Qcontrol;
7399   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7400                "This variable describes the behavior of the right control key.\n\
7401 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7402 Set to left means be the same key as `ns-control-modifier'.\n\
7403 Set to none means that the control / option key is not interpreted by Emacs\n\
7404 at all, allowing it to be used at a lower level for accented character entry.");
7405   ns_right_control_modifier = Qleft;
7407   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7408                "This variable describes the behavior of the function key (on laptops).\n\
7409 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7410 Set to none means that the function key is not interpreted by Emacs at all,\n\
7411 allowing it to be used at a lower level for accented character entry.");
7412   ns_function_modifier = Qnone;
7414   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7415                "Non-nil (the default) means to render text antialiased.");
7416   ns_antialias_text = Qt;
7418   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7419                "Whether to confirm application quit using dialog.");
7420   ns_confirm_quit = Qnil;
7422   staticpro (&ns_display_name_list);
7423   ns_display_name_list = Qnil;
7425   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7426                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7427 Only works on OSX 10.6 or later.  */);
7428   ns_auto_hide_menu_bar = Qnil;
7430   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7431      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7432 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7433 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7434 Default is t for OSX >= 10.7, nil otherwise. */);
7435 #ifdef HAVE_NATIVE_FS
7436   ns_use_native_fullscreen = YES;
7437 #else
7438   ns_use_native_fullscreen = NO;
7439 #endif
7440   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7442   /* TODO: move to common code */
7443   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7444                doc: /* Which toolkit scroll bars Emacs uses, if any.
7445 A value of nil means Emacs doesn't use toolkit scroll bars.
7446 With the X Window system, the value is a symbol describing the
7447 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7448 With MS Windows or Nextstep, the value is t.  */);
7449   Vx_toolkit_scroll_bars = Qt;
7451   DEFVAR_BOOL ("x-use-underline-position-properties",
7452                x_use_underline_position_properties,
7453      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7454 A value of nil means ignore them.  If you encounter fonts with bogus
7455 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7456 to 4.1, set this to nil. */);
7457   x_use_underline_position_properties = 0;
7459   DEFVAR_BOOL ("x-underline-at-descent-line",
7460                x_underline_at_descent_line,
7461      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7462 A value of nil means to draw the underline according to the value of the
7463 variable `x-use-underline-position-properties', which is usually at the
7464 baseline level.  The default value is nil.  */);
7465   x_underline_at_descent_line = 0;
7467   /* Tell Emacs about this window system.  */
7468   Fprovide (Qns, Qnil);
7470   syms_of_nsfont ();
7471 #ifdef NS_IMPL_COCOA
7472 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
7473   syms_of_macfont ();
7474 #endif
7475 #endif
7476