Merge from trunk.
[emacs/old-mirror.git] / src / nsterm.m
blob9c87923f32e5730d57427dcc5a205634c66c05a4
1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2013
4   Free Software 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;
176 static Lisp_Object Qcocoa, Qgnustep;
178 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
179    the maximum font size to NOT antialias.  On GNUstep there is currently
180    no way to control this behavior. */
181 float ns_antialias_threshold;
183 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
184 NSString *ns_app_name = @"Emacs";  /* default changed later */
186 /* Display variables */
187 struct ns_display_info *x_display_list; /* Chain of existing displays */
188 long context_menu_value = 0;
190 /* display update */
191 static struct frame *ns_updating_frame;
192 static NSView *focus_view = NULL;
193 static int ns_window_num = 0;
194 #ifdef NS_IMPL_GNUSTEP
195 static NSRect uRect;
196 #endif
197 static BOOL gsaved = NO;
198 static BOOL ns_fake_keydown = NO;
199 #ifdef NS_IMPL_COCOA
200 static BOOL ns_menu_bar_is_hidden = NO;
201 #endif
202 /*static int debug_lock = 0; */
204 /* event loop */
205 static BOOL send_appdefined = YES;
206 #define NO_APPDEFINED_DATA (-8)
207 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
208 static NSTimer *timed_entry = 0;
209 static NSTimer *scroll_repeat_entry = nil;
210 static fd_set select_readfds, select_writefds;
211 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
212 static int select_nfds = 0, select_valid = 0;
213 static struct timespec select_timeout = { 0, 0 };
214 static int selfds[2] = { -1, -1 };
215 static pthread_mutex_t select_mutex;
216 static int apploopnr = 0;
217 static NSAutoreleasePool *outerpool;
218 static struct input_event *emacs_event = NULL;
219 static struct input_event *q_event_ptr = NULL;
220 static int n_emacs_events_pending = 0;
221 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
222   *ns_pending_service_args;
223 static BOOL ns_do_open_file = NO;
224 static BOOL ns_last_use_native_fullscreen;
226 static struct {
227   struct input_event *q;
228   int nr, cap;
229 } hold_event_q = {
230   NULL, 0, 0
233 #ifdef NS_IMPL_COCOA
235  * State for pending menu activation:
236  * MENU_NONE     Normal state
237  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
238  *               run lisp to update the menu.
239  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
240  *               will open.
241  */
242 #define MENU_NONE 0
243 #define MENU_PENDING 1
244 #define MENU_OPENING 2
245 static int menu_will_open_state = MENU_NONE;
247 /* Saved position for menu click.  */
248 static CGPoint menu_mouse_point;
249 #endif
251 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
252 #define NS_FUNCTION_KEY_MASK 0x800000
253 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
254 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
255 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
256 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
257 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
258 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
259 #define EV_MODIFIERS(e)                               \
260     ((([e modifierFlags] & NSHelpKeyMask) ?           \
261            hyper_modifier : 0)                        \
262      | (!EQ (ns_right_alternate_modifier, Qleft) && \
263         (([e modifierFlags] & NSRightAlternateKeyMask) \
264          == NSRightAlternateKeyMask) ? \
265            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
266      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
267            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
268      | (([e modifierFlags] & NSShiftKeyMask) ?     \
269            shift_modifier : 0)                        \
270      | (!EQ (ns_right_control_modifier, Qleft) && \
271         (([e modifierFlags] & NSRightControlKeyMask) \
272          == NSRightControlKeyMask) ? \
273            parse_solitary_modifier (ns_right_control_modifier) : 0) \
274      | (([e modifierFlags] & NSControlKeyMask) ?      \
275            parse_solitary_modifier (ns_control_modifier) : 0)     \
276      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
277            parse_solitary_modifier (ns_function_modifier) : 0)    \
278      | (!EQ (ns_right_command_modifier, Qleft) && \
279         (([e modifierFlags] & NSRightCommandKeyMask) \
280          == NSRightCommandKeyMask) ? \
281            parse_solitary_modifier (ns_right_command_modifier) : 0) \
282      | (([e modifierFlags] & NSCommandKeyMask) ?      \
283            parse_solitary_modifier (ns_command_modifier):0))
285 #define EV_UDMODIFIERS(e)                                      \
286     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
287      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
288      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
289      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
290      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
291      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
292      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
293      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
294      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
296 #define EV_BUTTON(e)                                                         \
297     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
298       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
299      [e buttonNumber] - 1)
301 /* Convert the time field to a timestamp in milliseconds. */
302 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
304 /* This is a piece of code which is common to all the event handling
305    methods.  Maybe it should even be a function.  */
306 #define EV_TRAILER(e)                                                   \
307   {                                                                     \
308     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
309     EV_TRAILER2 (e);                                                    \
310   }
312 #define EV_TRAILER2(e)                                                  \
313   {                                                                     \
314       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
315       if (q_event_ptr)                                                  \
316         {                                                               \
317           n_emacs_events_pending++;                                     \
318           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
319         }                                                               \
320       else                                                              \
321         hold_event (emacs_event);                                       \
322       EVENT_INIT (*emacs_event);                                        \
323       ns_send_appdefined (-1);                                          \
324     }
326 /* TODO: get rid of need for these forward declarations */
327 static void ns_condemn_scroll_bars (struct frame *f);
328 static void ns_judge_scroll_bars (struct frame *f);
329 void x_set_frame_alpha (struct frame *f);
332 /* ==========================================================================
334     Utilities
336    ========================================================================== */
338 static void
339 hold_event (struct input_event *event)
341   if (hold_event_q.nr == hold_event_q.cap)
342     {
343       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
344       else hold_event_q.cap *= 2;
345       hold_event_q.q =
346         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
347     }
349   hold_event_q.q[hold_event_q.nr++] = *event;
350   /* Make sure ns_read_socket is called, i.e. we have input.  */
351   raise (SIGIO);
352   send_appdefined = YES;
355 static Lisp_Object
356 append2 (Lisp_Object list, Lisp_Object item)
357 /* --------------------------------------------------------------------------
358    Utility to append to a list
359    -------------------------------------------------------------------------- */
361   Lisp_Object array[2];
362   array[0] = list;
363   array[1] = list1 (item);
364   return Fnconc (2, &array[0]);
368 const char *
369 ns_etc_directory (void)
370 /* If running as a self-contained app bundle, return as a string the
371    filename of the etc directory, if present; else nil.  */
373   NSBundle *bundle = [NSBundle mainBundle];
374   NSString *resourceDir = [bundle resourcePath];
375   NSString *resourcePath;
376   NSFileManager *fileManager = [NSFileManager defaultManager];
377   BOOL isDir;
379   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
380   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
381     {
382       if (isDir) return [resourcePath UTF8String];
383     }
384   return NULL;
388 const char *
389 ns_exec_path (void)
390 /* If running as a self-contained app bundle, return as a path string
391    the filenames of the libexec and bin directories, ie libexec:bin.
392    Otherwise, return nil.
393    Normally, Emacs does not add its own bin/ directory to the PATH.
394    However, a self-contained NS build has a different layout, with
395    bin/ and libexec/ subdirectories in the directory that contains
396    Emacs.app itself.
397    We put libexec first, because init_callproc_1 uses the first
398    element to initialize exec-directory.  An alternative would be
399    for init_callproc to check for invocation-directory/libexec.
402   NSBundle *bundle = [NSBundle mainBundle];
403   NSString *resourceDir = [bundle resourcePath];
404   NSString *binDir = [bundle bundlePath];
405   NSString *resourcePath, *resourcePaths;
406   NSRange range;
407   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
408   NSFileManager *fileManager = [NSFileManager defaultManager];
409   NSArray *paths;
410   NSEnumerator *pathEnum;
411   BOOL isDir;
413   range = [resourceDir rangeOfString: @"Contents"];
414   if (range.location != NSNotFound)
415     {
416       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
417 #ifdef NS_IMPL_COCOA
418       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
419 #endif
420     }
422   paths = [binDir stringsByAppendingPaths:
423                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
424   pathEnum = [paths objectEnumerator];
425   resourcePaths = @"";
427   while ((resourcePath = [pathEnum nextObject]))
428     {
429       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
430         if (isDir)
431           {
432             if ([resourcePaths length] > 0)
433               resourcePaths
434                 = [resourcePaths stringByAppendingString: pathSeparator];
435             resourcePaths
436               = [resourcePaths stringByAppendingString: resourcePath];
437           }
438     }
439   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
441   return NULL;
445 const char *
446 ns_load_path (void)
447 /* If running as a self-contained app bundle, return as a path string
448    the filenames of the site-lisp and lisp directories.
449    Ie, site-lisp:lisp.  Otherwise, return nil.  */
451   NSBundle *bundle = [NSBundle mainBundle];
452   NSString *resourceDir = [bundle resourcePath];
453   NSString *resourcePath, *resourcePaths;
454   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
455   NSFileManager *fileManager = [NSFileManager defaultManager];
456   BOOL isDir;
457   NSArray *paths = [resourceDir stringsByAppendingPaths:
458                               [NSArray arrayWithObjects:
459                                          @"site-lisp", @"lisp", nil]];
460   NSEnumerator *pathEnum = [paths objectEnumerator];
461   resourcePaths = @"";
463   /* Hack to skip site-lisp.  */
464   if (no_site_lisp) resourcePath = [pathEnum nextObject];
466   while ((resourcePath = [pathEnum nextObject]))
467     {
468       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
469         if (isDir)
470           {
471             if ([resourcePaths length] > 0)
472               resourcePaths
473                 = [resourcePaths stringByAppendingString: pathSeparator];
474             resourcePaths
475               = [resourcePaths stringByAppendingString: resourcePath];
476           }
477     }
478   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
480   return NULL;
483 static void
484 ns_timeout (int usecs)
485 /* --------------------------------------------------------------------------
486      Blocking timer utility used by ns_ring_bell
487    -------------------------------------------------------------------------- */
489   struct timespec wakeup = timespec_add (current_timespec (),
490                                          make_timespec (0, usecs * 1000));
492   /* Keep waiting until past the time wakeup.  */
493   while (1)
494     {
495       struct timespec timeout, now = current_timespec ();
496       if (timespec_cmp (wakeup, now) <= 0)
497         break;
498       timeout = timespec_sub (wakeup, now);
500       /* Try to wait that long--but we might wake up sooner.  */
501       pselect (0, NULL, NULL, NULL, &timeout, NULL);
502     }
506 void
507 ns_release_object (void *obj)
508 /* --------------------------------------------------------------------------
509     Release an object (callable from C)
510    -------------------------------------------------------------------------- */
512     [(id)obj release];
516 void
517 ns_retain_object (void *obj)
518 /* --------------------------------------------------------------------------
519     Retain an object (callable from C)
520    -------------------------------------------------------------------------- */
522     [(id)obj retain];
526 void *
527 ns_alloc_autorelease_pool (void)
528 /* --------------------------------------------------------------------------
529      Allocate a pool for temporary objects (callable from C)
530    -------------------------------------------------------------------------- */
532   return [[NSAutoreleasePool alloc] init];
536 void
537 ns_release_autorelease_pool (void *pool)
538 /* --------------------------------------------------------------------------
539      Free a pool and temporary objects it refers to (callable from C)
540    -------------------------------------------------------------------------- */
542   ns_release_object (pool);
547 /* ==========================================================================
549     Focus (clipping) and screen update
551    ========================================================================== */
554 // Window constraining
555 // -------------------
557 // To ensure that the windows are not placed under the menu bar, they
558 // are typically moved by the call-back constrainFrameRect. However,
559 // by overriding it, it's possible to inhibit this, leaving the window
560 // in it's original position.
562 // It's possible to hide the menu bar. However, technically, it's only
563 // possible to hide it when the application is active. To ensure that
564 // this work properly, the menu bar and window constraining are
565 // deferred until the application becomes active.
567 // Even though it's not possible to manually move a window above the
568 // top of the screen, it is allowed if it's done programmatically,
569 // when the menu is hidden. This allows the editable area to cover the
570 // full screen height.
572 // Test cases
573 // ----------
575 // Use the following extra files:
577 //    init.el:
578 //       ;; Hide menu and place frame slightly above the top of the screen.
579 //       (setq ns-auto-hide-menu-bar t)
580 //       (set-frame-position (selected-frame) 0 -20)
582 // Test 1:
584 //    emacs -Q -l init.el
586 //    Result: No menu bar, and the title bar should be above the screen.
588 // Test 2:
590 //    emacs -Q
592 //    Result: Menu bar visible, frame placed immediately below the menu.
595 static void
596 ns_constrain_all_frames (void)
598   Lisp_Object tail, frame;
600   FOR_EACH_FRAME (tail, frame)
601     {
602       struct frame *f = XFRAME (frame);
603       if (FRAME_NS_P (f))
604         {
605           NSView *view = FRAME_NS_VIEW (f);
606           /* This no-op will trigger the default window placing
607            * constraint system. */
608           f->output_data.ns->dont_constrain = 0;
609           [[view window] setFrameOrigin:[[view window] frame].origin];
610         }
611     }
615 /* True, if the menu bar should be hidden.  */
617 static BOOL
618 ns_menu_bar_should_be_hidden (void)
620   return !NILP (ns_auto_hide_menu_bar)
621     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
625 /* Show or hide the menu bar, based on user setting.  */
627 static void
628 ns_update_auto_hide_menu_bar (void)
630 #ifdef NS_IMPL_COCOA
631 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
632   block_input ();
634   NSTRACE (ns_update_auto_hide_menu_bar);
636   if (NSApp != nil && [NSApp isActive])
637     {
638       // Note, "setPresentationOptions" triggers an error unless the
639       // application is active.
640       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
642       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
643         {
644           NSApplicationPresentationOptions options
645             = NSApplicationPresentationDefault;
647           if (menu_bar_should_be_hidden)
648             options |= NSApplicationPresentationAutoHideMenuBar
649               | NSApplicationPresentationAutoHideDock;
651           [NSApp setPresentationOptions: options];
653           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
655           if (!ns_menu_bar_is_hidden)
656             {
657               ns_constrain_all_frames ();
658             }
659         }
660     }
662   unblock_input ();
663 #endif
664 #endif
668 static void
669 ns_update_begin (struct frame *f)
670 /* --------------------------------------------------------------------------
671    Prepare for a grouped sequence of drawing calls
672    external (RIF) call; whole frame, called before update_window_begin
673    -------------------------------------------------------------------------- */
675   EmacsView *view = FRAME_NS_VIEW (f);
676   NSTRACE (ns_update_begin);
678   ns_update_auto_hide_menu_bar ();
680 #ifdef NS_IMPL_COCOA
681   if ([view isFullscreen] && [view fsIsNative])
682   {
683     // Fix reappearing tool bar in fullscreen for OSX 10.7
684     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
685     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
686     if (! tbar_visible != ! [toolbar isVisible])
687       [toolbar setVisible: tbar_visible];
688   }
689 #endif
691   ns_updating_frame = f;
692   [view lockFocus];
694   /* drawRect may have been called for say the minibuffer, and then clip path
695      is for the minibuffer.  But the display engine may draw more because
696      we have set the frame as garbaged.  So reset clip path to the whole
697      view.  */
698 #ifdef NS_IMPL_COCOA
699   {
700     NSBezierPath *bp;
701     NSRect r = [view frame];
702     NSRect cr = [[view window] frame];
703     /* If a large frame size is set, r may be larger than the window frame
704        before constrained.  In that case don't change the clip path, as we
705        will clear in to the tool bar and title bar.  */
706     if (r.size.height
707         + FRAME_NS_TITLEBAR_HEIGHT (f)
708         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
709       {
710         bp = [[NSBezierPath bezierPathWithRect: r] retain];
711         [bp setClip];
712         [bp release];
713       }
714   }
715 #endif
717 #ifdef NS_IMPL_GNUSTEP
718   uRect = NSMakeRect (0, 0, 0, 0);
719 #endif
723 static void
724 ns_update_window_begin (struct window *w)
725 /* --------------------------------------------------------------------------
726    Prepare for a grouped sequence of drawing calls
727    external (RIF) call; for one window, called after update_begin
728    -------------------------------------------------------------------------- */
730   struct frame *f = XFRAME (WINDOW_FRAME (w));
731   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
733   NSTRACE (ns_update_window_begin);
734   w->output_cursor = w->cursor;
736   block_input ();
738   if (f == hlinfo->mouse_face_mouse_frame)
739     {
740       /* Don't do highlighting for mouse motion during the update.  */
741       hlinfo->mouse_face_defer = 1;
743         /* If the frame needs to be redrawn,
744            simply forget about any prior mouse highlighting.  */
745       if (FRAME_GARBAGED_P (f))
746         hlinfo->mouse_face_window = Qnil;
748       /* (further code for mouse faces ifdef'd out in other terms elided) */
749     }
751   unblock_input ();
755 static void
756 ns_update_window_end (struct window *w, bool cursor_on_p,
757                       bool mouse_face_overwritten_p)
758 /* --------------------------------------------------------------------------
759    Finished a grouped sequence of drawing calls
760    external (RIF) call; for one window called before update_end
761    -------------------------------------------------------------------------- */
763   /* note: this fn is nearly identical in all terms */
764   if (!w->pseudo_window_p)
765     {
766       block_input ();
768       if (cursor_on_p)
769         display_and_set_cursor (w, 1,
770                                 w->output_cursor.hpos, w->output_cursor.vpos,
771                                 w->output_cursor.x, w->output_cursor.y);
773       if (draw_window_fringes (w, 1))
774         {
775           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
776             x_draw_right_divider (w);
777           else
778             x_draw_vertical_border (w);
779         }
781       unblock_input ();
782     }
784   /* If a row with mouse-face was overwritten, arrange for
785      frame_up_to_date to redisplay the mouse highlight.  */
786   if (mouse_face_overwritten_p)
787     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
789   NSTRACE (update_window_end);
793 static void
794 ns_update_end (struct frame *f)
795 /* --------------------------------------------------------------------------
796    Finished a grouped sequence of drawing calls
797    external (RIF) call; for whole frame, called after update_window_end
798    -------------------------------------------------------------------------- */
800   EmacsView *view = FRAME_NS_VIEW (f);
802 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
803   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
805   block_input ();
807   [view unlockFocus];
808   [[view window] flushWindow];
810   unblock_input ();
811   ns_updating_frame = NULL;
812   NSTRACE (ns_update_end);
815 static void
816 ns_focus (struct frame *f, NSRect *r, int n)
817 /* --------------------------------------------------------------------------
818    Internal: Focus on given frame.  During small local updates this is used to
819      draw, however during large updates, ns_update_begin and ns_update_end are
820      called to wrap the whole thing, in which case these calls are stubbed out.
821      Except, on GNUstep, we accumulate the rectangle being drawn into, because
822      the back end won't do this automatically, and will just end up flushing
823      the entire window.
824    -------------------------------------------------------------------------- */
826 //  NSTRACE (ns_focus);
827 /* static int c =0;
828    fprintf (stderr, "focus: %d", c++);
829    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
830    fprintf (stderr, "\n"); */
832   if (f != ns_updating_frame)
833     {
834       NSView *view = FRAME_NS_VIEW (f);
835       if (view != focus_view)
836         {
837           if (focus_view != NULL)
838             {
839               [focus_view unlockFocus];
840               [[focus_view window] flushWindow];
841 /*debug_lock--; */
842             }
844           if (view)
845             [view lockFocus];
846           focus_view = view;
847 /*if (view) debug_lock++; */
848         }
849     }
851   /* clipping */
852   if (r)
853     {
854       [[NSGraphicsContext currentContext] saveGraphicsState];
855       if (n == 2)
856         NSRectClipList (r, 2);
857       else
858         NSRectClip (*r);
859       gsaved = YES;
860     }
864 static void
865 ns_unfocus (struct frame *f)
866 /* --------------------------------------------------------------------------
867      Internal: Remove focus on given frame
868    -------------------------------------------------------------------------- */
870 //  NSTRACE (ns_unfocus);
872   if (gsaved)
873     {
874       [[NSGraphicsContext currentContext] restoreGraphicsState];
875       gsaved = NO;
876     }
878   if (f != ns_updating_frame)
879     {
880       if (focus_view != NULL)
881         {
882           [focus_view unlockFocus];
883           [[focus_view window] flushWindow];
884           focus_view = NULL;
885 /*debug_lock--; */
886         }
887     }
891 static void
892 ns_clip_to_row (struct window *w, struct glyph_row *row,
893                 enum glyph_row_area area, BOOL gc)
894 /* --------------------------------------------------------------------------
895      Internal (but parallels other terms): Focus drawing on given row
896    -------------------------------------------------------------------------- */
898   struct frame *f = XFRAME (WINDOW_FRAME (w));
899   NSRect clip_rect;
900   int window_x, window_y, window_width;
902   window_box (w, area, &window_x, &window_y, &window_width, 0);
904   clip_rect.origin.x = window_x;
905   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
906   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
907   clip_rect.size.width = window_width;
908   clip_rect.size.height = row->visible_height;
910   ns_focus (f, &clip_rect, 1);
914 static void
915 ns_ring_bell (struct frame *f)
916 /* --------------------------------------------------------------------------
917      "Beep" routine
918    -------------------------------------------------------------------------- */
920   NSTRACE (ns_ring_bell);
921   if (visible_bell)
922     {
923       NSAutoreleasePool *pool;
924       struct frame *frame = SELECTED_FRAME ();
925       NSView *view;
927       block_input ();
928       pool = [[NSAutoreleasePool alloc] init];
930       view = FRAME_NS_VIEW (frame);
931       if (view != nil)
932         {
933           NSRect r, surr;
934           NSPoint dim = NSMakePoint (128, 128);
936           r = [view bounds];
937           r.origin.x += (r.size.width - dim.x) / 2;
938           r.origin.y += (r.size.height - dim.y) / 2;
939           r.size.width = dim.x;
940           r.size.height = dim.y;
941           surr = NSInsetRect (r, -2, -2);
942           ns_focus (frame, &surr, 1);
943           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
944           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
945                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
946           NSRectFill (r);
947           [[view window] flushWindow];
948           ns_timeout (150000);
949           [[view window] restoreCachedImage];
950           [[view window] flushWindow];
951           ns_unfocus (frame);
952         }
953       [pool release];
954       unblock_input ();
955     }
956   else
957     {
958       NSBeep ();
959     }
962 /* ==========================================================================
964     Frame / window manager related functions
966    ========================================================================== */
969 static void
970 ns_raise_frame (struct frame *f)
971 /* --------------------------------------------------------------------------
972      Bring window to foreground and make it active
973    -------------------------------------------------------------------------- */
975   NSView *view;
976   check_window_system (f);
977   view = FRAME_NS_VIEW (f);
978   block_input ();
979   if (FRAME_VISIBLE_P (f))
980     [[view window] makeKeyAndOrderFront: NSApp];
981   unblock_input ();
985 static void
986 ns_lower_frame (struct frame *f)
987 /* --------------------------------------------------------------------------
988      Send window to back
989    -------------------------------------------------------------------------- */
991   NSView *view;
992   check_window_system (f);
993   view = FRAME_NS_VIEW (f);
994   block_input ();
995   [[view window] orderBack: NSApp];
996   unblock_input ();
1000 static void
1001 ns_frame_raise_lower (struct frame *f, int raise)
1002 /* --------------------------------------------------------------------------
1003      External (hook)
1004    -------------------------------------------------------------------------- */
1006   NSTRACE (ns_frame_raise_lower);
1008   if (raise)
1009     ns_raise_frame (f);
1010   else
1011     ns_lower_frame (f);
1015 static void
1016 ns_frame_rehighlight (struct frame *frame)
1017 /* --------------------------------------------------------------------------
1018      External (hook): called on things like window switching within frame
1019    -------------------------------------------------------------------------- */
1021   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1022   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1024   NSTRACE (ns_frame_rehighlight);
1025   if (dpyinfo->x_focus_frame)
1026     {
1027       dpyinfo->x_highlight_frame
1028         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1029            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1030            : dpyinfo->x_focus_frame);
1031       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1032         {
1033           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1034           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1035         }
1036     }
1037   else
1038       dpyinfo->x_highlight_frame = 0;
1040   if (dpyinfo->x_highlight_frame &&
1041          dpyinfo->x_highlight_frame != old_highlight)
1042     {
1043       if (old_highlight)
1044         {
1045           x_update_cursor (old_highlight, 1);
1046           x_set_frame_alpha (old_highlight);
1047         }
1048       if (dpyinfo->x_highlight_frame)
1049         {
1050           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1051           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1052         }
1053     }
1057 void
1058 x_make_frame_visible (struct frame *f)
1059 /* --------------------------------------------------------------------------
1060      External: Show the window (X11 semantics)
1061    -------------------------------------------------------------------------- */
1063   NSTRACE (x_make_frame_visible);
1064   /* XXX: at some points in past this was not needed, as the only place that
1065      called this (frame.c:Fraise_frame ()) also called raise_lower;
1066      if this ends up the case again, comment this out again. */
1067   if (!FRAME_VISIBLE_P (f))
1068     {
1069       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1071       SET_FRAME_VISIBLE (f, 1);
1072       ns_raise_frame (f);
1074       /* Making a new frame from a fullscreen frame will make the new frame
1075          fullscreen also.  So skip handleFS as this will print an error.  */
1076       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1077           && [view isFullscreen])
1078         return;
1080       if (f->want_fullscreen != FULLSCREEN_NONE)
1081         {
1082           block_input ();
1083           [view handleFS];
1084           unblock_input ();
1085         }
1086     }
1090 void
1091 x_make_frame_invisible (struct frame *f)
1092 /* --------------------------------------------------------------------------
1093      External: Hide the window (X11 semantics)
1094    -------------------------------------------------------------------------- */
1096   NSView *view;
1097   NSTRACE (x_make_frame_invisible);
1098   check_window_system (f);
1099   view = FRAME_NS_VIEW (f);
1100   [[view window] orderOut: NSApp];
1101   SET_FRAME_VISIBLE (f, 0);
1102   SET_FRAME_ICONIFIED (f, 0);
1106 void
1107 x_iconify_frame (struct frame *f)
1108 /* --------------------------------------------------------------------------
1109      External: Iconify window
1110    -------------------------------------------------------------------------- */
1112   NSView *view;
1113   struct ns_display_info *dpyinfo;
1115   NSTRACE (x_iconify_frame);
1116   check_window_system (f);
1117   view = FRAME_NS_VIEW (f);
1118   dpyinfo = FRAME_DISPLAY_INFO (f);
1120   if (dpyinfo->x_highlight_frame == f)
1121     dpyinfo->x_highlight_frame = 0;
1123   if ([[view window] windowNumber] <= 0)
1124     {
1125       /* the window is still deferred.  Make it very small, bring it
1126          on screen and order it out. */
1127       NSRect s = { { 100, 100}, {0, 0} };
1128       NSRect t;
1129       t = [[view window] frame];
1130       [[view window] setFrame: s display: NO];
1131       [[view window] orderBack: NSApp];
1132       [[view window] orderOut: NSApp];
1133       [[view window] setFrame: t display: NO];
1134     }
1135   [[view window] miniaturize: NSApp];
1138 /* Free X resources of frame F.  */
1140 void
1141 x_free_frame_resources (struct frame *f)
1143   NSView *view;
1144   struct ns_display_info *dpyinfo;
1145   Mouse_HLInfo *hlinfo;
1147   NSTRACE (x_free_frame_resources);
1148   check_window_system (f);
1149   view = FRAME_NS_VIEW (f);
1150   dpyinfo = FRAME_DISPLAY_INFO (f);
1151   hlinfo = MOUSE_HL_INFO (f);
1153   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1155   block_input ();
1157   free_frame_menubar (f);
1159   if (FRAME_FACE_CACHE (f))
1160     free_frame_faces (f);
1162   if (f == dpyinfo->x_focus_frame)
1163     dpyinfo->x_focus_frame = 0;
1164   if (f == dpyinfo->x_highlight_frame)
1165     dpyinfo->x_highlight_frame = 0;
1166   if (f == hlinfo->mouse_face_mouse_frame)
1167     reset_mouse_highlight (hlinfo);
1169   if (f->output_data.ns->miniimage != nil)
1170     [f->output_data.ns->miniimage release];
1172   [[view window] close];
1173   [view release];
1175   xfree (f->output_data.ns);
1177   unblock_input ();
1180 void
1181 x_destroy_window (struct frame *f)
1182 /* --------------------------------------------------------------------------
1183      External: Delete the window
1184    -------------------------------------------------------------------------- */
1186   NSTRACE (x_destroy_window);
1187   check_window_system (f);
1188   x_free_frame_resources (f);
1189   ns_window_num--;
1193 void
1194 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1195 /* --------------------------------------------------------------------------
1196      External: Position the window
1197    -------------------------------------------------------------------------- */
1199   NSView *view = FRAME_NS_VIEW (f);
1200   NSArray *screens = [NSScreen screens];
1201   NSScreen *fscreen = [screens objectAtIndex: 0];
1202   NSScreen *screen = [[view window] screen];
1204   NSTRACE (x_set_offset);
1206   block_input ();
1208   f->left_pos = xoff;
1209   f->top_pos = yoff;
1211   if (view != nil && screen && fscreen)
1212     {
1213       f->left_pos = f->size_hint_flags & XNegative
1214         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1215         : f->left_pos;
1216       /* We use visibleFrame here to take menu bar into account.
1217          Ideally we should also adjust left/top with visibleFrame.origin.  */
1219       f->top_pos = f->size_hint_flags & YNegative
1220         ? ([screen visibleFrame].size.height + f->top_pos
1221            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1222            - FRAME_TOOLBAR_HEIGHT (f))
1223         : f->top_pos;
1224 #ifdef NS_IMPL_GNUSTEP
1225       if (f->left_pos < 100)
1226         f->left_pos = 100;  /* don't overlap menu */
1227 #endif
1228       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1229          menu bar.  */
1230       f->output_data.ns->dont_constrain = 0;
1231       [[view window] setFrameTopLeftPoint:
1232                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1233                                     SCREENMAXBOUND ([fscreen frame].size.height
1234                                                     - NS_TOP_POS (f)))];
1235       f->size_hint_flags &= ~(XNegative|YNegative);
1236     }
1238   unblock_input ();
1242 void
1243 x_set_window_size (struct frame *f,
1244                    int change_grav,
1245                    int width,
1246                    int height,
1247                    bool pixelwise)
1248 /* --------------------------------------------------------------------------
1249      Adjust window pixel size based on given character grid size
1250      Impl is a bit more complex than other terms, need to do some
1251      internal clipping.
1252    -------------------------------------------------------------------------- */
1254   EmacsView *view = FRAME_NS_VIEW (f);
1255   NSWindow *window = [view window];
1256   NSRect wr = [window frame];
1257   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1258   int pixelwidth, pixelheight;
1259   int rows, cols;
1261   NSTRACE (x_set_window_size);
1263   if (view == nil)
1264     return;
1266 /*fprintf (stderr, "\tsetWindowSize: %d x %d, pixelwise %d, font size %d x %d\n", width, height, pixelwise, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));*/
1268   block_input ();
1270   check_frame_size (f, &width, &height, pixelwise);
1272   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1273   compute_fringe_widths (f, 0);
1275   if (pixelwise)
1276     {
1277       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1278       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1279       cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
1280       rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
1281     }
1282   else
1283     {
1284       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1285       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1286       cols = width;
1287       rows = height;
1288     }
1290   /* If we have a toolbar, take its height into account. */
1291   if (tb && ! [view isFullscreen])
1292     {
1293     /* NOTE: previously this would generate wrong result if toolbar not
1294              yet displayed and fixing toolbar_height=32 helped, but
1295              now (200903) seems no longer needed */
1296     FRAME_TOOLBAR_HEIGHT (f) =
1297       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1298         - FRAME_NS_TITLEBAR_HEIGHT (f);
1299 #ifdef NS_IMPL_GNUSTEP
1300       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1301 #endif
1302     }
1303   else
1304     FRAME_TOOLBAR_HEIGHT (f) = 0;
1306   wr.size.width = pixelwidth + f->border_width;
1307   wr.size.height = pixelheight;
1308   if (! [view isFullscreen])
1309     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1310       + FRAME_TOOLBAR_HEIGHT (f);
1312   /* Do not try to constrain to this screen.  We may have multiple
1313      screens, and want Emacs to span those.  Constraining to screen
1314      prevents that, and that is not nice to the user.  */
1315  if (f->output_data.ns->zooming)
1316    f->output_data.ns->zooming = 0;
1317  else
1318    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1320   [view setRows: rows andColumns: cols];
1321   [window setFrame: wr display: YES];
1323   /* This is a trick to compensate for Emacs' managing the scrollbar area
1324      as a fixed number of standard character columns.  Instead of leaving
1325      blank space for the extra, we chopped it off above.  Now for
1326      left-hand scrollbars, we shift all rendering to the left by the
1327      difference between the real width and Emacs' imagined one.  For
1328      right-hand bars, don't worry about it since the extra is never used.
1329      (Obviously doesn't work for vertically split windows tho..) */
1330   {
1331     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1332       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1333                      - NS_SCROLL_BAR_WIDTH (f), 0)
1334       : NSMakePoint (0, 0);
1335     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1336     [view setBoundsOrigin: origin];
1337   }
1339   change_frame_size (f, width, height, 0, 1, 0, pixelwise);
1340 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1342   mark_window_cursors_off (XWINDOW (f->root_window));
1343   cancel_mouse_face (f);
1345   unblock_input ();
1349 static void
1350 ns_fullscreen_hook (struct frame *f)
1352   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1354   if (!FRAME_VISIBLE_P (f))
1355     return;
1357    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1358     {
1359       /* Old style fs don't initiate correctly if created from
1360          init/default-frame alist, so use a timer (not nice...).
1361       */
1362       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1363                                      selector: @selector (handleFS)
1364                                      userInfo: nil repeats: NO];
1365       return;
1366     }
1368   block_input ();
1369   [view handleFS];
1370   unblock_input ();
1373 /* ==========================================================================
1375     Color management
1377    ========================================================================== */
1380 NSColor *
1381 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1383   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1384   if (idx < 1 || idx >= color_table->avail)
1385     return nil;
1386   return color_table->colors[idx];
1390 unsigned long
1391 ns_index_color (NSColor *color, struct frame *f)
1393   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1394   ptrdiff_t idx;
1395   ptrdiff_t i;
1397   if (!color_table->colors)
1398     {
1399       color_table->size = NS_COLOR_CAPACITY;
1400       color_table->avail = 1; /* skip idx=0 as marker */
1401       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1402       color_table->colors[0] = nil;
1403       color_table->empty_indices = [[NSMutableSet alloc] init];
1404     }
1406   /* Do we already have this color?  */
1407   for (i = 1; i < color_table->avail; i++)
1408     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1409       return i;
1411   if ([color_table->empty_indices count] > 0)
1412     {
1413       NSNumber *index = [color_table->empty_indices anyObject];
1414       [color_table->empty_indices removeObject: index];
1415       idx = [index unsignedLongValue];
1416     }
1417   else
1418     {
1419       if (color_table->avail == color_table->size)
1420         color_table->colors =
1421           xpalloc (color_table->colors, &color_table->size, 1,
1422                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1423       idx = color_table->avail++;
1424     }
1426   color_table->colors[idx] = color;
1427   [color retain];
1428 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1429   return idx;
1433 void
1434 ns_free_indexed_color (unsigned long idx, struct frame *f)
1436   struct ns_color_table *color_table;
1437   NSColor *color;
1438   NSNumber *index;
1440   if (!f)
1441     return;
1443   color_table = FRAME_DISPLAY_INFO (f)->color_table;
1445   if (idx <= 0 || idx >= color_table->size) {
1446     message1 ("ns_free_indexed_color: Color index out of range.\n");
1447     return;
1448   }
1450   index = [NSNumber numberWithUnsignedInt: idx];
1451   if ([color_table->empty_indices containsObject: index]) {
1452     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1453     return;
1454   }
1456   color = color_table->colors[idx];
1457   [color release];
1458   color_table->colors[idx] = nil;
1459   [color_table->empty_indices addObject: index];
1460 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1464 static int
1465 ns_get_color (const char *name, NSColor **col)
1466 /* --------------------------------------------------------------------------
1467      Parse a color name
1468    -------------------------------------------------------------------------- */
1469 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1470    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1471    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1473   NSColor *new = nil;
1474   static char hex[20];
1475   int scaling;
1476   float r = -1.0, g, b;
1477   NSString *nsname = [NSString stringWithUTF8String: name];
1479 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1480   block_input ();
1482   if ([nsname isEqualToString: @"ns_selection_bg_color"])
1483     {
1484 #ifdef NS_IMPL_COCOA
1485       NSString *defname = [[NSUserDefaults standardUserDefaults]
1486                             stringForKey: @"AppleHighlightColor"];
1487       if (defname != nil)
1488         nsname = defname;
1489       else
1490 #endif
1491       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1492         {
1493           *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1494           unblock_input ();
1495           return 0;
1496         }
1497       else
1498         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1500       name = [nsname UTF8String];
1501     }
1502   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1503     {
1504       /* NOTE: OSX applications normally don't set foreground selection, but
1505          text may be unreadable if we don't.
1506       */
1507       if ((new = [NSColor selectedTextColor]) != nil)
1508         {
1509           *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1510           unblock_input ();
1511           return 0;
1512         }
1514       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1515       name = [nsname UTF8String];
1516     }
1518   /* First, check for some sort of numeric specification. */
1519   hex[0] = '\0';
1521   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1522     {
1523       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1524       [scanner scanFloat: &r];
1525       [scanner scanFloat: &g];
1526       [scanner scanFloat: &b];
1527     }
1528   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1529     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1530   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1531     {
1532       int len = (strlen(name) - 1);
1533       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1534       int i;
1535       scaling = strlen(name+start) / 3;
1536       for (i = 0; i < 3; i++)
1537         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1538                  name + start + i * scaling);
1539       hex[3 * (scaling + 1) - 1] = '\0';
1540     }
1542   if (hex[0])
1543     {
1544       int rr, gg, bb;
1545       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1546       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1547         {
1548           r = rr / fscale;
1549           g = gg / fscale;
1550           b = bb / fscale;
1551         }
1552     }
1554   if (r >= 0.0F)
1555     {
1556       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1557       unblock_input ();
1558       return 0;
1559     }
1561   /* Otherwise, color is expected to be from a list */
1562   {
1563     NSEnumerator *lenum, *cenum;
1564     NSString *name;
1565     NSColorList *clist;
1567 #ifdef NS_IMPL_GNUSTEP
1568     /* XXX: who is wrong, the requestor or the implementation? */
1569     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1570         == NSOrderedSame)
1571       nsname = @"highlightColor";
1572 #endif
1574     lenum = [[NSColorList availableColorLists] objectEnumerator];
1575     while ( (clist = [lenum nextObject]) && new == nil)
1576       {
1577         cenum = [[clist allKeys] objectEnumerator];
1578         while ( (name = [cenum nextObject]) && new == nil )
1579           {
1580             if ([name compare: nsname
1581                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1582               new = [clist colorWithKey: name];
1583           }
1584       }
1585   }
1587   if (new)
1588     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1589   unblock_input ();
1590   return new ? 0 : 1;
1595 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1596 /* --------------------------------------------------------------------------
1597      Convert a Lisp string object to a NS color
1598    -------------------------------------------------------------------------- */
1600   NSTRACE (ns_lisp_to_color);
1601   if (STRINGP (color))
1602     return ns_get_color (SSDATA (color), col);
1603   else if (SYMBOLP (color))
1604     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1605   return 1;
1609 Lisp_Object
1610 ns_color_to_lisp (NSColor *col)
1611 /* --------------------------------------------------------------------------
1612      Convert a color to a lisp string with the RGB equivalent
1613    -------------------------------------------------------------------------- */
1615   EmacsCGFloat red, green, blue, alpha, gray;
1616   char buf[1024];
1617   const char *str;
1618   NSTRACE (ns_color_to_lisp);
1620   block_input ();
1621   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1623       if ((str =[[col colorNameComponent] UTF8String]))
1624         {
1625           unblock_input ();
1626           return build_string ((char *)str);
1627         }
1629     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1630         getRed: &red green: &green blue: &blue alpha: &alpha];
1631   if (red ==green && red ==blue)
1632     {
1633       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1634             getWhite: &gray alpha: &alpha];
1635       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1636                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1637       unblock_input ();
1638       return build_string (buf);
1639     }
1641   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1642             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1644   unblock_input ();
1645   return build_string (buf);
1649 void
1650 ns_query_color(void *col, XColor *color_def, int setPixel)
1651 /* --------------------------------------------------------------------------
1652          Get ARGB values out of NSColor col and put them into color_def.
1653          If setPixel, set the pixel to a concatenated version.
1654          and set color_def pixel to the resulting index.
1655    -------------------------------------------------------------------------- */
1657   EmacsCGFloat r, g, b, a;
1659   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1660   color_def->red   = r * 65535;
1661   color_def->green = g * 65535;
1662   color_def->blue  = b * 65535;
1664   if (setPixel == YES)
1665     color_def->pixel
1666       = ARGB_TO_ULONG((int)(a*255),
1667                       (int)(r*255), (int)(g*255), (int)(b*255));
1671 bool
1672 ns_defined_color (struct frame *f,
1673                   const char *name,
1674                   XColor *color_def,
1675                   bool alloc,
1676                   bool makeIndex)
1677 /* --------------------------------------------------------------------------
1678          Return true if named color found, and set color_def rgb accordingly.
1679          If makeIndex and alloc are nonzero put the color in the color_table,
1680          and set color_def pixel to the resulting index.
1681          If makeIndex is zero, set color_def pixel to ARGB.
1682          Return false if not found
1683    -------------------------------------------------------------------------- */
1685   NSColor *col;
1686   NSTRACE (ns_defined_color);
1688   block_input ();
1689   if (ns_get_color (name, &col) != 0) /* Color not found  */
1690     {
1691       unblock_input ();
1692       return 0;
1693     }
1694   if (makeIndex && alloc)
1695     color_def->pixel = ns_index_color (col, f);
1696   ns_query_color (col, color_def, !makeIndex);
1697   unblock_input ();
1698   return 1;
1702 void
1703 x_set_frame_alpha (struct frame *f)
1704 /* --------------------------------------------------------------------------
1705      change the entire-frame transparency
1706    -------------------------------------------------------------------------- */
1708   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1709   double alpha = 1.0;
1710   double alpha_min = 1.0;
1712   if (dpyinfo->x_highlight_frame == f)
1713     alpha = f->alpha[0];
1714   else
1715     alpha = f->alpha[1];
1717   if (FLOATP (Vframe_alpha_lower_limit))
1718     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1719   else if (INTEGERP (Vframe_alpha_lower_limit))
1720     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1722   if (alpha < 0.0)
1723     return;
1724   else if (1.0 < alpha)
1725     alpha = 1.0;
1726   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1727     alpha = alpha_min;
1729 #ifdef NS_IMPL_COCOA
1730   {
1731     EmacsView *view = FRAME_NS_VIEW (f);
1732   [[view window] setAlphaValue: alpha];
1733   }
1734 #endif
1738 /* ==========================================================================
1740     Mouse handling
1742    ========================================================================== */
1745 void
1746 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1747 /* --------------------------------------------------------------------------
1748      Programmatically reposition mouse pointer in pixel coordinates
1749    -------------------------------------------------------------------------- */
1751   NSTRACE (x_set_mouse_pixel_position);
1752   ns_raise_frame (f);
1753 #if 0
1754   /* FIXME: this does not work, and what about GNUstep? */
1755 #ifdef NS_IMPL_COCOA
1756   [FRAME_NS_VIEW (f) lockFocus];
1757   PSsetmouse ((float)pix_x, (float)pix_y);
1758   [FRAME_NS_VIEW (f) unlockFocus];
1759 #endif
1760 #endif
1764 void
1765 x_set_mouse_position (struct frame *f, int h, int v)
1766 /* --------------------------------------------------------------------------
1767      Programmatically reposition mouse pointer in character coordinates
1768    -------------------------------------------------------------------------- */
1770   int pix_x, pix_y;
1772   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1773   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1775   if (pix_x < 0) pix_x = 0;
1776   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1778   if (pix_y < 0) pix_y = 0;
1779   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1781   x_set_mouse_pixel_position (f, pix_x, pix_y);
1785 static int
1786 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1787 /*   ------------------------------------------------------------------------
1788      Called by EmacsView on mouseMovement events.  Passes on
1789      to emacs mainstream code if we moved off of a rect of interest
1790      known as last_mouse_glyph.
1791      ------------------------------------------------------------------------ */
1793   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1794   NSRect *r;
1796 //  NSTRACE (note_mouse_movement);
1798   dpyinfo->last_mouse_motion_frame = frame;
1799   r = &dpyinfo->last_mouse_glyph;
1801   /* Note, this doesn't get called for enter/leave, since we don't have a
1802      position.  Those are taken care of in the corresponding NSView methods. */
1804   /* has movement gone beyond last rect we were tracking? */
1805   if (x < r->origin.x || x >= r->origin.x + r->size.width
1806       || y < r->origin.y || y >= r->origin.y + r->size.height)
1807     {
1808       ns_update_begin (frame);
1809       frame->mouse_moved = 1;
1810       note_mouse_highlight (frame, x, y);
1811       remember_mouse_glyph (frame, x, y, r);
1812       ns_update_end (frame);
1813       return 1;
1814     }
1816   return 0;
1820 static void
1821 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1822                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1823                    Time *time)
1824 /* --------------------------------------------------------------------------
1825     External (hook): inform emacs about mouse position and hit parts.
1826     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1827     x & y should be position in the scrollbar (the whole bar, not the handle)
1828     and length of scrollbar respectively
1829    -------------------------------------------------------------------------- */
1831   id view;
1832   NSPoint position;
1833   Lisp_Object frame, tail;
1834   struct frame *f;
1835   struct ns_display_info *dpyinfo;
1837   NSTRACE (ns_mouse_position);
1839   if (*fp == NULL)
1840     {
1841       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1842       return;
1843     }
1845   dpyinfo = FRAME_DISPLAY_INFO (*fp);
1847   block_input ();
1849   if (dpyinfo->last_mouse_scroll_bar != nil && insist == 0)
1850     {
1851       /* TODO: we do not use this path at the moment because drag events will
1852            go directly to the EmacsScroller.  Leaving code in for now. */
1853       [dpyinfo->last_mouse_scroll_bar
1854           getMouseMotionPart: (int *)part window: bar_window x: x y: y];
1855       if (time)
1856         *time = dpyinfo->last_mouse_movement_time;
1857       dpyinfo->last_mouse_scroll_bar = nil;
1858     }
1859   else
1860     {
1861       /* Clear the mouse-moved flag for every frame on this display.  */
1862       FOR_EACH_FRAME (tail, frame)
1863         if (FRAME_NS_P (XFRAME (frame))
1864             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1865           XFRAME (frame)->mouse_moved = 0;
1867       dpyinfo->last_mouse_scroll_bar = nil;
1868       if (dpyinfo->last_mouse_frame
1869           && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
1870         f = dpyinfo->last_mouse_frame;
1871       else
1872         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1873                                     : SELECTED_FRAME ();
1875       if (f && FRAME_NS_P (f))
1876         {
1877           view = FRAME_NS_VIEW (*fp);
1879           position = [[view window] mouseLocationOutsideOfEventStream];
1880           position = [view convertPoint: position fromView: nil];
1881           remember_mouse_glyph (f, position.x, position.y,
1882                                 &dpyinfo->last_mouse_glyph);
1883 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1885           if (bar_window) *bar_window = Qnil;
1886           if (part) *part = 0; /*scroll_bar_handle; */
1888           if (x) XSETINT (*x, lrint (position.x));
1889           if (y) XSETINT (*y, lrint (position.y));
1890           if (time)
1891             *time = dpyinfo->last_mouse_movement_time;
1892           *fp = f;
1893         }
1894     }
1896   unblock_input ();
1900 static void
1901 ns_frame_up_to_date (struct frame *f)
1902 /* --------------------------------------------------------------------------
1903     External (hook): Fix up mouse highlighting right after a full update.
1904     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1905    -------------------------------------------------------------------------- */
1907   NSTRACE (ns_frame_up_to_date);
1909   if (FRAME_NS_P (f))
1910     {
1911       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1912       if (f == hlinfo->mouse_face_mouse_frame)
1913         {
1914           block_input ();
1915           ns_update_begin(f);
1916           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1917                                 hlinfo->mouse_face_mouse_x,
1918                                 hlinfo->mouse_face_mouse_y);
1919           ns_update_end(f);
1920           unblock_input ();
1921         }
1922     }
1926 static void
1927 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1928 /* --------------------------------------------------------------------------
1929     External (RIF): set frame mouse pointer type.
1930    -------------------------------------------------------------------------- */
1932   NSTRACE (ns_define_frame_cursor);
1933   if (FRAME_POINTER_TYPE (f) != cursor)
1934     {
1935       EmacsView *view = FRAME_NS_VIEW (f);
1936       FRAME_POINTER_TYPE (f) = cursor;
1937       [[view window] invalidateCursorRectsForView: view];
1938       /* Redisplay assumes this function also draws the changed frame
1939          cursor, but this function doesn't, so do it explicitly.  */
1940       x_update_cursor (f, 1);
1941     }
1946 /* ==========================================================================
1948     Keyboard handling
1950    ========================================================================== */
1953 static unsigned
1954 ns_convert_key (unsigned code)
1955 /* --------------------------------------------------------------------------
1956     Internal call used by NSView-keyDown.
1957    -------------------------------------------------------------------------- */
1959   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1960                                 / sizeof (convert_ns_to_X_keysym[0]));
1961   unsigned keysym;
1962   /* An array would be faster, but less easy to read. */
1963   for (keysym = 0; keysym < last_keysym; keysym += 2)
1964     if (code == convert_ns_to_X_keysym[keysym])
1965       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1966   return 0;
1967 /* if decide to use keyCode and Carbon table, use this line:
1968      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1972 char *
1973 x_get_keysym_name (int keysym)
1974 /* --------------------------------------------------------------------------
1975     Called by keyboard.c.  Not sure if the return val is important, except
1976     that it be unique.
1977    -------------------------------------------------------------------------- */
1979   static char value[16];
1980   NSTRACE (x_get_keysym_name);
1981   sprintf (value, "%d", keysym);
1982   return value;
1987 /* ==========================================================================
1989     Block drawing operations
1991    ========================================================================== */
1994 static void
1995 ns_redraw_scroll_bars (struct frame *f)
1997   int i;
1998   id view;
1999   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2000   NSTRACE (ns_redraw_scroll_bars);
2001   for (i =[subviews count]-1; i >= 0; i--)
2002     {
2003       view = [subviews objectAtIndex: i];
2004       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2005       [view display];
2006     }
2010 void
2011 ns_clear_frame (struct frame *f)
2012 /* --------------------------------------------------------------------------
2013       External (hook): Erase the entire frame
2014    -------------------------------------------------------------------------- */
2016   NSView *view = FRAME_NS_VIEW (f);
2017   NSRect r;
2019   NSTRACE (ns_clear_frame);
2021  /* comes on initial frame because we have
2022     after-make-frame-functions = select-frame */
2023  if (!FRAME_DEFAULT_FACE (f))
2024    return;
2026   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2028   r = [view bounds];
2030   block_input ();
2031   ns_focus (f, &r, 1);
2032   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2033   NSRectFill (r);
2034   ns_unfocus (f);
2036   /* as of 2006/11 or so this is now needed */
2037   ns_redraw_scroll_bars (f);
2038   unblock_input ();
2042 static void
2043 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2044 /* --------------------------------------------------------------------------
2045     External (RIF):  Clear section of frame
2046    -------------------------------------------------------------------------- */
2048   NSRect r = NSMakeRect (x, y, width, height);
2049   NSView *view = FRAME_NS_VIEW (f);
2050   struct face *face = FRAME_DEFAULT_FACE (f);
2052   if (!view || !face)
2053     return;
2055   NSTRACE (ns_clear_frame_area);
2057   r = NSIntersectionRect (r, [view frame]);
2058   ns_focus (f, &r, 1);
2059   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2061   NSRectFill (r);
2063   ns_unfocus (f);
2064   return;
2068 static void
2069 ns_scroll_run (struct window *w, struct run *run)
2070 /* --------------------------------------------------------------------------
2071     External (RIF):  Insert or delete n lines at line vpos
2072    -------------------------------------------------------------------------- */
2074   struct frame *f = XFRAME (w->frame);
2075   int x, y, width, height, from_y, to_y, bottom_y;
2077   NSTRACE (ns_scroll_run);
2079   /* begin copy from other terms */
2080   /* Get frame-relative bounding box of the text display area of W,
2081      without mode lines.  Include in this box the left and right
2082      fringe of W.  */
2083   window_box (w, ANY_AREA, &x, &y, &width, &height);
2085   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2086   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2087   bottom_y = y + height;
2089   if (to_y < from_y)
2090     {
2091       /* Scrolling up.  Make sure we don't copy part of the mode
2092          line at the bottom.  */
2093       if (from_y + run->height > bottom_y)
2094         height = bottom_y - from_y;
2095       else
2096         height = run->height;
2097     }
2098   else
2099     {
2100       /* Scrolling down.  Make sure we don't copy over the mode line.
2101          at the bottom.  */
2102       if (to_y + run->height > bottom_y)
2103         height = bottom_y - to_y;
2104       else
2105         height = run->height;
2106     }
2107   /* end copy from other terms */
2109   if (height == 0)
2110       return;
2112   block_input ();
2114   x_clear_cursor (w);
2116   {
2117     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2118     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2119     NSPoint dstOrigin = NSMakePoint (x, to_y);
2121     ns_focus (f, &dstRect, 1);
2122     NSCopyBits (0, srcRect , dstOrigin);
2123     ns_unfocus (f);
2124   }
2126   unblock_input ();
2130 static void
2131 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2132 /* --------------------------------------------------------------------------
2133     External (RIF): preparatory to fringe update after text was updated
2134    -------------------------------------------------------------------------- */
2136   struct frame *f;
2137   int width, height;
2139   NSTRACE (ns_after_update_window_line);
2141   /* begin copy from other terms */
2142   eassert (w);
2144   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2145     desired_row->redraw_fringe_bitmaps_p = 1;
2147   /* When a window has disappeared, make sure that no rest of
2148      full-width rows stays visible in the internal border.  */
2149   if (windows_or_buffers_changed
2150       && desired_row->full_width_p
2151       && (f = XFRAME (w->frame),
2152           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2153           width != 0)
2154       && (height = desired_row->visible_height,
2155           height > 0))
2156     {
2157       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2159       block_input ();
2160       ns_clear_frame_area (f, 0, y, width, height);
2161       ns_clear_frame_area (f,
2162                            FRAME_PIXEL_WIDTH (f) - width,
2163                            y, width, height);
2164       unblock_input ();
2165     }
2169 static void
2170 ns_shift_glyphs_for_insert (struct frame *f,
2171                            int x, int y, int width, int height,
2172                            int shift_by)
2173 /* --------------------------------------------------------------------------
2174     External (RIF): copy an area horizontally, don't worry about clearing src
2175    -------------------------------------------------------------------------- */
2177   NSRect srcRect = NSMakeRect (x, y, width, height);
2178   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2179   NSPoint dstOrigin = dstRect.origin;
2181   NSTRACE (ns_shift_glyphs_for_insert);
2183   ns_focus (f, &dstRect, 1);
2184   NSCopyBits (0, srcRect, dstOrigin);
2185   ns_unfocus (f);
2190 /* ==========================================================================
2192     Character encoding and metrics
2194    ========================================================================== */
2197 static void
2198 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2199 /* --------------------------------------------------------------------------
2200      External (RIF); compute left/right overhang of whole string and set in s
2201    -------------------------------------------------------------------------- */
2203   struct font *font = s->font;
2205   if (s->char2b)
2206     {
2207       struct font_metrics metrics;
2208       unsigned int codes[2];
2209       codes[0] = *(s->char2b);
2210       codes[1] = *(s->char2b + s->nchars - 1);
2212       font->driver->text_extents (font, codes, 2, &metrics);
2213       s->left_overhang = -metrics.lbearing;
2214       s->right_overhang
2215         = metrics.rbearing > metrics.width
2216         ? metrics.rbearing - metrics.width : 0;
2217     }
2218   else
2219     {
2220       s->left_overhang = 0;
2221       if (EQ (font->driver->type, Qns))
2222         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2223           FONT_HEIGHT (font) * 0.2 : 0;
2224       else
2225         s->right_overhang = 0;
2226     }
2231 /* ==========================================================================
2233     Fringe and cursor drawing
2235    ========================================================================== */
2238 extern int max_used_fringe_bitmap;
2239 static void
2240 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2241                       struct draw_fringe_bitmap_params *p)
2242 /* --------------------------------------------------------------------------
2243     External (RIF); fringe-related
2244    -------------------------------------------------------------------------- */
2246   struct frame *f = XFRAME (WINDOW_FRAME (w));
2247   struct face *face = p->face;
2248   static EmacsImage **bimgs = NULL;
2249   static int nBimgs = 0;
2251   /* grow bimgs if needed */
2252   if (nBimgs < max_used_fringe_bitmap)
2253     {
2254       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2255       memset (bimgs + nBimgs, 0,
2256               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2257       nBimgs = max_used_fringe_bitmap;
2258     }
2260   /* Must clip because of partially visible lines.  */
2261   ns_clip_to_row (w, row, ANY_AREA, YES);
2263   if (!p->overlay_p)
2264     {
2265       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2267       /* If the fringe is adjacent to the left (right) scroll bar of a
2268          leftmost (rightmost, respectively) window, then extend its
2269          background to the gap between the fringe and the bar.  */
2270       if ((WINDOW_LEFTMOST_P (w)
2271            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2272           || (WINDOW_RIGHTMOST_P (w)
2273               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2274         {
2275           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2277           if (sb_width > 0)
2278             {
2279               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2280               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2281                                     * FRAME_COLUMN_WIDTH (f));
2283               if (bx < 0)
2284                 {
2285                   /* Bitmap fills the fringe.  */
2286                   if (bar_area_x + bar_area_width == p->x)
2287                     bx = bar_area_x + sb_width;
2288                   else if (p->x + p->wd == bar_area_x)
2289                     bx = bar_area_x;
2290                   if (bx >= 0)
2291                     {
2292                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2294                       nx = bar_area_width - sb_width;
2295                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2296                                                             row->y));
2297                       ny = row->visible_height;
2298                     }
2299                 }
2300               else
2301                 {
2302                   if (bar_area_x + bar_area_width == bx)
2303                     {
2304                       bx = bar_area_x + sb_width;
2305                       nx += bar_area_width - sb_width;
2306                     }
2307                   else if (bx + nx == bar_area_x)
2308                     nx += bar_area_width - sb_width;
2309                 }
2310             }
2311         }
2313       if (bx >= 0 && nx > 0)
2314         {
2315           NSRect r = NSMakeRect (bx, by, nx, ny);
2316           NSRectClip (r);
2317           [ns_lookup_indexed_color (face->background, f) set];
2318           NSRectFill (r);
2319         }
2320     }
2322   if (p->which)
2323     {
2324       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2325       EmacsImage *img = bimgs[p->which - 1];
2327       if (!img)
2328         {
2329           unsigned short *bits = p->bits + p->dh;
2330           int len = p->h;
2331           int i;
2332           unsigned char *cbits = xmalloc (len);
2334           for (i = 0; i < len; i++)
2335             cbits[i] = ~(bits[i] & 0xff);
2336           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2337                                            flip: NO];
2338           bimgs[p->which - 1] = img;
2339           xfree (cbits);
2340         }
2342       NSRectClip (r);
2343       /* Since we composite the bitmap instead of just blitting it, we need
2344          to erase the whole background. */
2345       [ns_lookup_indexed_color(face->background, f) set];
2346       NSRectFill (r);
2347       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2348 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2349       [img drawInRect: r
2350               fromRect: NSZeroRect
2351              operation: NSCompositeSourceOver
2352               fraction: 1.0
2353            respectFlipped: YES
2354                 hints: nil];
2355 #else
2356       {
2357         NSPoint pt = r.origin;
2358         pt.y += p->h;
2359         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2360       }
2361 #endif
2362     }
2363   ns_unfocus (f);
2367 static void
2368 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2369                        int x, int y, enum text_cursor_kinds cursor_type,
2370                        int cursor_width, bool on_p, bool active_p)
2371 /* --------------------------------------------------------------------------
2372      External call (RIF): draw cursor.
2373      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2374    -------------------------------------------------------------------------- */
2376   NSRect r, s;
2377   int fx, fy, h, cursor_height;
2378   struct frame *f = WINDOW_XFRAME (w);
2379   struct glyph *phys_cursor_glyph;
2380   struct glyph *cursor_glyph;
2381   struct face *face;
2382   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2384   /* If cursor is out of bounds, don't draw garbage.  This can happen
2385      in mini-buffer windows when switching between echo area glyphs
2386      and mini-buffer.  */
2388   NSTRACE (dumpcursor);
2390   if (!on_p)
2391     return;
2393   w->phys_cursor_type = cursor_type;
2394   w->phys_cursor_on_p = on_p;
2396   if (cursor_type == NO_CURSOR)
2397     {
2398       w->phys_cursor_width = 0;
2399       return;
2400     }
2402   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2403     {
2404       if (glyph_row->exact_window_width_line_p
2405           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2406         {
2407           glyph_row->cursor_in_fringe_p = 1;
2408           draw_fringe_bitmap (w, glyph_row, 0);
2409         }
2410       return;
2411     }
2413   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2414      (other terminals do it the other way round).  We must set
2415      w->phys_cursor_width to the cursor width.  For bar cursors, that
2416      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2417   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2419   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2420      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2421   if (cursor_type == BAR_CURSOR)
2422     {
2423       if (cursor_width < 1)
2424         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2425       w->phys_cursor_width = cursor_width;
2426     }
2427   /* If we have an HBAR, "cursor_width" MAY specify height. */
2428   else if (cursor_type == HBAR_CURSOR)
2429     {
2430       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2431       fy += h - cursor_height;
2432       h = cursor_height;
2433     }
2435   r.origin.x = fx, r.origin.y = fy;
2436   r.size.height = h;
2437   r.size.width = w->phys_cursor_width;
2439   /* TODO: only needed in rare cases with last-resort font in HELLO..
2440      should we do this more efficiently? */
2441   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2444   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2445   if (face && NS_FACE_BACKGROUND (face)
2446       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2447     {
2448       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2449       hollow_color = FRAME_CURSOR_COLOR (f);
2450     }
2451   else
2452     [FRAME_CURSOR_COLOR (f) set];
2454 #ifdef NS_IMPL_COCOA
2455   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2456            atomic.  Cleaner ways of doing this should be investigated.
2457            One way would be to set a global variable DRAWING_CURSOR
2458            when making the call to draw_phys..(), don't focus in that
2459            case, then move the ns_unfocus() here after that call. */
2460   NSDisableScreenUpdates ();
2461 #endif
2463   switch (cursor_type)
2464     {
2465     case NO_CURSOR:
2466       break;
2467     case FILLED_BOX_CURSOR:
2468       NSRectFill (r);
2469       break;
2470     case HOLLOW_BOX_CURSOR:
2471       NSRectFill (r);
2472       [hollow_color set];
2473       NSRectFill (NSInsetRect (r, 1, 1));
2474       [FRAME_CURSOR_COLOR (f) set];
2475       break;
2476     case HBAR_CURSOR:
2477       NSRectFill (r);
2478       break;
2479     case BAR_CURSOR:
2480       s = r;
2481       /* If the character under cursor is R2L, draw the bar cursor
2482          on the right of its glyph, rather than on the left.  */
2483       cursor_glyph = get_phys_cursor_glyph (w);
2484       if ((cursor_glyph->resolved_level & 1) != 0)
2485         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2487       NSRectFill (s);
2488       break;
2489     }
2490   ns_unfocus (f);
2492   /* draw the character under the cursor */
2493   if (cursor_type != NO_CURSOR)
2494     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2496 #ifdef NS_IMPL_COCOA
2497   NSEnableScreenUpdates ();
2498 #endif
2503 static void
2504 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2505 /* --------------------------------------------------------------------------
2506      External (RIF): Draw a vertical line.
2507    -------------------------------------------------------------------------- */
2509   struct frame *f = XFRAME (WINDOW_FRAME (w));
2510   struct face *face;
2511   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2513   NSTRACE (ns_draw_vertical_window_border);
2515   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2516   if (face)
2517       [ns_lookup_indexed_color(face->foreground, f) set];
2519   ns_focus (f, &r, 1);
2520   NSRectFill(r);
2521   ns_unfocus (f);
2525 static void
2526 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2527 /* --------------------------------------------------------------------------
2528      External (RIF): Draw a window divider.
2529    -------------------------------------------------------------------------- */
2531   struct frame *f = XFRAME (WINDOW_FRAME (w));
2532   struct face *face;
2533   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2535   NSTRACE (ns_draw_window_divider);
2537   face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2538   if (face)
2539       [ns_lookup_indexed_color(face->foreground, f) set];
2541   ns_focus (f, &r, 1);
2542   NSRectFill(r);
2543   ns_unfocus (f);
2547 void
2548 show_hourglass (struct atimer *timer)
2550   if (hourglass_shown_p)
2551     return;
2553   block_input ();
2555   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2557   hourglass_shown_p = 1;
2558   unblock_input ();
2562 void
2563 hide_hourglass (void)
2565   if (!hourglass_shown_p)
2566     return;
2568   block_input ();
2570   /* TODO: remove NSProgressIndicator from all frames */
2572   hourglass_shown_p = 0;
2573   unblock_input ();
2578 /* ==========================================================================
2580     Glyph drawing operations
2582    ========================================================================== */
2584 static int
2585 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2586 /* --------------------------------------------------------------------------
2587     Wrapper utility to account for internal border width on full-width lines,
2588     and allow top full-width rows to hit the frame top.  nr should be pointer
2589     to two successive NSRects.  Number of rects actually used is returned.
2590    -------------------------------------------------------------------------- */
2592   int n = get_glyph_string_clip_rects (s, nr, 2);
2593   return n;
2596 /* --------------------------------------------------------------------
2597    Draw a wavy line under glyph string s. The wave fills wave_height
2598    pixels from y.
2600                     x          wave_length = 2
2601                                  --
2602                 y    *   *   *   *   *
2603                      |* * * * * * * * *
2604     wave_height = 3  | *   *   *   *
2605   --------------------------------------------------------------------- */
2607 static void
2608 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2610   int wave_height = 3, wave_length = 2;
2611   int y, dx, dy, odd, xmax;
2612   NSPoint a, b;
2613   NSRect waveClip;
2615   dx = wave_length;
2616   dy = wave_height - 1;
2617   y =  s->ybase - wave_height + 3;
2618   xmax = x + width;
2620   /* Find and set clipping rectangle */
2621   waveClip = NSMakeRect (x, y, width, wave_height);
2622   [[NSGraphicsContext currentContext] saveGraphicsState];
2623   NSRectClip (waveClip);
2625   /* Draw the waves */
2626   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2627   b.x = a.x + dx;
2628   odd = (int)(a.x/dx) % 2;
2629   a.y = b.y = y + 0.5;
2631   if (odd)
2632     a.y += dy;
2633   else
2634     b.y += dy;
2636   while (a.x <= xmax)
2637     {
2638       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2639       a.x = b.x, a.y = b.y;
2640       b.x += dx, b.y = y + 0.5 + odd*dy;
2641       odd = !odd;
2642     }
2644   /* Restore previous clipping rectangle(s) */
2645   [[NSGraphicsContext currentContext] restoreGraphicsState];
2650 void
2651 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2652                          NSColor *defaultCol, CGFloat width, CGFloat x)
2653 /* --------------------------------------------------------------------------
2654    Draw underline, overline, and strike-through on glyph string s.
2655    -------------------------------------------------------------------------- */
2657   if (s->for_overlaps)
2658     return;
2660   /* Do underline. */
2661   if (face->underline_p)
2662     {
2663       if (s->face->underline_type == FACE_UNDER_WAVE)
2664         {
2665           if (face->underline_defaulted_p)
2666             [defaultCol set];
2667           else
2668             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2670           ns_draw_underwave (s, width, x);
2671         }
2672       else if (s->face->underline_type == FACE_UNDER_LINE)
2673         {
2675           NSRect r;
2676           unsigned long thickness, position;
2678           /* If the prev was underlined, match its appearance. */
2679           if (s->prev && s->prev->face->underline_p
2680               && s->prev->face->underline_type == FACE_UNDER_LINE
2681               && s->prev->underline_thickness > 0)
2682             {
2683               thickness = s->prev->underline_thickness;
2684               position = s->prev->underline_position;
2685             }
2686           else
2687             {
2688               struct font *font;
2689               unsigned long descent;
2691               font=s->font;
2692               descent = s->y + s->height - s->ybase;
2694               /* Use underline thickness of font, defaulting to 1. */
2695               thickness = (font && font->underline_thickness > 0)
2696                 ? font->underline_thickness : 1;
2698               /* Determine the offset of underlining from the baseline. */
2699               if (x_underline_at_descent_line)
2700                 position = descent - thickness;
2701               else if (x_use_underline_position_properties
2702                        && font && font->underline_position >= 0)
2703                 position = font->underline_position;
2704               else if (font)
2705                 position = lround (font->descent / 2);
2706               else
2707                 position = underline_minimum_offset;
2709               position = max (position, underline_minimum_offset);
2711               /* Ensure underlining is not cropped. */
2712               if (descent <= position)
2713                 {
2714                   position = descent - 1;
2715                   thickness = 1;
2716                 }
2717               else if (descent < position + thickness)
2718                 thickness = 1;
2719             }
2721           s->underline_thickness = thickness;
2722           s->underline_position = position;
2724           r = NSMakeRect (x, s->ybase + position, width, thickness);
2726           if (face->underline_defaulted_p)
2727             [defaultCol set];
2728           else
2729             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2730           NSRectFill (r);
2731         }
2732     }
2733   /* Do overline. We follow other terms in using a thickness of 1
2734      and ignoring overline_margin. */
2735   if (face->overline_p)
2736     {
2737       NSRect r;
2738       r = NSMakeRect (x, s->y, width, 1);
2740       if (face->overline_color_defaulted_p)
2741         [defaultCol set];
2742       else
2743         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2744       NSRectFill (r);
2745     }
2747   /* Do strike-through.  We follow other terms for thickness and
2748      vertical position.*/
2749   if (face->strike_through_p)
2750     {
2751       NSRect r;
2752       unsigned long dy;
2754       dy = lrint ((s->height - 1) / 2);
2755       r = NSMakeRect (x, s->y + dy, width, 1);
2757       if (face->strike_through_color_defaulted_p)
2758         [defaultCol set];
2759       else
2760         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2761       NSRectFill (r);
2762     }
2765 static void
2766 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2767              char left_p, char right_p)
2768 /* --------------------------------------------------------------------------
2769     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2770     Note we can't just use an NSDrawRect command, because of the possibility
2771     of some sides not being drawn, and because the rect will be filled.
2772    -------------------------------------------------------------------------- */
2774   NSRect s = r;
2775   [col set];
2777   /* top, bottom */
2778   s.size.height = thickness;
2779   NSRectFill (s);
2780   s.origin.y += r.size.height - thickness;
2781   NSRectFill (s);
2783   s.size.height = r.size.height;
2784   s.origin.y = r.origin.y;
2786   /* left, right (optional) */
2787   s.size.width = thickness;
2788   if (left_p)
2789     NSRectFill (s);
2790   if (right_p)
2791     {
2792       s.origin.x += r.size.width - thickness;
2793       NSRectFill (s);
2794     }
2798 static void
2799 ns_draw_relief (NSRect r, int thickness, char raised_p,
2800                char top_p, char bottom_p, char left_p, char right_p,
2801                struct glyph_string *s)
2802 /* --------------------------------------------------------------------------
2803     Draw a relief rect inside r, optionally leaving some sides open.
2804     Note we can't just use an NSDrawBezel command, because of the possibility
2805     of some sides not being drawn, and because the rect will be filled.
2806    -------------------------------------------------------------------------- */
2808   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2809   NSColor *newBaseCol = nil;
2810   NSRect sr = r;
2812   NSTRACE (ns_draw_relief);
2814   /* set up colors */
2816   if (s->face->use_box_color_for_shadows_p)
2817     {
2818       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2819     }
2820 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2821            && s->img->pixmap
2822            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2823        {
2824          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2825        } */
2826   else
2827     {
2828       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2829     }
2831   if (newBaseCol == nil)
2832     newBaseCol = [NSColor grayColor];
2834   if (newBaseCol != baseCol)  /* TODO: better check */
2835     {
2836       [baseCol release];
2837       baseCol = [newBaseCol retain];
2838       [lightCol release];
2839       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2840       [darkCol release];
2841       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2842     }
2844   [(raised_p ? lightCol : darkCol) set];
2846   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2848   /* top */
2849   sr.size.height = thickness;
2850   if (top_p) NSRectFill (sr);
2852   /* left */
2853   sr.size.height = r.size.height;
2854   sr.size.width = thickness;
2855   if (left_p) NSRectFill (sr);
2857   [(raised_p ? darkCol : lightCol) set];
2859   /* bottom */
2860   sr.size.width = r.size.width;
2861   sr.size.height = thickness;
2862   sr.origin.y += r.size.height - thickness;
2863   if (bottom_p) NSRectFill (sr);
2865   /* right */
2866   sr.size.height = r.size.height;
2867   sr.origin.y = r.origin.y;
2868   sr.size.width = thickness;
2869   sr.origin.x += r.size.width - thickness;
2870   if (right_p) NSRectFill (sr);
2874 static void
2875 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2876 /* --------------------------------------------------------------------------
2877       Function modeled after x_draw_glyph_string_box ().
2878       Sets up parameters for drawing.
2879    -------------------------------------------------------------------------- */
2881   int right_x, last_x;
2882   char left_p, right_p;
2883   struct glyph *last_glyph;
2884   NSRect r;
2885   int thickness;
2886   struct face *face;
2888   if (s->hl == DRAW_MOUSE_FACE)
2889     {
2890       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2891       if (!face)
2892         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2893     }
2894   else
2895     face = s->face;
2897   thickness = face->box_line_width;
2899   NSTRACE (ns_dumpglyphs_box_or_relief);
2901   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2902             ? WINDOW_RIGHT_EDGE_X (s->w)
2903             : window_box_right (s->w, s->area));
2904   last_glyph = (s->cmp || s->img
2905                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2907   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2908               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2910   left_p = (s->first_glyph->left_box_line_p
2911             || (s->hl == DRAW_MOUSE_FACE
2912                 && (s->prev == NULL || s->prev->hl != s->hl)));
2913   right_p = (last_glyph->right_box_line_p
2914              || (s->hl == DRAW_MOUSE_FACE
2915                  && (s->next == NULL || s->next->hl != s->hl)));
2917   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2919   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2920   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2921     {
2922       ns_draw_box (r, abs (thickness),
2923                    ns_lookup_indexed_color (face->box_color, s->f),
2924                   left_p, right_p);
2925     }
2926   else
2927     {
2928       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2929                      1, 1, left_p, right_p, s);
2930     }
2934 static void
2935 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2936 /* --------------------------------------------------------------------------
2937       Modeled after x_draw_glyph_string_background, which draws BG in
2938       certain cases.  Others are left to the text rendering routine.
2939    -------------------------------------------------------------------------- */
2941   NSTRACE (ns_maybe_dumpglyphs_background);
2943   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2944     {
2945       int box_line_width = max (s->face->box_line_width, 0);
2946       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2947           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2948         {
2949           struct face *face;
2950           if (s->hl == DRAW_MOUSE_FACE)
2951             {
2952               face = FACE_FROM_ID (s->f,
2953                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2954               if (!face)
2955                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2956             }
2957           else
2958             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2959           if (!face->stipple)
2960             [(NS_FACE_BACKGROUND (face) != 0
2961               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2962               : FRAME_BACKGROUND_COLOR (s->f)) set];
2963           else
2964             {
2965               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
2966               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2967             }
2969           if (s->hl != DRAW_CURSOR)
2970             {
2971               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2972                                     s->background_width,
2973                                     s->height-2*box_line_width);
2974               NSRectFill (r);
2975             }
2977           s->background_filled_p = 1;
2978         }
2979     }
2983 static void
2984 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2985 /* --------------------------------------------------------------------------
2986       Renders an image and associated borders.
2987    -------------------------------------------------------------------------- */
2989   EmacsImage *img = s->img->pixmap;
2990   int box_line_vwidth = max (s->face->box_line_width, 0);
2991   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2992   int bg_x, bg_y, bg_height;
2993   int th;
2994   char raised_p;
2995   NSRect br;
2996   struct face *face;
2997   NSColor *tdCol;
2999   NSTRACE (ns_dumpglyphs_image);
3001   if (s->face->box != FACE_NO_BOX
3002       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3003     x += abs (s->face->box_line_width);
3005   bg_x = x;
3006   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3007   bg_height = s->height;
3008   /* other terms have this, but was causing problems w/tabbar mode */
3009   /* - 2 * box_line_vwidth; */
3011   if (s->slice.x == 0) x += s->img->hmargin;
3012   if (s->slice.y == 0) y += s->img->vmargin;
3014   /* Draw BG: if we need larger area than image itself cleared, do that,
3015      otherwise, since we composite the image under NS (instead of mucking
3016      with its background color), we must clear just the image area. */
3017   if (s->hl == DRAW_MOUSE_FACE)
3018     {
3019       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3020       if (!face)
3021        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3022     }
3023   else
3024     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3026   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3028   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3029       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3030     {
3031       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3032       s->background_filled_p = 1;
3033     }
3034   else
3035     {
3036       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3037     }
3039   NSRectFill (br);
3041   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3042   if (img != nil)
3043     {
3044 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
3045       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3046       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3047                               s->slice.width, s->slice.height);
3048       [img drawInRect: dr
3049              fromRect: ir
3050              operation: NSCompositeSourceOver
3051               fraction: 1.0
3052            respectFlipped: YES
3053                 hints: nil];
3054 #else
3055       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3056                   operation: NSCompositeSourceOver];
3057 #endif
3058     }
3060   if (s->hl == DRAW_CURSOR)
3061     {
3062     [FRAME_CURSOR_COLOR (s->f) set];
3063     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3064       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3065     else
3066       /* Currently on NS img->mask is always 0. Since
3067          get_window_cursor_type specifies a hollow box cursor when on
3068          a non-masked image we never reach this clause. But we put it
3069          in in anticipation of better support for image masks on
3070          NS. */
3071       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3072     }
3073   else
3074     {
3075       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3076     }
3078   /* Draw underline, overline, strike-through. */
3079   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3081   /* Draw relief, if requested */
3082   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3083     {
3084       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3085         {
3086           th = tool_bar_button_relief >= 0 ?
3087             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3088           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3089         }
3090       else
3091         {
3092           th = abs (s->img->relief);
3093           raised_p = (s->img->relief > 0);
3094         }
3096       r.origin.x = x - th;
3097       r.origin.y = y - th;
3098       r.size.width = s->slice.width + 2*th-1;
3099       r.size.height = s->slice.height + 2*th-1;
3100       ns_draw_relief (r, th, raised_p,
3101                       s->slice.y == 0,
3102                       s->slice.y + s->slice.height == s->img->height,
3103                       s->slice.x == 0,
3104                       s->slice.x + s->slice.width == s->img->width, s);
3105     }
3107   /* If there is no mask, the background won't be seen,
3108      so draw a rectangle on the image for the cursor.
3109      Do this for all images, getting transparency right is not reliable.  */
3110   if (s->hl == DRAW_CURSOR)
3111     {
3112       int thickness = abs (s->img->relief);
3113       if (thickness == 0) thickness = 1;
3114       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3115     }
3119 static void
3120 ns_dumpglyphs_stretch (struct glyph_string *s)
3122   NSRect r[2];
3123   int n, i;
3124   struct face *face;
3125   NSColor *fgCol, *bgCol;
3127   if (!s->background_filled_p)
3128     {
3129       n = ns_get_glyph_string_clip_rect (s, r);
3130       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3132       ns_focus (s->f, r, n);
3134       if (s->hl == DRAW_MOUSE_FACE)
3135        {
3136          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3137          if (!face)
3138            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3139        }
3140       else
3141        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3143       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3144       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3146       for (i = 0; i < n; ++i)
3147         {
3148           if (!s->row->full_width_p)
3149             {
3150               int overrun, leftoverrun;
3152               /* truncate to avoid overwriting fringe and/or scrollbar */
3153               overrun = max (0, (s->x + s->background_width)
3154                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3155                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3156               r[i].size.width -= overrun;
3158               /* truncate to avoid overwriting to left of the window box */
3159               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3160                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3162               if (leftoverrun > 0)
3163                 {
3164                   r[i].origin.x += leftoverrun;
3165                   r[i].size.width -= leftoverrun;
3166                 }
3168               /* XXX: Try to work between problem where a stretch glyph on
3169                  a partially-visible bottom row will clear part of the
3170                  modeline, and another where list-buffers headers and similar
3171                  rows erroneously have visible_height set to 0.  Not sure
3172                  where this is coming from as other terms seem not to show. */
3173               r[i].size.height = min (s->height, s->row->visible_height);
3174             }
3176           [bgCol set];
3178           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3179              overwriting cursor (usually when cursor on a tab) */
3180           if (s->hl == DRAW_CURSOR)
3181             {
3182               CGFloat x, width;
3184               x = r[i].origin.x;
3185               width = s->w->phys_cursor_width;
3186               r[i].size.width -= width;
3187               r[i].origin.x += width;
3189               NSRectFill (r[i]);
3191               /* Draw overlining, etc. on the cursor. */
3192               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3193                 ns_draw_text_decoration (s, face, bgCol, width, x);
3194               else
3195                 ns_draw_text_decoration (s, face, fgCol, width, x);
3196             }
3197           else
3198             {
3199               NSRectFill (r[i]);
3200             }
3202           /* Draw overlining, etc. on the stretch glyph (or the part
3203              of the stretch glyph after the cursor). */
3204           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3205                                    r[i].origin.x);
3206         }
3207       ns_unfocus (s->f);
3208       s->background_filled_p = 1;
3209     }
3213 static void
3214 ns_draw_glyph_string (struct glyph_string *s)
3215 /* --------------------------------------------------------------------------
3216       External (RIF): Main draw-text call.
3217    -------------------------------------------------------------------------- */
3219   /* TODO (optimize): focus for box and contents draw */
3220   NSRect r[2];
3221   int n, flags;
3222   char box_drawn_p = 0;
3223   struct font *font = s->face->font;
3224   if (! font) font = FRAME_FONT (s->f);
3226   NSTRACE (ns_draw_glyph_string);
3228   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3229     {
3230       int width;
3231       struct glyph_string *next;
3233       for (width = 0, next = s->next;
3234            next && width < s->right_overhang;
3235            width += next->width, next = next->next)
3236         if (next->first_glyph->type != IMAGE_GLYPH)
3237           {
3238             if (next->first_glyph->type != STRETCH_GLYPH)
3239               {
3240                 n = ns_get_glyph_string_clip_rect (s->next, r);
3241                 ns_focus (s->f, r, n);
3242                 ns_maybe_dumpglyphs_background (s->next, 1);
3243                 ns_unfocus (s->f);
3244               }
3245             else
3246               {
3247                 ns_dumpglyphs_stretch (s->next);
3248               }
3249             next->num_clips = 0;
3250           }
3251     }
3253   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3254         && (s->first_glyph->type == CHAR_GLYPH
3255             || s->first_glyph->type == COMPOSITE_GLYPH))
3256     {
3257       n = ns_get_glyph_string_clip_rect (s, r);
3258       ns_focus (s->f, r, n);
3259       ns_maybe_dumpglyphs_background (s, 1);
3260       ns_dumpglyphs_box_or_relief (s);
3261       ns_unfocus (s->f);
3262       box_drawn_p = 1;
3263     }
3265   switch (s->first_glyph->type)
3266     {
3268     case IMAGE_GLYPH:
3269       n = ns_get_glyph_string_clip_rect (s, r);
3270       ns_focus (s->f, r, n);
3271       ns_dumpglyphs_image (s, r[0]);
3272       ns_unfocus (s->f);
3273       break;
3275     case STRETCH_GLYPH:
3276       ns_dumpglyphs_stretch (s);
3277       break;
3279     case CHAR_GLYPH:
3280     case COMPOSITE_GLYPH:
3281       n = ns_get_glyph_string_clip_rect (s, r);
3282       ns_focus (s->f, r, n);
3284       if (s->for_overlaps || (s->cmp_from > 0
3285                               && ! s->first_glyph->u.cmp.automatic))
3286         s->background_filled_p = 1;
3287       else
3288         ns_maybe_dumpglyphs_background
3289           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3291       flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3292         (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3293          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3294           NS_DUMPGLYPH_NORMAL));
3296       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3297         {
3298           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3299           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3300           NS_FACE_FOREGROUND (s->face) = tmp;
3301         }
3303       font->driver->draw
3304         (s, 0, s->nchars, s->x, s->y,
3305          (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3306          || flags == NS_DUMPGLYPH_MOUSEFACE);
3308       {
3309         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3310                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3311                                                    s->f)
3312                         : FRAME_FOREGROUND_COLOR (s->f));
3313         [col set];
3315         /* Draw underline, overline, strike-through. */
3316         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3317       }
3319       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3320         {
3321           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3322           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3323           NS_FACE_FOREGROUND (s->face) = tmp;
3324         }
3326       ns_unfocus (s->f);
3327       break;
3329     case GLYPHLESS_GLYPH:
3330       n = ns_get_glyph_string_clip_rect (s, r);
3331       ns_focus (s->f, r, n);
3333       if (s->for_overlaps || (s->cmp_from > 0
3334                               && ! s->first_glyph->u.cmp.automatic))
3335         s->background_filled_p = 1;
3336       else
3337         ns_maybe_dumpglyphs_background
3338           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3339       /* ... */
3340       /* Not yet implemented.  */
3341       /* ... */
3342       ns_unfocus (s->f);
3343       break;
3345     default:
3346       emacs_abort ();
3347     }
3349   /* Draw box if not done already. */
3350   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3351     {
3352       n = ns_get_glyph_string_clip_rect (s, r);
3353       ns_focus (s->f, r, n);
3354       ns_dumpglyphs_box_or_relief (s);
3355       ns_unfocus (s->f);
3356     }
3358   s->num_clips = 0;
3363 /* ==========================================================================
3365     Event loop
3367    ========================================================================== */
3370 static void
3371 ns_send_appdefined (int value)
3372 /* --------------------------------------------------------------------------
3373     Internal: post an appdefined event which EmacsApp-sendEvent will
3374               recognize and take as a command to halt the event loop.
3375    -------------------------------------------------------------------------- */
3377   /*NSTRACE (ns_send_appdefined); */
3379 #ifdef NS_IMPL_GNUSTEP
3380   // GNUStep needs postEvent to happen on the main thread.
3381   if (! [[NSThread currentThread] isMainThread])
3382     {
3383       EmacsApp *app = (EmacsApp *)NSApp;
3384       app->nextappdefined = value;
3385       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3386                             withObject:nil
3387                          waitUntilDone:YES];
3388       return;
3389     }
3390 #endif
3392   /* Only post this event if we haven't already posted one.  This will end
3393        the [NXApp run] main loop after having processed all events queued at
3394        this moment.  */
3395   if (send_appdefined)
3396     {
3397       NSEvent *nxev;
3399       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3400       send_appdefined = NO;
3402       /* Don't need wakeup timer any more */
3403       if (timed_entry)
3404         {
3405           [timed_entry invalidate];
3406           [timed_entry release];
3407           timed_entry = nil;
3408         }
3410       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3411                                 location: NSMakePoint (0, 0)
3412                            modifierFlags: 0
3413                                timestamp: 0
3414                             windowNumber: [[NSApp mainWindow] windowNumber]
3415                                  context: [NSApp context]
3416                                  subtype: 0
3417                                    data1: value
3418                                    data2: 0];
3420       /* Post an application defined event on the event queue.  When this is
3421          received the [NXApp run] will return, thus having processed all
3422          events which are currently queued.  */
3423       [NSApp postEvent: nxev atStart: NO];
3424     }
3427 #ifdef HAVE_NATIVE_FS
3428 static void
3429 check_native_fs ()
3431   Lisp_Object frame, tail;
3433   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3434     return;
3436   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3438   FOR_EACH_FRAME (tail, frame)
3439     {
3440       struct frame *f = XFRAME (frame);
3441       if (FRAME_NS_P (f))
3442         {
3443           EmacsView *view = FRAME_NS_VIEW (f);
3444           [view updateCollectionBehaviour];
3445         }
3446     }
3448 #endif
3450 /* GNUStep and OSX <= 10.4 does not have cancelTracking.  */
3451 #if defined (NS_IMPL_COCOA) && \
3452   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
3453 /* Check if menu open should be cancelled or continued as normal.  */
3454 void
3455 ns_check_menu_open (NSMenu *menu)
3457   /* Click in menu bar? */
3458   NSArray *a = [[NSApp mainMenu] itemArray];
3459   int i;
3460   BOOL found = NO;
3462   if (menu == nil) // Menu tracking ended.
3463     {
3464       if (menu_will_open_state == MENU_OPENING)
3465         menu_will_open_state = MENU_NONE;
3466       return;
3467     }
3469   for (i = 0; ! found && i < [a count]; i++)
3470     found = menu == [[a objectAtIndex:i] submenu];
3471   if (found)
3472     {
3473       if (menu_will_open_state == MENU_NONE && emacs_event)
3474         {
3475           NSEvent *theEvent = [NSApp currentEvent];
3476           struct frame *emacsframe = SELECTED_FRAME ();
3478           [menu cancelTracking];
3479           menu_will_open_state = MENU_PENDING;
3480           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3481           EV_TRAILER (theEvent);
3483           CGEventRef ourEvent = CGEventCreate (NULL);
3484           menu_mouse_point = CGEventGetLocation (ourEvent);
3485           CFRelease (ourEvent);
3486         }
3487       else if (menu_will_open_state == MENU_OPENING)
3488         {
3489           menu_will_open_state = MENU_NONE;
3490         }
3491     }
3494 /* Redo saved menu click if state is MENU_PENDING.  */
3495 void
3496 ns_check_pending_open_menu ()
3498   if (menu_will_open_state == MENU_PENDING)
3499     {
3500       CGEventSourceRef source
3501         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3503       CGEventRef event = CGEventCreateMouseEvent (source,
3504                                                   kCGEventLeftMouseDown,
3505                                                   menu_mouse_point,
3506                                                   kCGMouseButtonLeft);
3507       CGEventSetType (event, kCGEventLeftMouseDown);
3508       CGEventPost (kCGHIDEventTap, event);
3509       CFRelease (event);
3510       CFRelease (source);
3512       menu_will_open_state = MENU_OPENING;
3513     }
3515 #endif /* NS_IMPL_COCOA) && >= MAC_OS_X_VERSION_10_5 */
3517 static int
3518 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3519 /* --------------------------------------------------------------------------
3520      External (hook): Post an event to ourself and keep reading events until
3521      we read it back again.  In effect process all events which were waiting.
3522      From 21+ we have to manage the event buffer ourselves.
3523    -------------------------------------------------------------------------- */
3525   struct input_event ev;
3526   int nevents;
3528 /* NSTRACE (ns_read_socket); */
3530 #ifdef HAVE_NATIVE_FS
3531   check_native_fs ();
3532 #endif
3534   if ([NSApp modalWindow] != nil)
3535     return -1;
3537   if (hold_event_q.nr > 0)
3538     {
3539       int i;
3540       for (i = 0; i < hold_event_q.nr; ++i)
3541         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3542       hold_event_q.nr = 0;
3543       return i;
3544     }
3546   block_input ();
3547   n_emacs_events_pending = 0;
3548   EVENT_INIT (ev);
3549   emacs_event = &ev;
3550   q_event_ptr = hold_quit;
3552   /* we manage autorelease pools by allocate/reallocate each time around
3553      the loop; strict nesting is occasionally violated but seems not to
3554      matter.. earlier methods using full nesting caused major memory leaks */
3555   [outerpool release];
3556   outerpool = [[NSAutoreleasePool alloc] init];
3558   /* If have pending open-file requests, attend to the next one of those. */
3559   if (ns_pending_files && [ns_pending_files count] != 0
3560       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3561     {
3562       [ns_pending_files removeObjectAtIndex: 0];
3563     }
3564   /* Deal with pending service requests. */
3565   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3566     && [(EmacsApp *)
3567          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3568                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3569     {
3570       [ns_pending_service_names removeObjectAtIndex: 0];
3571       [ns_pending_service_args removeObjectAtIndex: 0];
3572     }
3573   else
3574     {
3575       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3576          to ourself, otherwise [NXApp run] will never exit.  */
3577       send_appdefined = YES;
3578       ns_send_appdefined (-1);
3580       if (++apploopnr != 1)
3581         {
3582           emacs_abort ();
3583         }
3584       [NSApp run];
3585       --apploopnr;
3586     }
3588   nevents = n_emacs_events_pending;
3589   n_emacs_events_pending = 0;
3590   emacs_event = q_event_ptr = NULL;
3591   unblock_input ();
3593   return nevents;
3598 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3599            fd_set *exceptfds, struct timespec const *timeout,
3600            sigset_t const *sigmask)
3601 /* --------------------------------------------------------------------------
3602      Replacement for select, checking for events
3603    -------------------------------------------------------------------------- */
3605   int result;
3606   int t, k, nr = 0;
3607   struct input_event event;
3608   char c;
3610 /*  NSTRACE (ns_select); */
3612 #ifdef HAVE_NATIVE_FS
3613   check_native_fs ();
3614 #endif
3616   if (hold_event_q.nr > 0)
3617     {
3618       /* We already have events pending. */
3619       raise (SIGIO);
3620       errno = EINTR;
3621       return -1;
3622     }
3624   for (k = 0; k < nfds+1; k++)
3625     {
3626       if (readfds && FD_ISSET(k, readfds)) ++nr;
3627       if (writefds && FD_ISSET(k, writefds)) ++nr;
3628     }
3630   if (NSApp == nil
3631       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3632     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3634   [outerpool release];
3635   outerpool = [[NSAutoreleasePool alloc] init];
3638   send_appdefined = YES;
3639   if (nr > 0)
3640     {
3641       pthread_mutex_lock (&select_mutex);
3642       select_nfds = nfds;
3643       select_valid = 0;
3644       if (readfds)
3645         {
3646           select_readfds = *readfds;
3647           select_valid += SELECT_HAVE_READ;
3648         }
3649       if (writefds)
3650         {
3651           select_writefds = *writefds;
3652           select_valid += SELECT_HAVE_WRITE;
3653         }
3655       if (timeout)
3656         {
3657           select_timeout = *timeout;
3658           select_valid += SELECT_HAVE_TMO;
3659         }
3661       pthread_mutex_unlock (&select_mutex);
3663       /* Inform fd_handler that select should be called */
3664       c = 'g';
3665       emacs_write_sig (selfds[1], &c, 1);
3666     }
3667   else if (nr == 0 && timeout)
3668     {
3669       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3670       double time = timespectod (*timeout);
3671       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3672                                                       target: NSApp
3673                                                     selector:
3674                                   @selector (timeout_handler:)
3675                                                     userInfo: 0
3676                                                      repeats: NO]
3677                       retain];
3678     }
3679   else /* No timeout and no file descriptors, can this happen?  */
3680     {
3681       /* Send appdefined so we exit from the loop */
3682       ns_send_appdefined (-1);
3683     }
3685   EVENT_INIT (event);
3686   block_input ();
3687   emacs_event = &event;
3688   if (++apploopnr != 1)
3689     {
3690       emacs_abort ();
3691     }
3692   [NSApp run];
3693   --apploopnr;
3694   emacs_event = NULL;
3695   if (nr > 0 && readfds)
3696     {
3697       c = 's';
3698       emacs_write_sig (selfds[1], &c, 1);
3699     }
3700   unblock_input ();
3702   t = last_appdefined_event_data;
3704   if (t != NO_APPDEFINED_DATA)
3705     {
3706       last_appdefined_event_data = NO_APPDEFINED_DATA;
3708       if (t == -2)
3709         {
3710           /* The NX_APPDEFINED event we received was a timeout. */
3711           result = 0;
3712         }
3713       else if (t == -1)
3714         {
3715           /* The NX_APPDEFINED event we received was the result of
3716              at least one real input event arriving.  */
3717           errno = EINTR;
3718           result = -1;
3719         }
3720       else
3721         {
3722           /* Received back from select () in fd_handler; copy the results */
3723           pthread_mutex_lock (&select_mutex);
3724           if (readfds) *readfds = select_readfds;
3725           if (writefds) *writefds = select_writefds;
3726           pthread_mutex_unlock (&select_mutex);
3727           result = t;
3728         }
3729     }
3730   else
3731     {
3732       errno = EINTR;
3733       result = -1;
3734     }
3736   return result;
3741 /* ==========================================================================
3743     Scrollbar handling
3745    ========================================================================== */
3748 static void
3749 ns_set_vertical_scroll_bar (struct window *window,
3750                            int portion, int whole, int position)
3751 /* --------------------------------------------------------------------------
3752       External (hook): Update or add scrollbar
3753    -------------------------------------------------------------------------- */
3755   Lisp_Object win;
3756   NSRect r, v;
3757   struct frame *f = XFRAME (WINDOW_FRAME (window));
3758   EmacsView *view = FRAME_NS_VIEW (f);
3759   int window_y, window_height;
3760   int top, left, height, width, sb_width, sb_left;
3761   EmacsScroller *bar;
3762   BOOL fringe_extended_p;
3764   /* optimization; display engine sends WAY too many of these.. */
3765   if (!NILP (window->vertical_scroll_bar))
3766     {
3767       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3768       if ([bar checkSamePosition: position portion: portion whole: whole])
3769         {
3770           if (view->scrollbarsNeedingUpdate == 0)
3771             {
3772               if (!windows_or_buffers_changed)
3773                   return;
3774             }
3775           else
3776             view->scrollbarsNeedingUpdate--;
3777         }
3778     }
3780   NSTRACE (ns_set_vertical_scroll_bar);
3782   /* Get dimensions.  */
3783   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3784   top = window_y;
3785   height = window_height;
3786   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3787   left = WINDOW_SCROLL_BAR_AREA_X (window);
3789   /* allow for displaying a skinnier scrollbar than char area allotted */
3790   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3791     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3792   sb_left = left;
3794   r = NSMakeRect (sb_left, top, sb_width, height);
3795   /* the parent view is flipped, so we need to flip y value */
3796   v = [view frame];
3797   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3799   fringe_extended_p = WINDOW_FRINGE_EXTENDED_P (window);
3801   XSETWINDOW (win, window);
3802   block_input ();
3804   /* we want at least 5 lines to display a scrollbar */
3805   if (WINDOW_TOTAL_LINES (window) < 5)
3806     {
3807       if (!NILP (window->vertical_scroll_bar))
3808         {
3809           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3810           [bar removeFromSuperview];
3811           wset_vertical_scroll_bar (window, Qnil);
3812         }
3813       ns_clear_frame_area (f, sb_left, top, width, height);
3814       unblock_input ();
3815       return;
3816     }
3818   if (NILP (window->vertical_scroll_bar))
3819     {
3820       if (width > 0 && height > 0)
3821         {
3822           if (fringe_extended_p)
3823             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3824           else
3825             ns_clear_frame_area (f, left, top, width, height);
3826         }
3828       bar = [[EmacsScroller alloc] initFrame: r window: win];
3829       wset_vertical_scroll_bar (window, make_save_ptr (bar));
3830     }
3831   else
3832     {
3833       NSRect oldRect;
3834       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3835       oldRect = [bar frame];
3836       r.size.width = oldRect.size.width;
3837       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3838         {
3839           if (oldRect.origin.x != r.origin.x)
3840               ns_clear_frame_area (f, sb_left, top, width, height);
3841           [bar setFrame: r];
3842         }
3843     }
3845   [bar setPosition: position portion: portion whole: whole];
3846   unblock_input ();
3850 static void
3851 ns_condemn_scroll_bars (struct frame *f)
3852 /* --------------------------------------------------------------------------
3853      External (hook): arrange for all frame's scrollbars to be removed
3854      at next call to judge_scroll_bars, except for those redeemed.
3855    -------------------------------------------------------------------------- */
3857   int i;
3858   id view;
3859   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3861   NSTRACE (ns_condemn_scroll_bars);
3863   for (i =[subviews count]-1; i >= 0; i--)
3864     {
3865       view = [subviews objectAtIndex: i];
3866       if ([view isKindOfClass: [EmacsScroller class]])
3867         [view condemn];
3868     }
3872 static void
3873 ns_redeem_scroll_bar (struct window *window)
3874 /* --------------------------------------------------------------------------
3875      External (hook): arrange to spare this window's scrollbar
3876      at next call to judge_scroll_bars.
3877    -------------------------------------------------------------------------- */
3879   id bar;
3880   NSTRACE (ns_redeem_scroll_bar);
3881   if (!NILP (window->vertical_scroll_bar))
3882     {
3883       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3884       [bar reprieve];
3885     }
3889 static void
3890 ns_judge_scroll_bars (struct frame *f)
3891 /* --------------------------------------------------------------------------
3892      External (hook): destroy all scrollbars on frame that weren't
3893      redeemed after call to condemn_scroll_bars.
3894    -------------------------------------------------------------------------- */
3896   int i;
3897   id view;
3898   EmacsView *eview = FRAME_NS_VIEW (f);
3899   NSArray *subviews = [[eview superview] subviews];
3900   BOOL removed = NO;
3902   NSTRACE (ns_judge_scroll_bars);
3903   for (i = [subviews count]-1; i >= 0; --i)
3904     {
3905       view = [subviews objectAtIndex: i];
3906       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3907       [view judge];
3908       removed = YES;
3909     }
3911   if (removed)
3912     [eview updateFrameSize: NO];
3915 /* ==========================================================================
3917     Initialization
3919    ========================================================================== */
3922 x_display_pixel_height (struct ns_display_info *dpyinfo)
3924   NSArray *screens = [NSScreen screens];
3925   NSEnumerator *enumerator = [screens objectEnumerator];
3926   NSScreen *screen;
3927   NSRect frame;
3929   frame = NSZeroRect;
3930   while ((screen = [enumerator nextObject]) != nil)
3931     frame = NSUnionRect (frame, [screen frame]);
3933   return NSHeight (frame);
3937 x_display_pixel_width (struct ns_display_info *dpyinfo)
3939   NSArray *screens = [NSScreen screens];
3940   NSEnumerator *enumerator = [screens objectEnumerator];
3941   NSScreen *screen;
3942   NSRect frame;
3944   frame = NSZeroRect;
3945   while ((screen = [enumerator nextObject]) != nil)
3946     frame = NSUnionRect (frame, [screen frame]);
3948   return NSWidth (frame);
3952 static Lisp_Object ns_string_to_lispmod (const char *s)
3953 /* --------------------------------------------------------------------------
3954      Convert modifier name to lisp symbol
3955    -------------------------------------------------------------------------- */
3957   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3958     return Qmeta;
3959   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3960     return Qsuper;
3961   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3962     return Qcontrol;
3963   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3964     return Qalt;
3965   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3966     return Qhyper;
3967   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3968     return Qnone;
3969   else
3970     return Qnil;
3974 static void
3975 ns_default (const char *parameter, Lisp_Object *result,
3976            Lisp_Object yesval, Lisp_Object noval,
3977            BOOL is_float, BOOL is_modstring)
3978 /* --------------------------------------------------------------------------
3979       Check a parameter value in user's preferences
3980    -------------------------------------------------------------------------- */
3982   const char *value = ns_get_defaults_value (parameter);
3984   if (value)
3985     {
3986       double f;
3987       char *pos;
3988       if (c_strcasecmp (value, "YES") == 0)
3989         *result = yesval;
3990       else if (c_strcasecmp (value, "NO") == 0)
3991         *result = noval;
3992       else if (is_float && (f = strtod (value, &pos), pos != value))
3993         *result = make_float (f);
3994       else if (is_modstring && value)
3995         *result = ns_string_to_lispmod (value);
3996       else fprintf (stderr,
3997                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3998     }
4002 static void
4003 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4004 /* --------------------------------------------------------------------------
4005       Initialize global info and storage for display.
4006    -------------------------------------------------------------------------- */
4008     NSScreen *screen = [NSScreen mainScreen];
4009     NSWindowDepth depth = [screen depth];
4011     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4012     dpyinfo->resy = 72.27;
4013     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4014                                                   NSColorSpaceFromDepth (depth)]
4015                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4016                                                  NSColorSpaceFromDepth (depth)];
4017     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4018     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4019     dpyinfo->color_table->colors = NULL;
4020     dpyinfo->root_window = 42; /* a placeholder.. */
4021     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4022     dpyinfo->n_fonts = 0;
4023     dpyinfo->smallest_font_height = 1;
4024     dpyinfo->smallest_char_width = 1;
4026     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4030 /* This and next define (many of the) public functions in this file. */
4031 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4032          with using despite presence in the "system dependent" redisplay
4033          interface.  In addition, many of the ns_ methods have code that is
4034          shared with all terms, indicating need for further refactoring. */
4035 extern frame_parm_handler ns_frame_parm_handlers[];
4036 static struct redisplay_interface ns_redisplay_interface =
4038   ns_frame_parm_handlers,
4039   x_produce_glyphs,
4040   x_write_glyphs,
4041   x_insert_glyphs,
4042   x_clear_end_of_line,
4043   ns_scroll_run,
4044   ns_after_update_window_line,
4045   ns_update_window_begin,
4046   ns_update_window_end,
4047   0, /* flush_display */
4048   x_clear_window_mouse_face,
4049   x_get_glyph_overhangs,
4050   x_fix_overlapping_area,
4051   ns_draw_fringe_bitmap,
4052   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4053   0, /* destroy_fringe_bitmap */
4054   ns_compute_glyph_string_overhangs,
4055   ns_draw_glyph_string,
4056   ns_define_frame_cursor,
4057   ns_clear_frame_area,
4058   ns_draw_window_cursor,
4059   ns_draw_vertical_window_border,
4060   ns_draw_window_divider,
4061   ns_shift_glyphs_for_insert
4065 static void
4066 ns_delete_display (struct ns_display_info *dpyinfo)
4068   /* TODO... */
4072 /* This function is called when the last frame on a display is deleted. */
4073 static void
4074 ns_delete_terminal (struct terminal *terminal)
4076   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4078   /* Protect against recursive calls.  delete_frame in
4079      delete_terminal calls us back when it deletes our last frame.  */
4080   if (!terminal->name)
4081     return;
4083   block_input ();
4085   x_destroy_all_bitmaps (dpyinfo);
4086   ns_delete_display (dpyinfo);
4087   unblock_input ();
4091 static struct terminal *
4092 ns_create_terminal (struct ns_display_info *dpyinfo)
4093 /* --------------------------------------------------------------------------
4094       Set up use of NS before we make the first connection.
4095    -------------------------------------------------------------------------- */
4097   struct terminal *terminal;
4099   NSTRACE (ns_create_terminal);
4101   terminal = create_terminal ();
4103   terminal->type = output_ns;
4104   terminal->display_info.ns = dpyinfo;
4105   dpyinfo->terminal = terminal;
4107   terminal->rif = &ns_redisplay_interface;
4109   terminal->clear_frame_hook = ns_clear_frame;
4110   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4111   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
4112   terminal->ring_bell_hook = ns_ring_bell;
4113   terminal->reset_terminal_modes_hook = NULL;
4114   terminal->set_terminal_modes_hook = NULL;
4115   terminal->update_begin_hook = ns_update_begin;
4116   terminal->update_end_hook = ns_update_end;
4117   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4118   terminal->read_socket_hook = ns_read_socket;
4119   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4120   terminal->mouse_position_hook = ns_mouse_position;
4121   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4122   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4124   terminal->fullscreen_hook = ns_fullscreen_hook;
4126   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4127   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4128   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4129   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4131   terminal->delete_frame_hook = x_destroy_window;
4132   terminal->delete_terminal_hook = ns_delete_terminal;
4134   return terminal;
4138 struct ns_display_info *
4139 ns_term_init (Lisp_Object display_name)
4140 /* --------------------------------------------------------------------------
4141      Start the Application and get things rolling.
4142    -------------------------------------------------------------------------- */
4144   struct terminal *terminal;
4145   struct ns_display_info *dpyinfo;
4146   static int ns_initialized = 0;
4147   Lisp_Object tmp;
4149   if (ns_initialized) return x_display_list;
4150   ns_initialized = 1;
4152   NSTRACE (ns_term_init);
4154   [outerpool release];
4155   outerpool = [[NSAutoreleasePool alloc] init];
4157   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4158   /*GSDebugAllocationActive (YES); */
4159   block_input ();
4161   baud_rate = 38400;
4162   Fset_input_interrupt_mode (Qnil);
4164   if (selfds[0] == -1)
4165     {
4166       if (emacs_pipe (selfds) != 0)
4167         {
4168           fprintf (stderr, "Failed to create pipe: %s\n",
4169                    emacs_strerror (errno));
4170           emacs_abort ();
4171         }
4173       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4174       FD_ZERO (&select_readfds);
4175       FD_ZERO (&select_writefds);
4176       pthread_mutex_init (&select_mutex, NULL);
4177     }
4179   ns_pending_files = [[NSMutableArray alloc] init];
4180   ns_pending_service_names = [[NSMutableArray alloc] init];
4181   ns_pending_service_args = [[NSMutableArray alloc] init];
4183 /* Start app and create the main menu, window, view.
4184      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4185      The view will then ask the NSApp to stop and return to Emacs. */
4186   [EmacsApp sharedApplication];
4187   if (NSApp == nil)
4188     return NULL;
4189   [NSApp setDelegate: NSApp];
4191   /* Start the select thread.  */
4192   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4193                            toTarget:NSApp
4194                          withObject:nil];
4196   /* debugging: log all notifications */
4197   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4198                                          selector: @selector (logNotification:)
4199                                              name: nil object: nil]; */
4201   dpyinfo = xzalloc (sizeof *dpyinfo);
4203   ns_initialize_display_info (dpyinfo);
4204   terminal = ns_create_terminal (dpyinfo);
4206   terminal->kboard = allocate_kboard (Qns);
4207   /* Don't let the initial kboard remain current longer than necessary.
4208      That would cause problems if a file loaded on startup tries to
4209      prompt in the mini-buffer.  */
4210   if (current_kboard == initial_kboard)
4211     current_kboard = terminal->kboard;
4212   terminal->kboard->reference_count++;
4214   dpyinfo->next = x_display_list;
4215   x_display_list = dpyinfo;
4217   dpyinfo->name_list_element = Fcons (display_name, Qnil);
4219   terminal->name = xstrdup (SSDATA (display_name));
4221   unblock_input ();
4223   if (!inhibit_x_resources)
4224     {
4225       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4226                  Qt, Qnil, NO, NO);
4227       tmp = Qnil;
4228       /* this is a standard variable */
4229       ns_default ("AppleAntiAliasingThreshold", &tmp,
4230                  make_float (10.0), make_float (6.0), YES, NO);
4231       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4232     }
4234   {
4235     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4237     if ( cl == nil )
4238       {
4239         Lisp_Object color_file, color_map, color;
4240         unsigned long c;
4241         char *name;
4243         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4244                          Fsymbol_value (intern ("data-directory")));
4246         color_map = Fx_load_color_file (color_file);
4247         if (NILP (color_map))
4248           fatal ("Could not read %s.\n", SDATA (color_file));
4250         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4251         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4252           {
4253             color = XCAR (color_map);
4254             name = SSDATA (XCAR (color));
4255             c = XINT (XCDR (color));
4256             [cl setColor:
4257                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4258                                             green: GREEN_FROM_ULONG (c) / 255.0
4259                                              blue: BLUE_FROM_ULONG (c) / 255.0
4260                                             alpha: 1.0]
4261                   forKey: [NSString stringWithUTF8String: name]];
4262           }
4263         [cl writeToFile: nil];
4264       }
4265   }
4267   {
4268 #ifdef NS_IMPL_GNUSTEP
4269     Vwindow_system_version = build_string (gnustep_base_version);
4270 #else
4271     /*PSnextrelease (128, c); */
4272     char c[DBL_BUFSIZE_BOUND];
4273     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4274     Vwindow_system_version = make_unibyte_string (c, len);
4275 #endif
4276   }
4278   delete_keyboard_wait_descriptor (0);
4280   ns_app_name = [[NSProcessInfo processInfo] processName];
4282 /* Set up OS X app menu */
4283 #ifdef NS_IMPL_COCOA
4284   {
4285     NSMenu *appMenu;
4286     NSMenuItem *item;
4287     /* set up the application menu */
4288     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4289     [svcsMenu setAutoenablesItems: NO];
4290     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4291     [appMenu setAutoenablesItems: NO];
4292     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4293     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4295     [appMenu insertItemWithTitle: @"About Emacs"
4296                           action: @selector (orderFrontStandardAboutPanel:)
4297                    keyEquivalent: @""
4298                          atIndex: 0];
4299     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4300     [appMenu insertItemWithTitle: @"Preferences..."
4301                           action: @selector (showPreferencesWindow:)
4302                    keyEquivalent: @","
4303                          atIndex: 2];
4304     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4305     item = [appMenu insertItemWithTitle: @"Services"
4306                                  action: @selector (menuDown:)
4307                           keyEquivalent: @""
4308                                 atIndex: 4];
4309     [appMenu setSubmenu: svcsMenu forItem: item];
4310     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4311     [appMenu insertItemWithTitle: @"Hide Emacs"
4312                           action: @selector (hide:)
4313                    keyEquivalent: @"h"
4314                          atIndex: 6];
4315     item =  [appMenu insertItemWithTitle: @"Hide Others"
4316                           action: @selector (hideOtherApplications:)
4317                    keyEquivalent: @"h"
4318                          atIndex: 7];
4319     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4320     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4321     [appMenu insertItemWithTitle: @"Quit Emacs"
4322                           action: @selector (terminate:)
4323                    keyEquivalent: @"q"
4324                          atIndex: 9];
4326     item = [mainMenu insertItemWithTitle: ns_app_name
4327                                   action: @selector (menuDown:)
4328                            keyEquivalent: @""
4329                                  atIndex: 0];
4330     [mainMenu setSubmenu: appMenu forItem: item];
4331     [dockMenu insertItemWithTitle: @"New Frame"
4332                            action: @selector (newFrame:)
4333                     keyEquivalent: @""
4334                           atIndex: 0];
4336     [NSApp setMainMenu: mainMenu];
4337     [NSApp setAppleMenu: appMenu];
4338     [NSApp setServicesMenu: svcsMenu];
4339     /* Needed at least on Cocoa, to get dock menu to show windows */
4340     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4342     [[NSNotificationCenter defaultCenter]
4343       addObserver: mainMenu
4344          selector: @selector (trackingNotification:)
4345              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4346     [[NSNotificationCenter defaultCenter]
4347       addObserver: mainMenu
4348          selector: @selector (trackingNotification:)
4349              name: NSMenuDidEndTrackingNotification object: mainMenu];
4350   }
4351 #endif /* MAC OS X menu setup */
4353   /* Register our external input/output types, used for determining
4354      applicable services and also drag/drop eligibility. */
4355   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4356   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4357                       retain];
4358   ns_drag_types = [[NSArray arrayWithObjects:
4359                             NSStringPboardType,
4360                             NSTabularTextPboardType,
4361                             NSFilenamesPboardType,
4362                             NSURLPboardType,
4363                             NSColorPboardType,
4364                             NSFontPboardType, nil] retain];
4366   /* If fullscreen is in init/default-frame-alist, focus isn't set
4367      right for fullscreen windows, so set this.  */
4368   [NSApp activateIgnoringOtherApps:YES];
4370   [NSApp run];
4371   ns_do_open_file = YES;
4373 #ifdef NS_IMPL_GNUSTEP
4374   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4375      We must re-catch it so subprocess works.  */
4376   catch_child_signal ();
4377 #endif
4378   return dpyinfo;
4382 void
4383 ns_term_shutdown (int sig)
4385   [[NSUserDefaults standardUserDefaults] synchronize];
4387   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4388   if (STRINGP (Vauto_save_list_file_name))
4389     unlink (SSDATA (Vauto_save_list_file_name));
4391   if (sig == 0 || sig == SIGTERM)
4392     {
4393       [NSApp terminate: NSApp];
4394     }
4395   else // force a stack trace to happen
4396     {
4397       emacs_abort ();
4398     }
4402 /* ==========================================================================
4404     EmacsApp implementation
4406    ========================================================================== */
4409 @implementation EmacsApp
4411 - (id)init
4413   if (self = [super init])
4414     {
4415 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
4416       self->isFirst = YES;
4417 #endif
4418 #ifdef NS_IMPL_GNUSTEP
4419       self->applicationDidFinishLaunchingCalled = NO;
4420 #endif
4421     }
4423   return self;
4426 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
4427 - (void)run
4429     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4431     if (isFirst) [self finishLaunching];
4432     isFirst = NO;
4434     shouldKeepRunning = YES;
4435     do
4436       {
4437         [pool release];
4438         pool = [[NSAutoreleasePool alloc] init];
4440         NSEvent *event =
4441           [self nextEventMatchingMask:NSAnyEventMask
4442                             untilDate:[NSDate distantFuture]
4443                                inMode:NSDefaultRunLoopMode
4444                               dequeue:YES];
4445         [self sendEvent:event];
4446         [self updateWindows];
4447     } while (shouldKeepRunning);
4449     [pool release];
4452 - (void)stop: (id)sender
4454     shouldKeepRunning = NO;
4455     // Stop possible dialog also.  Noop if no dialog present.
4456     // The file dialog still leaks 7k - 10k on 10.9 though.
4457     [super stop:sender];
4459 #endif
4461 - (void)logNotification: (NSNotification *)notification
4463   const char *name = [[notification name] UTF8String];
4464   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4465       && !strstr (name, "WindowNumber"))
4466     NSLog (@"notification: '%@'", [notification name]);
4470 - (void)sendEvent: (NSEvent *)theEvent
4471 /* --------------------------------------------------------------------------
4472      Called when NSApp is running for each event received.  Used to stop
4473      the loop when we choose, since there's no way to just run one iteration.
4474    -------------------------------------------------------------------------- */
4476   int type = [theEvent type];
4477   NSWindow *window = [theEvent window];
4479 /*  NSTRACE (sendEvent); */
4480 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4482 #ifdef NS_IMPL_GNUSTEP
4483   // Keyboard events aren't propagated to file dialogs for some reason.
4484   if ([NSApp modalWindow] != nil &&
4485       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4486     {
4487       [[NSApp modalWindow] sendEvent: theEvent];
4488       return;
4489     }
4490 #endif
4492   if (type == NSApplicationDefined)
4493     {
4494       switch ([theEvent data2])
4495         {
4496 #ifdef NS_IMPL_COCOA
4497         case NSAPP_DATA2_RUNASSCRIPT:
4498           ns_run_ascript ();
4499           [self stop: self];
4500           return;
4501 #endif
4502         case NSAPP_DATA2_RUNFILEDIALOG:
4503           ns_run_file_dialog ();
4504           [self stop: self];
4505           return;
4506         }
4507     }
4509   if (type == NSCursorUpdate && window == nil)
4510     {
4511       fprintf (stderr, "Dropping external cursor update event.\n");
4512       return;
4513     }
4515   if (type == NSApplicationDefined)
4516     {
4517       /* Events posted by ns_send_appdefined interrupt the run loop here.
4518          But, if a modal window is up, an appdefined can still come through,
4519          (e.g., from a makeKeyWindow event) but stopping self also stops the
4520          modal loop. Just defer it until later. */
4521       if ([NSApp modalWindow] == nil)
4522         {
4523           last_appdefined_event_data = [theEvent data1];
4524           [self stop: self];
4525         }
4526       else
4527         {
4528           send_appdefined = YES;
4529         }
4530     }
4533 #ifdef NS_IMPL_COCOA
4534   /* If no dialog and none of our frames have focus and it is a move, skip it.
4535      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4536      such as Wifi, sound, date or similar.
4537      This prevents "spooky" highlighting in the frame under the menu.  */
4538   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4539     {
4540       struct ns_display_info *di;
4541       BOOL has_focus = NO;
4542       for (di = x_display_list; ! has_focus && di; di = di->next)
4543         has_focus = di->x_focus_frame != 0;
4544       if (! has_focus)
4545         return;
4546     }
4547 #endif
4549   [super sendEvent: theEvent];
4553 - (void)showPreferencesWindow: (id)sender
4555   struct frame *emacsframe = SELECTED_FRAME ();
4556   NSEvent *theEvent = [NSApp currentEvent];
4558   if (!emacs_event)
4559     return;
4560   emacs_event->kind = NS_NONKEY_EVENT;
4561   emacs_event->code = KEY_NS_SHOW_PREFS;
4562   emacs_event->modifiers = 0;
4563   EV_TRAILER (theEvent);
4567 - (void)newFrame: (id)sender
4569   struct frame *emacsframe = SELECTED_FRAME ();
4570   NSEvent *theEvent = [NSApp currentEvent];
4572   if (!emacs_event)
4573     return;
4574   emacs_event->kind = NS_NONKEY_EVENT;
4575   emacs_event->code = KEY_NS_NEW_FRAME;
4576   emacs_event->modifiers = 0;
4577   EV_TRAILER (theEvent);
4581 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4582 - (BOOL) openFile: (NSString *)fileName
4584   struct frame *emacsframe = SELECTED_FRAME ();
4585   NSEvent *theEvent = [NSApp currentEvent];
4587   if (!emacs_event)
4588     return NO;
4590   emacs_event->kind = NS_NONKEY_EVENT;
4591   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4592   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4593   ns_input_line = Qnil; /* can be start or cons start,end */
4594   emacs_event->modifiers =0;
4595   EV_TRAILER (theEvent);
4597   return YES;
4601 /* **************************************************************************
4603       EmacsApp delegate implementation
4605    ************************************************************************** */
4607 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4608 /* --------------------------------------------------------------------------
4609      When application is loaded, terminate event loop in ns_term_init
4610    -------------------------------------------------------------------------- */
4612   NSTRACE (applicationDidFinishLaunching);
4613 #ifdef NS_IMPL_GNUSTEP
4614   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
4615 #endif
4616   [NSApp setServicesProvider: NSApp];
4617   ns_send_appdefined (-2);
4621 /* Termination sequences:
4622     C-x C-c:
4623     Cmd-Q:
4624     MenuBar | File | Exit:
4625     Select Quit from App menubar:
4626         -terminate
4627         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4628         ns_term_shutdown()
4630     Select Quit from Dock menu:
4631     Logout attempt:
4632         -appShouldTerminate
4633           Cancel -> Nothing else
4634           Accept ->
4636           -terminate
4637           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4638           ns_term_shutdown()
4642 - (void) terminate: (id)sender
4644   struct frame *emacsframe = SELECTED_FRAME ();
4646   if (!emacs_event)
4647     return;
4649   emacs_event->kind = NS_NONKEY_EVENT;
4650   emacs_event->code = KEY_NS_POWER_OFF;
4651   emacs_event->arg = Qt; /* mark as non-key event */
4652   EV_TRAILER ((id)nil);
4656 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4658   int ret;
4660   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4661     return NSTerminateNow;
4663     ret = NSRunAlertPanel(ns_app_name,
4664                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4665                           @"Save Buffers and Exit", @"Cancel", nil);
4667     if (ret == NSAlertDefaultReturn)
4668         return NSTerminateNow;
4669     else if (ret == NSAlertAlternateReturn)
4670         return NSTerminateCancel;
4671     return NSTerminateNow;  /* just in case */
4674 static int
4675 not_in_argv (NSString *arg)
4677   int k;
4678   const char *a = [arg UTF8String];
4679   for (k = 1; k < initial_argc; ++k)
4680     if (strcmp (a, initial_argv[k]) == 0) return 0;
4681   return 1;
4684 /*   Notification from the Workspace to open a file */
4685 - (BOOL)application: sender openFile: (NSString *)file
4687   if (ns_do_open_file || not_in_argv (file))
4688     [ns_pending_files addObject: file];
4689   return YES;
4693 /*   Open a file as a temporary file */
4694 - (BOOL)application: sender openTempFile: (NSString *)file
4696   if (ns_do_open_file || not_in_argv (file))
4697     [ns_pending_files addObject: file];
4698   return YES;
4702 /*   Notification from the Workspace to open a file noninteractively (?) */
4703 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4705   if (ns_do_open_file || not_in_argv (file))
4706     [ns_pending_files addObject: file];
4707   return YES;
4710 /*   Notification from the Workspace to open multiple files */
4711 - (void)application: sender openFiles: (NSArray *)fileList
4713   NSEnumerator *files = [fileList objectEnumerator];
4714   NSString *file;
4715   /* Don't open files from the command line unconditionally,
4716      Cocoa parses the command line wrong, --option value tries to open value
4717      if --option is the last option.  */
4718   while ((file = [files nextObject]) != nil)
4719     if (ns_do_open_file || not_in_argv (file))
4720       [ns_pending_files addObject: file];
4722   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4727 /* Handle dock menu requests.  */
4728 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4730   return dockMenu;
4734 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4735 - (void)applicationWillBecomeActive: (NSNotification *)notification
4737   //ns_app_active=YES;
4739 - (void)applicationDidBecomeActive: (NSNotification *)notification
4741   NSTRACE (applicationDidBecomeActive);
4743 #ifdef NS_IMPL_GNUSTEP
4744   if (! applicationDidFinishLaunchingCalled)
4745     [self applicationDidFinishLaunching:notification];
4746 #endif
4747   //ns_app_active=YES;
4749   ns_update_auto_hide_menu_bar ();
4750   // No constraining takes place when the application is not active.
4751   ns_constrain_all_frames ();
4753 - (void)applicationDidResignActive: (NSNotification *)notification
4755   //ns_app_active=NO;
4756   ns_send_appdefined (-1);
4761 /* ==========================================================================
4763     EmacsApp aux handlers for managing event loop
4765    ========================================================================== */
4768 - (void)timeout_handler: (NSTimer *)timedEntry
4769 /* --------------------------------------------------------------------------
4770      The timeout specified to ns_select has passed.
4771    -------------------------------------------------------------------------- */
4773   /*NSTRACE (timeout_handler); */
4774   ns_send_appdefined (-2);
4777 #ifdef NS_IMPL_GNUSTEP
4778 - (void)sendFromMainThread:(id)unused
4780   ns_send_appdefined (nextappdefined);
4782 #endif
4784 - (void)fd_handler:(id)unused
4785 /* --------------------------------------------------------------------------
4786      Check data waiting on file descriptors and terminate if so
4787    -------------------------------------------------------------------------- */
4789   int result;
4790   int waiting = 1, nfds;
4791   char c;
4793   fd_set readfds, writefds, *wfds;
4794   struct timespec timeout, *tmo;
4795   NSAutoreleasePool *pool = nil;
4797   /* NSTRACE (fd_handler); */
4799   for (;;)
4800     {
4801       [pool release];
4802       pool = [[NSAutoreleasePool alloc] init];
4804       if (waiting)
4805         {
4806           fd_set fds;
4807           FD_ZERO (&fds);
4808           FD_SET (selfds[0], &fds);
4809           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4810           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4811             waiting = 0;
4812         }
4813       else
4814         {
4815           pthread_mutex_lock (&select_mutex);
4816           nfds = select_nfds;
4818           if (select_valid & SELECT_HAVE_READ)
4819             readfds = select_readfds;
4820           else
4821             FD_ZERO (&readfds);
4823           if (select_valid & SELECT_HAVE_WRITE)
4824             {
4825               writefds = select_writefds;
4826               wfds = &writefds;
4827             }
4828           else
4829             wfds = NULL;
4830           if (select_valid & SELECT_HAVE_TMO)
4831             {
4832               timeout = select_timeout;
4833               tmo = &timeout;
4834             }
4835           else
4836             tmo = NULL;
4838           pthread_mutex_unlock (&select_mutex);
4840           FD_SET (selfds[0], &readfds);
4841           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4843           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4845           if (result == 0)
4846             ns_send_appdefined (-2);
4847           else if (result > 0)
4848             {
4849               if (FD_ISSET (selfds[0], &readfds))
4850                 {
4851                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4852                     waiting = 1;
4853                 }
4854               else
4855                 {
4856                   pthread_mutex_lock (&select_mutex);
4857                   if (select_valid & SELECT_HAVE_READ)
4858                     select_readfds = readfds;
4859                   if (select_valid & SELECT_HAVE_WRITE)
4860                     select_writefds = writefds;
4861                   if (select_valid & SELECT_HAVE_TMO)
4862                     select_timeout = timeout;
4863                   pthread_mutex_unlock (&select_mutex);
4865                   ns_send_appdefined (result);
4866                 }
4867             }
4868           waiting = 1;
4869         }
4870     }
4875 /* ==========================================================================
4877     Service provision
4879    ========================================================================== */
4881 /* called from system: queue for next pass through event loop */
4882 - (void)requestService: (NSPasteboard *)pboard
4883               userData: (NSString *)userData
4884                  error: (NSString **)error
4886   [ns_pending_service_names addObject: userData];
4887   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4888       SSDATA (ns_string_from_pasteboard (pboard))]];
4892 /* called from ns_read_socket to clear queue */
4893 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4895   struct frame *emacsframe = SELECTED_FRAME ();
4896   NSEvent *theEvent = [NSApp currentEvent];
4898   if (!emacs_event)
4899     return NO;
4901   emacs_event->kind = NS_NONKEY_EVENT;
4902   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4903   ns_input_spi_name = build_string ([name UTF8String]);
4904   ns_input_spi_arg = build_string ([arg UTF8String]);
4905   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4906   EV_TRAILER (theEvent);
4908   return YES;
4912 @end  /* EmacsApp */
4916 /* ==========================================================================
4918     EmacsView implementation
4920    ========================================================================== */
4923 @implementation EmacsView
4925 /* needed to inform when window closed from LISP */
4926 - (void) setWindowClosing: (BOOL)closing
4928   windowClosing = closing;
4932 - (void)dealloc
4934   NSTRACE (EmacsView_dealloc);
4935   [toolbar release];
4936   if (fs_state == FULLSCREEN_BOTH)
4937     [nonfs_window release];
4938   [super dealloc];
4942 /* called on font panel selection */
4943 - (void)changeFont: (id)sender
4945   NSEvent *e = [[self window] currentEvent];
4946   struct face *face = FRAME_DEFAULT_FACE (emacsframe);
4947   struct font *font = face->font;
4948   id newFont;
4949   CGFloat size;
4950   NSFont *nsfont;
4952   NSTRACE (changeFont);
4954   if (!emacs_event)
4955     return;
4957   if (EQ (font->driver->type, Qns))
4958     nsfont = ((struct nsfont_info *)font)->nsfont;
4959 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
4960   else
4961     nsfont = (NSFont *) macfont_get_nsctfont (font);
4962 #endif
4964   if ((newFont = [sender convertFont: nsfont]))
4965     {
4966       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4968       emacs_event->kind = NS_NONKEY_EVENT;
4969       emacs_event->modifiers = 0;
4970       emacs_event->code = KEY_NS_CHANGE_FONT;
4972       size = [newFont pointSize];
4973       ns_input_fontsize = make_number (lrint (size));
4974       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4975       EV_TRAILER (e);
4976     }
4980 - (BOOL)acceptsFirstResponder
4982   NSTRACE (acceptsFirstResponder);
4983   return YES;
4987 - (void)resetCursorRects
4989   NSRect visible = [self visibleRect];
4990   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4991   NSTRACE (resetCursorRects);
4993   if (currentCursor == nil)
4994     currentCursor = [NSCursor arrowCursor];
4996   if (!NSIsEmptyRect (visible))
4997     [self addCursorRect: visible cursor: currentCursor];
4998   [currentCursor setOnMouseEntered: YES];
5003 /*****************************************************************************/
5004 /* Keyboard handling. */
5005 #define NS_KEYLOG 0
5007 - (void)keyDown: (NSEvent *)theEvent
5009   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5010   int code;
5011   unsigned fnKeysym = 0;
5012   static NSMutableArray *nsEvArray;
5013 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5014   static BOOL firstTime = YES;
5015 #endif
5016   int left_is_none;
5017   unsigned int flags = [theEvent modifierFlags];
5019   NSTRACE (keyDown);
5021   /* Rhapsody and OS X give up and down events for the arrow keys */
5022   if (ns_fake_keydown == YES)
5023     ns_fake_keydown = NO;
5024   else if ([theEvent type] != NSKeyDown)
5025     return;
5027   if (!emacs_event)
5028     return;
5030  if (![[self window] isKeyWindow]
5031      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5032      /* we must avoid an infinite loop here. */
5033      && (EmacsView *)[[theEvent window] delegate] != self)
5034    {
5035      /* XXX: There is an occasional condition in which, when Emacs display
5036          updates a different frame from the current one, and temporarily
5037          selects it, then processes some interrupt-driven input
5038          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5039          for some reason that window has its first responder set to the NSView
5040          most recently updated (I guess), which is not the correct one. */
5041      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5042      return;
5043    }
5045   if (nsEvArray == nil)
5046     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5048   [NSCursor setHiddenUntilMouseMoves: YES];
5050   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5051     {
5052       clear_mouse_face (hlinfo);
5053       hlinfo->mouse_face_hidden = 1;
5054     }
5056   if (!processingCompose)
5057     {
5058       /* When using screen sharing, no left or right information is sent,
5059          so use Left key in those cases.  */
5060       int is_left_key, is_right_key;
5062       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5063         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5065       /* (Carbon way: [theEvent keyCode]) */
5067       /* is it a "function key"? */
5068       fnKeysym = (code < 0x00ff && (flags&NSNumericPadKeyMask))
5069         ? ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask)
5070         : ns_convert_key (code);
5072       if (fnKeysym)
5073         {
5074           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5075              because Emacs treats Delete and KP-Delete same (in simple.el). */
5076           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5077 #ifdef NS_IMPL_GNUSTEP
5078               /*  GNUstep uses incompatible keycodes, even for those that are
5079                   supposed to be hardware independent.  Just check for delete.
5080                   Keypad delete does not have keysym 0xFFFF.
5081                   See http://savannah.gnu.org/bugs/?25395
5082               */
5083               || (fnKeysym == 0xFFFF && code == 127)
5084 #endif
5085             )
5086             code = 0xFF08; /* backspace */
5087           else
5088             code = fnKeysym;
5089         }
5091       /* are there modifiers? */
5092       emacs_event->modifiers = 0;
5094       if (flags & NSHelpKeyMask)
5095           emacs_event->modifiers |= hyper_modifier;
5097       if (flags & NSShiftKeyMask)
5098         emacs_event->modifiers |= shift_modifier;
5100       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5101       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5102         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5104       if (is_right_key)
5105         emacs_event->modifiers |= parse_solitary_modifier
5106           (EQ (ns_right_command_modifier, Qleft)
5107            ? ns_command_modifier
5108            : ns_right_command_modifier);
5110       if (is_left_key)
5111         {
5112           emacs_event->modifiers |= parse_solitary_modifier
5113             (ns_command_modifier);
5115           /* if super (default), take input manager's word so things like
5116              dvorak / qwerty layout work */
5117           if (EQ (ns_command_modifier, Qsuper)
5118               && !fnKeysym
5119               && [[theEvent characters] length] != 0)
5120             {
5121               /* XXX: the code we get will be unshifted, so if we have
5122                  a shift modifier, must convert ourselves */
5123               if (!(flags & NSShiftKeyMask))
5124                 code = [[theEvent characters] characterAtIndex: 0];
5125 #if 0
5126               /* this is ugly and also requires linking w/Carbon framework
5127                  (for LMGetKbdType) so for now leave this rare (?) case
5128                  undealt with.. in future look into CGEvent methods */
5129               else
5130                 {
5131                   long smv = GetScriptManagerVariable (smKeyScript);
5132                   Handle uchrHandle = GetResource
5133                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5134                   UInt32 dummy = 0;
5135                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5136                                  [[theEvent characters] characterAtIndex: 0],
5137                                  kUCKeyActionDisplay,
5138                                  (flags & ~NSCommandKeyMask) >> 8,
5139                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5140                                  &dummy, 1, &dummy, &code);
5141                   code &= 0xFF;
5142                 }
5143 #endif
5144             }
5145         }
5147       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5148       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5149         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5151       if (is_right_key)
5152           emacs_event->modifiers |= parse_solitary_modifier
5153               (EQ (ns_right_control_modifier, Qleft)
5154                ? ns_control_modifier
5155                : ns_right_control_modifier);
5157       if (is_left_key)
5158         emacs_event->modifiers |= parse_solitary_modifier
5159           (ns_control_modifier);
5161       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5162           emacs_event->modifiers |=
5163             parse_solitary_modifier (ns_function_modifier);
5165       left_is_none = NILP (ns_alternate_modifier)
5166         || EQ (ns_alternate_modifier, Qnone);
5168       is_right_key = (flags & NSRightAlternateKeyMask)
5169         == NSRightAlternateKeyMask;
5170       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5171         || (! is_right_key
5172             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5174       if (is_right_key)
5175         {
5176           if ((NILP (ns_right_alternate_modifier)
5177                || EQ (ns_right_alternate_modifier, Qnone)
5178                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5179               && !fnKeysym)
5180             {   /* accept pre-interp alt comb */
5181               if ([[theEvent characters] length] > 0)
5182                 code = [[theEvent characters] characterAtIndex: 0];
5183               /*HACK: clear lone shift modifier to stop next if from firing */
5184               if (emacs_event->modifiers == shift_modifier)
5185                 emacs_event->modifiers = 0;
5186             }
5187           else
5188             emacs_event->modifiers |= parse_solitary_modifier
5189               (EQ (ns_right_alternate_modifier, Qleft)
5190                ? ns_alternate_modifier
5191                : ns_right_alternate_modifier);
5192         }
5194       if (is_left_key) /* default = meta */
5195         {
5196           if (left_is_none && !fnKeysym)
5197             {   /* accept pre-interp alt comb */
5198               if ([[theEvent characters] length] > 0)
5199                 code = [[theEvent characters] characterAtIndex: 0];
5200               /*HACK: clear lone shift modifier to stop next if from firing */
5201               if (emacs_event->modifiers == shift_modifier)
5202                 emacs_event->modifiers = 0;
5203             }
5204           else
5205               emacs_event->modifiers |=
5206                 parse_solitary_modifier (ns_alternate_modifier);
5207         }
5209   if (NS_KEYLOG)
5210     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5211              code, fnKeysym, flags, emacs_event->modifiers);
5213       /* if it was a function key or had modifiers, pass it directly to emacs */
5214       if (fnKeysym || (emacs_event->modifiers
5215                        && (emacs_event->modifiers != shift_modifier)
5216                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5217 /*[[theEvent characters] length] */
5218         {
5219           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5220           if (code < 0x20)
5221             code |= (1<<28)|(3<<16);
5222           else if (code == 0x7f)
5223             code |= (1<<28)|(3<<16);
5224           else if (!fnKeysym)
5225             emacs_event->kind = code > 0xFF
5226               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5228           emacs_event->code = code;
5229           EV_TRAILER (theEvent);
5230           processingCompose = NO;
5231           return;
5232         }
5233     }
5236 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5237   /* if we get here we should send the key for input manager processing */
5238   /* Disable warning, there is nothing a user can do about it anyway, and
5239      it does not seem to matter.  */
5240 #if 0
5241   if (firstTime && [[NSInputManager currentInputManager]
5242                      wantsToDelayTextChangeNotifications] == NO)
5243     fprintf (stderr,
5244           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5245 #endif
5246   firstTime = NO;
5247 #endif
5248   if (NS_KEYLOG && !processingCompose)
5249     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5251   processingCompose = YES;
5252   [nsEvArray addObject: theEvent];
5253   [self interpretKeyEvents: nsEvArray];
5254   [nsEvArray removeObject: theEvent];
5258 #ifdef NS_IMPL_COCOA
5259 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5260    decided not to send key-down for.
5261    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5262    This only applies on Tiger and earlier.
5263    If it matches one of these, send it on to keyDown. */
5264 -(void)keyUp: (NSEvent *)theEvent
5266   int flags = [theEvent modifierFlags];
5267   int code = [theEvent keyCode];
5268   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5269       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5270     {
5271       if (NS_KEYLOG)
5272         fprintf (stderr, "keyUp: passed test");
5273       ns_fake_keydown = YES;
5274       [self keyDown: theEvent];
5275     }
5277 #endif
5280 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5283 /* <NSTextInput>: called when done composing;
5284    NOTE: also called when we delete over working text, followed immed.
5285          by doCommandBySelector: deleteBackward: */
5286 - (void)insertText: (id)aString
5288   int code;
5289   int len = [(NSString *)aString length];
5290   int i;
5292   if (NS_KEYLOG)
5293     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5294   processingCompose = NO;
5296   if (!emacs_event)
5297     return;
5299   /* first, clear any working text */
5300   if (workingText != nil)
5301     [self deleteWorkingText];
5303   /* now insert the string as keystrokes */
5304   for (i =0; i<len; i++)
5305     {
5306       code = [aString characterAtIndex: i];
5307       /* TODO: still need this? */
5308       if (code == 0x2DC)
5309         code = '~'; /* 0x7E */
5310       if (code != 32) /* Space */
5311         emacs_event->modifiers = 0;
5312       emacs_event->kind
5313         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5314       emacs_event->code = code;
5315       EV_TRAILER ((id)nil);
5316     }
5320 /* <NSTextInput>: inserts display of composing characters */
5321 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5323   NSString *str = [aString respondsToSelector: @selector (string)] ?
5324     [aString string] : aString;
5325   if (NS_KEYLOG)
5326     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5327            str, (unsigned long)[str length],
5328            (unsigned long)selRange.length,
5329            (unsigned long)selRange.location);
5331   if (workingText != nil)
5332     [self deleteWorkingText];
5333   if ([str length] == 0)
5334     return;
5336   if (!emacs_event)
5337     return;
5339   processingCompose = YES;
5340   workingText = [str copy];
5341   ns_working_text = build_string ([workingText UTF8String]);
5343   emacs_event->kind = NS_TEXT_EVENT;
5344   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5345   EV_TRAILER ((id)nil);
5349 /* delete display of composing characters [not in <NSTextInput>] */
5350 - (void)deleteWorkingText
5352   if (workingText == nil)
5353     return;
5354   if (NS_KEYLOG)
5355     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5356   [workingText release];
5357   workingText = nil;
5358   processingCompose = NO;
5360   if (!emacs_event)
5361     return;
5363   emacs_event->kind = NS_TEXT_EVENT;
5364   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5365   EV_TRAILER ((id)nil);
5369 - (BOOL)hasMarkedText
5371   return workingText != nil;
5375 - (NSRange)markedRange
5377   NSRange rng = workingText != nil
5378     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5379   if (NS_KEYLOG)
5380     NSLog (@"markedRange request");
5381   return rng;
5385 - (void)unmarkText
5387   if (NS_KEYLOG)
5388     NSLog (@"unmark (accept) text");
5389   [self deleteWorkingText];
5390   processingCompose = NO;
5394 /* used to position char selection windows, etc. */
5395 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5397   NSRect rect;
5398   NSPoint pt;
5399   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5400   if (NS_KEYLOG)
5401     NSLog (@"firstRectForCharRange request");
5403   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5404   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5405   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5406   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5407                                        +FRAME_LINE_HEIGHT (emacsframe));
5409   pt = [self convertPoint: pt toView: nil];
5410   pt = [[self window] convertBaseToScreen: pt];
5411   rect.origin = pt;
5412   return rect;
5416 - (NSInteger)conversationIdentifier
5418   return (NSInteger)self;
5422 - (void)doCommandBySelector: (SEL)aSelector
5424   if (NS_KEYLOG)
5425     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5427   processingCompose = NO;
5428   if (aSelector == @selector (deleteBackward:))
5429     {
5430       /* happens when user backspaces over an ongoing composition:
5431          throw a 'delete' into the event queue */
5432       if (!emacs_event)
5433         return;
5434       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5435       emacs_event->code = 0xFF08;
5436       EV_TRAILER ((id)nil);
5437     }
5440 - (NSArray *)validAttributesForMarkedText
5442   static NSArray *arr = nil;
5443   if (arr == nil) arr = [NSArray new];
5444  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5445   return arr;
5448 - (NSRange)selectedRange
5450   if (NS_KEYLOG)
5451     NSLog (@"selectedRange request");
5452   return NSMakeRange (NSNotFound, 0);
5455 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5456     GNUSTEP_GUI_MINOR_VERSION > 22
5457 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5458 #else
5459 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5460 #endif
5462   if (NS_KEYLOG)
5463     NSLog (@"characterIndexForPoint request");
5464   return 0;
5467 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5469   static NSAttributedString *str = nil;
5470   if (str == nil) str = [NSAttributedString new];
5471   if (NS_KEYLOG)
5472     NSLog (@"attributedSubstringFromRange request");
5473   return str;
5476 /* End <NSTextInput> impl. */
5477 /*****************************************************************************/
5480 /* This is what happens when the user presses a mouse button.  */
5481 - (void)mouseDown: (NSEvent *)theEvent
5483   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5484   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5486   NSTRACE (mouseDown);
5488   [self deleteWorkingText];
5490   if (!emacs_event)
5491     return;
5493   dpyinfo->last_mouse_frame = emacsframe;
5494   /* appears to be needed to prevent spurious movement events generated on
5495      button clicks */
5496   emacsframe->mouse_moved = 0;
5498   if ([theEvent type] == NSScrollWheel)
5499     {
5500       CGFloat delta = [theEvent deltaY];
5501       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5502       if (delta == 0)
5503         return;
5504       emacs_event->kind = WHEEL_EVENT;
5505       emacs_event->code = 0;
5506       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5507         ((delta > 0) ? up_modifier : down_modifier);
5508     }
5509   else
5510     {
5511       emacs_event->kind = MOUSE_CLICK_EVENT;
5512       emacs_event->code = EV_BUTTON (theEvent);
5513       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5514                              | EV_UDMODIFIERS (theEvent);
5515     }
5516   XSETINT (emacs_event->x, lrint (p.x));
5517   XSETINT (emacs_event->y, lrint (p.y));
5518   EV_TRAILER (theEvent);
5522 - (void)rightMouseDown: (NSEvent *)theEvent
5524   NSTRACE (rightMouseDown);
5525   [self mouseDown: theEvent];
5529 - (void)otherMouseDown: (NSEvent *)theEvent
5531   NSTRACE (otherMouseDown);
5532   [self mouseDown: theEvent];
5536 - (void)mouseUp: (NSEvent *)theEvent
5538   NSTRACE (mouseUp);
5539   [self mouseDown: theEvent];
5543 - (void)rightMouseUp: (NSEvent *)theEvent
5545   NSTRACE (rightMouseUp);
5546   [self mouseDown: theEvent];
5550 - (void)otherMouseUp: (NSEvent *)theEvent
5552   NSTRACE (otherMouseUp);
5553   [self mouseDown: theEvent];
5557 - (void) scrollWheel: (NSEvent *)theEvent
5559   NSTRACE (scrollWheel);
5560   [self mouseDown: theEvent];
5564 /* Tell emacs the mouse has moved. */
5565 - (void)mouseMoved: (NSEvent *)e
5567   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5568   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5569   Lisp_Object frame;
5570   NSPoint pt;
5572 //  NSTRACE (mouseMoved);
5574   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
5575   pt = [self convertPoint: [e locationInWindow] fromView: nil];
5576   dpyinfo->last_mouse_motion_x = pt.x;
5577   dpyinfo->last_mouse_motion_y = pt.y;
5579   /* update any mouse face */
5580   if (hlinfo->mouse_face_hidden)
5581     {
5582       hlinfo->mouse_face_hidden = 0;
5583       clear_mouse_face (hlinfo);
5584     }
5586   /* tooltip handling */
5587   previous_help_echo_string = help_echo_string;
5588   help_echo_string = Qnil;
5590   if (!NILP (Vmouse_autoselect_window))
5591     {
5592       NSTRACE (mouse_autoselect_window);
5593       static Lisp_Object last_mouse_window;
5594       Lisp_Object window
5595         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
5597       if (WINDOWP (window)
5598           && !EQ (window, last_mouse_window)
5599           && !EQ (window, selected_window)
5600           && (focus_follows_mouse
5601               || (EQ (XWINDOW (window)->frame,
5602                       XWINDOW (selected_window)->frame))))
5603         {
5604           NSTRACE (in_window);
5605           emacs_event->kind = SELECT_WINDOW_EVENT;
5606           emacs_event->frame_or_window = window;
5607           EV_TRAILER2 (e);
5608         }
5609       /* Remember the last window where we saw the mouse.  */
5610       last_mouse_window = window;
5611     }
5613   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
5614     help_echo_string = previous_help_echo_string;
5616   XSETFRAME (frame, emacsframe);
5617   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5618     {
5619       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5620          (note_mouse_highlight), which is called through the
5621          note_mouse_movement () call above */
5622       gen_help_event (help_echo_string, frame, help_echo_window,
5623                       help_echo_object, help_echo_pos);
5624     }
5625   else
5626     {
5627       help_echo_string = Qnil;
5628       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5629     }
5631   if (emacsframe->mouse_moved && send_appdefined)
5632     ns_send_appdefined (-1);
5636 - (void)mouseDragged: (NSEvent *)e
5638   NSTRACE (mouseDragged);
5639   [self mouseMoved: e];
5643 - (void)rightMouseDragged: (NSEvent *)e
5645   NSTRACE (rightMouseDragged);
5646   [self mouseMoved: e];
5650 - (void)otherMouseDragged: (NSEvent *)e
5652   NSTRACE (otherMouseDragged);
5653   [self mouseMoved: e];
5657 - (BOOL)windowShouldClose: (id)sender
5659   NSEvent *e =[[self window] currentEvent];
5661   NSTRACE (windowShouldClose);
5662   windowClosing = YES;
5663   if (!emacs_event)
5664     return NO;
5665   emacs_event->kind = DELETE_WINDOW_EVENT;
5666   emacs_event->modifiers = 0;
5667   emacs_event->code = 0;
5668   EV_TRAILER (e);
5669   /* Don't close this window, let this be done from lisp code.  */
5670   return NO;
5673 - (void) updateFrameSize: (BOOL) delay;
5675   NSWindow *window = [self window];
5676   NSRect wr = [window frame];
5677   int extra = 0;
5678   int oldc = cols, oldr = rows;
5679   int oldw = FRAME_PIXEL_WIDTH (emacsframe),
5680     oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5681   int neww, newh;
5683   if (! [self isFullscreen])
5684     {
5685 #ifdef NS_IMPL_GNUSTEP
5686       // GNUStep does not always update the tool bar height.  Force it.
5687       if (toolbar) update_frame_tool_bar (emacsframe);
5688 #endif
5690       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5691         + FRAME_TOOLBAR_HEIGHT (emacsframe);
5692     }
5694   neww = (int)wr.size.width - emacsframe->border_width;
5695   newh = (int)wr.size.height - extra;
5697   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
5698   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
5700   if (cols < MINWIDTH)
5701     cols = MINWIDTH;
5703   if (rows < MINHEIGHT)
5704     rows = MINHEIGHT;
5706   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5707     {
5708       NSView *view = FRAME_NS_VIEW (emacsframe);
5709       NSWindow *win = [view window];
5710       NSSize sz = [win resizeIncrements];
5712       change_frame_size (emacsframe,
5713                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
5714                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
5715                          0, delay, 0, 1);
5716       SET_FRAME_GARBAGED (emacsframe);
5717       cancel_mouse_face (emacsframe);
5719       // Did resize increments change because of a font change?
5720       if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5721           sz.height != FRAME_LINE_HEIGHT (emacsframe))
5722         {
5723           sz.width = FRAME_COLUMN_WIDTH (emacsframe);
5724           sz.height = FRAME_LINE_HEIGHT (emacsframe);
5725           [win setResizeIncrements: sz];
5726         }
5728       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5729       [self windowDidMove:nil];   // Update top/left.
5730     }
5733 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5734 /* normalize frame to gridded text size */
5736   int extra = 0;
5738   NSTRACE (windowWillResize);
5739 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5741   if (fs_state == FULLSCREEN_MAXIMIZED
5742       && (maximized_width != (int)frameSize.width
5743           || maximized_height != (int)frameSize.height))
5744     [self setFSValue: FULLSCREEN_NONE];
5745   else if (fs_state == FULLSCREEN_WIDTH
5746            && maximized_width != (int)frameSize.width)
5747     [self setFSValue: FULLSCREEN_NONE];
5748   else if (fs_state == FULLSCREEN_HEIGHT
5749            && maximized_height != (int)frameSize.height)
5750     [self setFSValue: FULLSCREEN_NONE];
5751   if (fs_state == FULLSCREEN_NONE)
5752     maximized_width = maximized_height = -1;
5754   if (! [self isFullscreen])
5755     {
5756       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5757         + FRAME_TOOLBAR_HEIGHT (emacsframe);
5758     }
5760   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
5761   if (cols < MINWIDTH)
5762     cols = MINWIDTH;
5764   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5765                                            frameSize.height - extra);
5766   if (rows < MINHEIGHT)
5767     rows = MINHEIGHT;
5768 #ifdef NS_IMPL_COCOA
5769   {
5770     /* this sets window title to have size in it; the wm does this under GS */
5771     NSRect r = [[self window] frame];
5772     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5773       {
5774         if (old_title != 0)
5775           {
5776             xfree (old_title);
5777             old_title = 0;
5778           }
5779       }
5780     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5781       {
5782         char *size_title;
5783         NSWindow *window = [self window];
5784         if (old_title == 0)
5785           {
5786             char *t = strdup ([[[self window] title] UTF8String]);
5787             char *pos = strstr (t, "  â€”  ");
5788             if (pos)
5789               *pos = '\0';
5790             old_title = t;
5791           }
5792         size_title = xmalloc (strlen (old_title) + 40);
5793         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5794         [window setTitle: [NSString stringWithUTF8String: size_title]];
5795         [window display];
5796         xfree (size_title);
5797       }
5798   }
5799 #endif /* NS_IMPL_COCOA */
5800 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5802   return frameSize;
5806 - (void)windowDidResize: (NSNotification *)notification
5808   if (! [self fsIsNative])
5809     {
5810       NSWindow *theWindow = [notification object];
5811       /* We can get notification on the non-FS window when in
5812          fullscreen mode.  */
5813       if ([self window] != theWindow) return;
5814     }
5816 #ifdef NS_IMPL_GNUSTEP
5817   NSWindow *theWindow = [notification object];
5819    /* In GNUstep, at least currently, it's possible to get a didResize
5820       without getting a willResize.. therefore we need to act as if we got
5821       the willResize now */
5822   NSSize sz = [theWindow frame].size;
5823   sz = [self windowWillResize: theWindow toSize: sz];
5824 #endif /* NS_IMPL_GNUSTEP */
5826   NSTRACE (windowDidResize);
5827 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5829 if (cols > 0 && rows > 0)
5830     {
5831       [self updateFrameSize: YES];
5832     }
5834   ns_send_appdefined (-1);
5837 #ifdef NS_IMPL_COCOA
5838 - (void)viewDidEndLiveResize
5840   [super viewDidEndLiveResize];
5841   if (old_title != 0)
5842     {
5843       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
5844       xfree (old_title);
5845       old_title = 0;
5846     }
5847   maximizing_resize = NO;
5849 #endif /* NS_IMPL_COCOA */
5852 - (void)windowDidBecomeKey: (NSNotification *)notification
5853 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5855   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5856   struct frame *old_focus = dpyinfo->x_focus_frame;
5858   NSTRACE (windowDidBecomeKey);
5860   if (emacsframe != old_focus)
5861     dpyinfo->x_focus_frame = emacsframe;
5863   ns_frame_rehighlight (emacsframe);
5865   if (emacs_event)
5866     {
5867       emacs_event->kind = FOCUS_IN_EVENT;
5868       EV_TRAILER ((id)nil);
5869     }
5873 - (void)windowDidResignKey: (NSNotification *)notification
5874 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5876   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5877   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
5878   NSTRACE (windowDidResignKey);
5880   if (is_focus_frame)
5881     dpyinfo->x_focus_frame = 0;
5883   ns_frame_rehighlight (emacsframe);
5885   /* FIXME: for some reason needed on second and subsequent clicks away
5886             from sole-frame Emacs to get hollow box to show */
5887   if (!windowClosing && [[self window] isVisible] == YES)
5888     {
5889       x_update_cursor (emacsframe, 1);
5890       x_set_frame_alpha (emacsframe);
5891     }
5893   if (emacs_event && is_focus_frame)
5894     {
5895       [self deleteWorkingText];
5896       emacs_event->kind = FOCUS_OUT_EVENT;
5897       EV_TRAILER ((id)nil);
5898     }
5902 - (void)windowWillMiniaturize: sender
5904   NSTRACE (windowWillMiniaturize);
5908 - (BOOL)isFlipped
5910   return YES;
5914 - (BOOL)isOpaque
5916   return NO;
5920 - initFrameFromEmacs: (struct frame *)f
5922   NSRect r, wr;
5923   Lisp_Object tem;
5924   NSWindow *win;
5925   NSSize sz;
5926   NSColor *col;
5927   NSString *name;
5929   NSTRACE (initFrameFromEmacs);
5931   windowClosing = NO;
5932   processingCompose = NO;
5933   scrollbarsNeedingUpdate = 0;
5934   fs_state = FULLSCREEN_NONE;
5935   fs_before_fs = next_maximized = -1;
5936 #ifdef HAVE_NATIVE_FS
5937   fs_is_native = ns_use_native_fullscreen;
5938 #else
5939   fs_is_native = NO;
5940 #endif
5941   maximized_width = maximized_height = -1;
5942   nonfs_window = nil;
5944 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5946   ns_userRect = NSMakeRect (0, 0, 0, 0);
5947   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5948                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5949   [self initWithFrame: r];
5950   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5952   FRAME_NS_VIEW (f) = self;
5953   emacsframe = f;
5954 #ifdef NS_IMPL_COCOA
5955   old_title = 0;
5956   maximizing_resize = NO;
5957 #endif
5959   win = [[EmacsWindow alloc]
5960             initWithContentRect: r
5961                       styleMask: (NSResizableWindowMask |
5962 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5963                                   NSTitledWindowMask |
5964 #endif
5965                                   NSMiniaturizableWindowMask |
5966                                   NSClosableWindowMask)
5967                         backing: NSBackingStoreBuffered
5968                           defer: YES];
5970 #ifdef HAVE_NATIVE_FS
5971     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
5972 #endif
5974   wr = [win frame];
5975   bwidth = f->border_width = wr.size.width - r.size.width;
5976   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5978   [win setAcceptsMouseMovedEvents: YES];
5979   [win setDelegate: self];
5980   [win useOptimizedDrawing: YES];
5982   sz.width = FRAME_COLUMN_WIDTH (f);
5983   sz.height = FRAME_LINE_HEIGHT (f);
5984   [win setResizeIncrements: sz];
5986   [[win contentView] addSubview: self];
5988   if (ns_drag_types)
5989     [self registerForDraggedTypes: ns_drag_types];
5991   tem = f->name;
5992   name = [NSString stringWithUTF8String:
5993                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5994   [win setTitle: name];
5996   /* toolbar support */
5997   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5998                          [NSString stringWithFormat: @"Emacs Frame %d",
5999                                    ns_window_num]];
6000   [win setToolbar: toolbar];
6001   [toolbar setVisible: NO];
6002 #ifdef NS_IMPL_COCOA
6003   {
6004     NSButton *toggleButton;
6005   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6006   [toggleButton setTarget: self];
6007   [toggleButton setAction: @selector (toggleToolbar: )];
6008   }
6009 #endif
6010   FRAME_TOOLBAR_HEIGHT (f) = 0;
6012   tem = f->icon_name;
6013   if (!NILP (tem))
6014     [win setMiniwindowTitle:
6015            [NSString stringWithUTF8String: SSDATA (tem)]];
6017   {
6018     NSScreen *screen = [win screen];
6020     if (screen != 0)
6021       [win setFrameTopLeftPoint: NSMakePoint
6022            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6023             IN_BOUND (-SCREENMAX,
6024                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
6025   }
6027   [win makeFirstResponder: self];
6029   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6030                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6031   [win setBackgroundColor: col];
6032   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6033     [win setOpaque: NO];
6035   [self allocateGState];
6037   [NSApp registerServicesMenuSendTypes: ns_send_types
6038                            returnTypes: nil];
6040   ns_window_num++;
6041   return self;
6045 - (void)windowDidMove: sender
6047   NSWindow *win = [self window];
6048   NSRect r = [win frame];
6049   NSArray *screens = [NSScreen screens];
6050   NSScreen *screen = [screens objectAtIndex: 0];
6052   NSTRACE (windowDidMove);
6054   if (!emacsframe->output_data.ns)
6055     return;
6056   if (screen != nil)
6057     {
6058       emacsframe->left_pos = r.origin.x;
6059       emacsframe->top_pos =
6060         [screen frame].size.height - (r.origin.y + r.size.height);
6061     }
6065 /* Called AFTER method below, but before our windowWillResize call there leads
6066    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
6067    location so set_window_size moves the frame. */
6068 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6070   emacsframe->output_data.ns->zooming = 1;
6071   return YES;
6075 /* Override to do something slightly nonstandard, but nice.  First click on
6076    zoom button will zoom vertically.  Second will zoom completely.  Third
6077    returns to original. */
6078 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6079                         defaultFrame:(NSRect)defaultFrame
6081   NSRect result = [sender frame];
6083   NSTRACE (windowWillUseStandardFrame);
6085   if (fs_before_fs != -1) /* Entering fullscreen */
6086       {
6087         result = defaultFrame;
6088       }
6089   else if (next_maximized == FULLSCREEN_HEIGHT
6090       || (next_maximized == -1
6091           && abs (defaultFrame.size.height - result.size.height)
6092           > FRAME_LINE_HEIGHT (emacsframe)))
6093     {
6094       /* first click */
6095       ns_userRect = result;
6096       maximized_height = result.size.height = defaultFrame.size.height;
6097       maximized_width = -1;
6098       result.origin.y = defaultFrame.origin.y;
6099       [self setFSValue: FULLSCREEN_HEIGHT];
6100 #ifdef NS_IMPL_COCOA
6101       maximizing_resize = YES;
6102 #endif
6103     }
6104   else if (next_maximized == FULLSCREEN_WIDTH)
6105     {
6106       ns_userRect = result;
6107       maximized_width = result.size.width = defaultFrame.size.width;
6108       maximized_height = -1;
6109       result.origin.x = defaultFrame.origin.x;
6110       [self setFSValue: FULLSCREEN_WIDTH];
6111     }
6112   else if (next_maximized == FULLSCREEN_MAXIMIZED
6113            || (next_maximized == -1
6114                && abs (defaultFrame.size.width - result.size.width)
6115                > FRAME_COLUMN_WIDTH (emacsframe)))
6116     {
6117       result = defaultFrame;  /* second click */
6118       maximized_width = result.size.width;
6119       maximized_height = result.size.height;
6120       [self setFSValue: FULLSCREEN_MAXIMIZED];
6121 #ifdef NS_IMPL_COCOA
6122       maximizing_resize = YES;
6123 #endif
6124     }
6125   else
6126     {
6127       /* restore */
6128       result = ns_userRect.size.height ? ns_userRect : result;
6129       ns_userRect = NSMakeRect (0, 0, 0, 0);
6130 #ifdef NS_IMPL_COCOA
6131       maximizing_resize = fs_state != FULLSCREEN_NONE;
6132 #endif
6133       [self setFSValue: FULLSCREEN_NONE];
6134       maximized_width = maximized_height = -1;
6135     }
6137   if (fs_before_fs == -1) next_maximized = -1;
6138   [self windowWillResize: sender toSize: result.size];
6139   return result;
6143 - (void)windowDidDeminiaturize: sender
6145   NSTRACE (windowDidDeminiaturize);
6146   if (!emacsframe->output_data.ns)
6147     return;
6149   SET_FRAME_ICONIFIED (emacsframe, 0);
6150   SET_FRAME_VISIBLE (emacsframe, 1);
6151   windows_or_buffers_changed = 63;
6153   if (emacs_event)
6154     {
6155       emacs_event->kind = DEICONIFY_EVENT;
6156       EV_TRAILER ((id)nil);
6157     }
6161 - (void)windowDidExpose: sender
6163   NSTRACE (windowDidExpose);
6164   if (!emacsframe->output_data.ns)
6165     return;
6167   SET_FRAME_VISIBLE (emacsframe, 1);
6168   SET_FRAME_GARBAGED (emacsframe);
6170   if (send_appdefined)
6171     ns_send_appdefined (-1);
6175 - (void)windowDidMiniaturize: sender
6177   NSTRACE (windowDidMiniaturize);
6178   if (!emacsframe->output_data.ns)
6179     return;
6181   SET_FRAME_ICONIFIED (emacsframe, 1);
6182   SET_FRAME_VISIBLE (emacsframe, 0);
6184   if (emacs_event)
6185     {
6186       emacs_event->kind = ICONIFY_EVENT;
6187       EV_TRAILER ((id)nil);
6188     }
6191 #ifdef HAVE_NATIVE_FS
6192 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6193       willUseFullScreenPresentationOptions:
6194   (NSApplicationPresentationOptions)proposedOptions
6196   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6198 #endif
6200 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6202   fs_before_fs = fs_state;
6205 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6207   [self setFSValue: FULLSCREEN_BOTH];
6208   if (! [self fsIsNative])
6209     {
6210       [self windowDidBecomeKey:notification];
6211       [nonfs_window orderOut:self];
6212     }
6213   else
6214     {
6215       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
6216 #ifdef NS_IMPL_COCOA
6217 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6218       unsigned val = (unsigned)[NSApp presentationOptions];
6220       // OSX 10.7 bug fix, the menu won't appear without this.
6221       // val is non-zero on other OSX versions.
6222       if (val == 0)
6223         {
6224           NSApplicationPresentationOptions options
6225             = NSApplicationPresentationAutoHideDock
6226             | NSApplicationPresentationAutoHideMenuBar
6227             | NSApplicationPresentationFullScreen
6228             | NSApplicationPresentationAutoHideToolbar;
6230           [NSApp setPresentationOptions: options];
6231         }
6232 #endif
6233 #endif
6234       [toolbar setVisible:tbar_visible];
6235     }
6238 - (void)windowWillExitFullScreen:(NSNotification *)notification
6240   if (next_maximized != -1)
6241     fs_before_fs = next_maximized;
6244 - (void)windowDidExitFullScreen:(NSNotification *)notification
6246   [self setFSValue: fs_before_fs];
6247   fs_before_fs = -1;
6248 #ifdef HAVE_NATIVE_FS
6249   [self updateCollectionBehaviour];
6250 #endif
6251   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6252     {
6253       [toolbar setVisible:YES];
6254       update_frame_tool_bar (emacsframe);
6255       [self updateFrameSize:YES];
6256       [[self window] display];
6257     }
6258   else
6259     [toolbar setVisible:NO];
6261   if (next_maximized != -1)
6262     [[self window] performZoom:self];
6265 - (BOOL)fsIsNative
6267   return fs_is_native;
6270 - (BOOL)isFullscreen
6272   if (! fs_is_native) return nonfs_window != nil;
6273 #ifdef HAVE_NATIVE_FS
6274   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6275 #else
6276   return NO;
6277 #endif
6280 #ifdef HAVE_NATIVE_FS
6281 - (void)updateCollectionBehaviour
6283   if (! [self isFullscreen])
6284     {
6285       NSWindow *win = [self window];
6286       NSWindowCollectionBehavior b = [win collectionBehavior];
6287       if (ns_use_native_fullscreen)
6288         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6289       else
6290         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6292       [win setCollectionBehavior: b];
6293       fs_is_native = ns_use_native_fullscreen;
6294     }
6296 #endif
6298 - (void)toggleFullScreen: (id)sender
6300   NSWindow *w, *fw;
6301   BOOL onFirstScreen;
6302   struct frame *f;
6303   NSSize sz;
6304   NSRect r, wr;
6305   NSColor *col;
6307   if (fs_is_native)
6308     {
6309 #ifdef HAVE_NATIVE_FS
6310       [[self window] toggleFullScreen:sender];
6311 #endif
6312       return;
6313     }
6315   w = [self window];
6316   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6317   f = emacsframe;
6318   wr = [w frame];
6319   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6320                                  (FRAME_DEFAULT_FACE (f)),
6321                                  f);
6323   sz.width = FRAME_COLUMN_WIDTH (f);
6324   sz.height = FRAME_LINE_HEIGHT (f);
6326   if (fs_state != FULLSCREEN_BOTH)
6327     {
6328       /* Hide dock and menubar if we are on the primary screen.  */
6329       if (onFirstScreen)
6330         {
6331 #if defined (NS_IMPL_COCOA) && \
6332   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6333           NSApplicationPresentationOptions options
6334             = NSApplicationPresentationAutoHideDock
6335             | NSApplicationPresentationAutoHideMenuBar;
6337           [NSApp setPresentationOptions: options];
6338 #else
6339           [NSMenu setMenuBarVisible:NO];
6340 #endif
6341         }
6343       fw = [[EmacsFSWindow alloc]
6344                        initWithContentRect:[w contentRectForFrameRect:wr]
6345                                  styleMask:NSBorderlessWindowMask
6346                                    backing:NSBackingStoreBuffered
6347                                      defer:YES
6348                                     screen:[w screen]];
6350       [fw setContentView:[w contentView]];
6351       [fw setTitle:[w title]];
6352       [fw setDelegate:self];
6353       [fw setAcceptsMouseMovedEvents: YES];
6354       [fw useOptimizedDrawing: YES];
6355       [fw setResizeIncrements: sz];
6356       [fw setBackgroundColor: col];
6357       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6358         [fw setOpaque: NO];
6360       f->border_width = 0;
6361       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6362       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6363       FRAME_TOOLBAR_HEIGHT (f) = 0;
6365       nonfs_window = w;
6367       [self windowWillEnterFullScreen:nil];
6368       [fw makeKeyAndOrderFront:NSApp];
6369       [fw makeFirstResponder:self];
6370       [w orderOut:self];
6371       r = [fw frameRectForContentRect:[[fw screen] frame]];
6372       [fw setFrame: r display:YES animate:YES];
6373       [self windowDidEnterFullScreen:nil];
6374       [fw display];
6375     }
6376   else
6377     {
6378       fw = w;
6379       w = nonfs_window;
6380       nonfs_window = nil;
6382       if (onFirstScreen)
6383         {
6384 #if defined (NS_IMPL_COCOA) && \
6385   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6386           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6387 #else
6388           [NSMenu setMenuBarVisible:YES];
6389 #endif
6390         }
6392       [w setContentView:[fw contentView]];
6393       [w setResizeIncrements: sz];
6394       [w setBackgroundColor: col];
6395       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6396         [w setOpaque: NO];
6398       f->border_width = bwidth;
6399       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6400       if (FRAME_EXTERNAL_TOOL_BAR (f))
6401         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6403       [self windowWillExitFullScreen:nil];
6404       [fw setFrame: [w frame] display:YES animate:YES];
6405       [fw close];
6406       [w makeKeyAndOrderFront:NSApp];
6407       [self windowDidExitFullScreen:nil];
6408       [self updateFrameSize:YES];
6409     }
6412 - (void)handleFS
6414   if (fs_state != emacsframe->want_fullscreen)
6415     {
6416       if (fs_state == FULLSCREEN_BOTH)
6417         {
6418           [self toggleFullScreen:self];
6419         }
6421       switch (emacsframe->want_fullscreen)
6422         {
6423         case FULLSCREEN_BOTH:
6424           [self toggleFullScreen:self];
6425           break;
6426         case FULLSCREEN_WIDTH:
6427           next_maximized = FULLSCREEN_WIDTH;
6428           if (fs_state != FULLSCREEN_BOTH)
6429             [[self window] performZoom:self];
6430           break;
6431         case FULLSCREEN_HEIGHT:
6432           next_maximized = FULLSCREEN_HEIGHT;
6433           if (fs_state != FULLSCREEN_BOTH)
6434             [[self window] performZoom:self];
6435           break;
6436         case FULLSCREEN_MAXIMIZED:
6437           next_maximized = FULLSCREEN_MAXIMIZED;
6438           if (fs_state != FULLSCREEN_BOTH)
6439             [[self window] performZoom:self];
6440           break;
6441         case FULLSCREEN_NONE:
6442           if (fs_state != FULLSCREEN_BOTH)
6443             {
6444               next_maximized = FULLSCREEN_NONE;
6445               [[self window] performZoom:self];
6446             }
6447           break;
6448         }
6450       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6451     }
6455 - (void) setFSValue: (int)value
6457   Lisp_Object lval = Qnil;
6458   switch (value)
6459     {
6460     case FULLSCREEN_BOTH:
6461       lval = Qfullboth;
6462       break;
6463     case FULLSCREEN_WIDTH:
6464       lval = Qfullwidth;
6465       break;
6466     case FULLSCREEN_HEIGHT:
6467       lval = Qfullheight;
6468       break;
6469     case FULLSCREEN_MAXIMIZED:
6470       lval = Qmaximized;
6471       break;
6472     }
6473   store_frame_param (emacsframe, Qfullscreen, lval);
6474   fs_state = value;
6477 - (void)mouseEntered: (NSEvent *)theEvent
6479   NSTRACE (mouseEntered);
6480   if (emacsframe)
6481     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6482       = EV_TIMESTAMP (theEvent);
6486 - (void)mouseExited: (NSEvent *)theEvent
6488   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6490   NSTRACE (mouseExited);
6492   if (!hlinfo)
6493     return;
6495   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6496     = EV_TIMESTAMP (theEvent);
6498   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6499     {
6500       clear_mouse_face (hlinfo);
6501       hlinfo->mouse_face_mouse_frame = 0;
6502     }
6506 - menuDown: sender
6508   NSTRACE (menuDown);
6509   if (context_menu_value == -1)
6510     context_menu_value = [sender tag];
6511   else
6512     {
6513       NSInteger tag = [sender tag];
6514       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6515                                     emacsframe->menu_bar_vector,
6516                                     (void *)tag);
6517     }
6519   ns_send_appdefined (-1);
6520   return self;
6524 - (EmacsToolbar *)toolbar
6526   return toolbar;
6530 /* this gets called on toolbar button click */
6531 - toolbarClicked: (id)item
6533   NSEvent *theEvent;
6534   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6536   NSTRACE (toolbarClicked);
6538   if (!emacs_event)
6539     return self;
6541   /* send first event (for some reason two needed) */
6542   theEvent = [[self window] currentEvent];
6543   emacs_event->kind = TOOL_BAR_EVENT;
6544   XSETFRAME (emacs_event->arg, emacsframe);
6545   EV_TRAILER (theEvent);
6547   emacs_event->kind = TOOL_BAR_EVENT;
6548 /*   XSETINT (emacs_event->code, 0); */
6549   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6550                            idx + TOOL_BAR_ITEM_KEY);
6551   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6552   EV_TRAILER (theEvent);
6553   return self;
6557 - toggleToolbar: (id)sender
6559   if (!emacs_event)
6560     return self;
6562   emacs_event->kind = NS_NONKEY_EVENT;
6563   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6564   EV_TRAILER ((id)nil);
6565   return self;
6569 - (void)drawRect: (NSRect)rect
6571   int x = NSMinX (rect), y = NSMinY (rect);
6572   int width = NSWidth (rect), height = NSHeight (rect);
6574   NSTRACE (drawRect);
6576   if (!emacsframe || !emacsframe->output_data.ns)
6577     return;
6579   ns_clear_frame_area (emacsframe, x, y, width, height);
6580   expose_frame (emacsframe, x, y, width, height);
6582   /*
6583     drawRect: may be called (at least in OS X 10.5) for invisible
6584     views as well for some reason.  Thus, do not infer visibility
6585     here.
6587     emacsframe->async_visible = 1;
6588     emacsframe->async_iconified = 0;
6589   */
6593 /* NSDraggingDestination protocol methods.  Actually this is not really a
6594    protocol, but a category of Object.  O well...  */
6596 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6598   NSTRACE (draggingEntered);
6599   return NSDragOperationGeneric;
6603 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6605   return YES;
6609 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6611   id pb;
6612   int x, y;
6613   NSString *type;
6614   NSEvent *theEvent = [[self window] currentEvent];
6615   NSPoint position;
6617   NSTRACE (performDragOperation);
6619   if (!emacs_event)
6620     return NO;
6622   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6623   x = lrint (position.x);  y = lrint (position.y);
6625   pb = [sender draggingPasteboard];
6626   type = [pb availableTypeFromArray: ns_drag_types];
6627   if (type == 0)
6628     {
6629       return NO;
6630     }
6631   else if ([type isEqualToString: NSFilenamesPboardType])
6632     {
6633       NSArray *files;
6634       NSEnumerator *fenum;
6635       NSString *file;
6637       if (!(files = [pb propertyListForType: type]))
6638         return NO;
6640       fenum = [files objectEnumerator];
6641       while ( (file = [fenum nextObject]) )
6642         {
6643           emacs_event->kind = NS_NONKEY_EVENT;
6644           emacs_event->code = KEY_NS_DRAG_FILE;
6645           XSETINT (emacs_event->x, x);
6646           XSETINT (emacs_event->y, y);
6647           ns_input_file = append2 (ns_input_file,
6648                                    build_string ([file UTF8String]));
6649           emacs_event->modifiers = EV_MODIFIERS (theEvent);
6650           EV_TRAILER (theEvent);
6651         }
6652       return YES;
6653     }
6654   else if ([type isEqualToString: NSURLPboardType])
6655     {
6656       NSString *file;
6657       NSURL *fileURL;
6659       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6660           [fileURL isFileURL] == NO)
6661         return NO;
6663       file = [fileURL path];
6664       emacs_event->kind = NS_NONKEY_EVENT;
6665       emacs_event->code = KEY_NS_DRAG_FILE;
6666       XSETINT (emacs_event->x, x);
6667       XSETINT (emacs_event->y, y);
6668       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6669       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6670       EV_TRAILER (theEvent);
6671       return YES;
6672     }
6673   else if ([type isEqualToString: NSStringPboardType]
6674            || [type isEqualToString: NSTabularTextPboardType])
6675     {
6676       NSString *data;
6678       if (! (data = [pb stringForType: type]))
6679         return NO;
6681       emacs_event->kind = NS_NONKEY_EVENT;
6682       emacs_event->code = KEY_NS_DRAG_TEXT;
6683       XSETINT (emacs_event->x, x);
6684       XSETINT (emacs_event->y, y);
6685       ns_input_text = build_string ([data UTF8String]);
6686       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6687       EV_TRAILER (theEvent);
6688       return YES;
6689     }
6690   else if ([type isEqualToString: NSColorPboardType])
6691     {
6692       NSColor *c = [NSColor colorFromPasteboard: pb];
6693       emacs_event->kind = NS_NONKEY_EVENT;
6694       emacs_event->code = KEY_NS_DRAG_COLOR;
6695       XSETINT (emacs_event->x, x);
6696       XSETINT (emacs_event->y, y);
6697       ns_input_color = ns_color_to_lisp (c);
6698       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6699       EV_TRAILER (theEvent);
6700       return YES;
6701     }
6702   else if ([type isEqualToString: NSFontPboardType])
6703     {
6704       /* impl based on GNUstep NSTextView.m */
6705       NSData *data = [pb dataForType: NSFontPboardType];
6706       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6707       NSFont *font = [dict objectForKey: NSFontAttributeName];
6708       char fontSize[10];
6710       if (font == nil)
6711         return NO;
6713       emacs_event->kind = NS_NONKEY_EVENT;
6714       emacs_event->code = KEY_NS_CHANGE_FONT;
6715       XSETINT (emacs_event->x, x);
6716       XSETINT (emacs_event->y, y);
6717       ns_input_font = build_string ([[font fontName] UTF8String]);
6718       snprintf (fontSize, 10, "%f", [font pointSize]);
6719       ns_input_fontsize = build_string (fontSize);
6720       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6721       EV_TRAILER (theEvent);
6722       return YES;
6723     }
6724   else
6725     {
6726       error ("Invalid data type in dragging pasteboard.");
6727       return NO;
6728     }
6732 - (id) validRequestorForSendType: (NSString *)typeSent
6733                       returnType: (NSString *)typeReturned
6735   NSTRACE (validRequestorForSendType);
6736   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6737       && typeReturned == nil)
6738     {
6739       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6740         return self;
6741     }
6743   return [super validRequestorForSendType: typeSent
6744                                returnType: typeReturned];
6748 /* The next two methods are part of NSServicesRequests informal protocol,
6749    supposedly called when a services menu item is chosen from this app.
6750    But this should not happen because we override the services menu with our
6751    own entries which call ns-perform-service.
6752    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6753    So let's at least stub them out until further investigation can be done. */
6755 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6757   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6758      be written into the buffer in place of the existing selection..
6759      ordinary service calls go through functions defined in ns-win.el */
6760   return NO;
6763 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6765   NSArray *typesDeclared;
6766   Lisp_Object val;
6768   /* We only support NSStringPboardType */
6769   if ([types containsObject:NSStringPboardType] == NO) {
6770     return NO;
6771   }
6773   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6774   if (CONSP (val) && SYMBOLP (XCAR (val)))
6775     {
6776       val = XCDR (val);
6777       if (CONSP (val) && NILP (XCDR (val)))
6778         val = XCAR (val);
6779     }
6780   if (! STRINGP (val))
6781     return NO;
6783   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6784   [pb declareTypes:typesDeclared owner:nil];
6785   ns_string_to_pasteboard (pb, val);
6786   return YES;
6790 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6791    (gives a miniaturized version of the window); currently we use the latter for
6792    frames whose active buffer doesn't correspond to any file
6793    (e.g., '*scratch*') */
6794 - setMiniwindowImage: (BOOL) setMini
6796   id image = [[self window] miniwindowImage];
6797   NSTRACE (setMiniwindowImage);
6799   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6800      about "AppleDockIconEnabled" notwithstanding, however the set message
6801      below has its effect nonetheless. */
6802   if (image != emacsframe->output_data.ns->miniimage)
6803     {
6804       if (image && [image isKindOfClass: [EmacsImage class]])
6805         [image release];
6806       [[self window] setMiniwindowImage:
6807                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6808     }
6810   return self;
6814 - (void) setRows: (int) r andColumns: (int) c
6816   rows = r;
6817   cols = c;
6820 @end  /* EmacsView */
6824 /* ==========================================================================
6826     EmacsWindow implementation
6828    ========================================================================== */
6830 @implementation EmacsWindow
6832 #ifdef NS_IMPL_COCOA
6833 - (id)accessibilityAttributeValue:(NSString *)attribute
6835   Lisp_Object str = Qnil;
6836   struct frame *f = SELECTED_FRAME ();
6837   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
6839   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6840     return NSAccessibilityTextFieldRole;
6842   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6843       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6844     {
6845       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6846     }
6847   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6848     {
6849       if (! NILP (BVAR (curbuf, mark_active)))
6850           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6852       if (NILP (str))
6853         {
6854           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6855           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6856           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6858           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6859             str = make_uninit_multibyte_string (range, byte_range);
6860           else
6861             str = make_uninit_string (range);
6862           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6863              Is this a problem?  */
6864           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6865         }
6866     }
6869   if (! NILP (str))
6870     {
6871       if (CONSP (str) && SYMBOLP (XCAR (str)))
6872         {
6873           str = XCDR (str);
6874           if (CONSP (str) && NILP (XCDR (str)))
6875             str = XCAR (str);
6876         }
6877       if (STRINGP (str))
6878         {
6879           const char *utfStr = SSDATA (str);
6880           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6881           return nsStr;
6882         }
6883     }
6885   return [super accessibilityAttributeValue:attribute];
6887 #endif /* NS_IMPL_COCOA */
6889 /* If we have multiple monitors, one above the other, we don't want to
6890    restrict the height to just one monitor.  So we override this.  */
6891 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6893   /* When making the frame visible for the first time or if there is just
6894      one screen, we want to constrain.  Other times not.  */
6895   NSUInteger nr_screens = [[NSScreen screens] count];
6896   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6897   NSTRACE (constrainFrameRect);
6899   if (nr_screens == 1)
6900     {
6901       NSRect r = [super constrainFrameRect:frameRect toScreen:screen];
6902       return r;
6903     }
6905   if (f->output_data.ns->dont_constrain
6906       || ns_menu_bar_should_be_hidden ())
6907     return frameRect;
6909   f->output_data.ns->dont_constrain = 1;
6910   return [super constrainFrameRect:frameRect toScreen:screen];
6913 @end /* EmacsWindow */
6916 @implementation EmacsFSWindow
6918 - (BOOL)canBecomeKeyWindow
6920   return YES;
6923 - (BOOL)canBecomeMainWindow
6925   return YES;
6928 @end
6930 /* ==========================================================================
6932     EmacsScroller implementation
6934    ========================================================================== */
6937 @implementation EmacsScroller
6939 /* for repeat button push */
6940 #define SCROLL_BAR_FIRST_DELAY 0.5
6941 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6943 + (CGFloat) scrollerWidth
6945   /* TODO: if we want to allow variable widths, this is the place to do it,
6946            however neither GNUstep nor Cocoa support it very well */
6947   return [NSScroller scrollerWidth];
6951 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6953   NSTRACE (EmacsScroller_initFrame);
6955   r.size.width = [EmacsScroller scrollerWidth];
6956   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6957   [self setContinuous: YES];
6958   [self setEnabled: YES];
6960   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6961      locked against the top and bottom edges, and right edge on OS X, where
6962      scrollers are on right. */
6963 #ifdef NS_IMPL_GNUSTEP
6964   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6965 #else
6966   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6967 #endif
6969   win = nwin;
6970   condemned = NO;
6971   pixel_height = NSHeight (r);
6972   if (pixel_height == 0) pixel_height = 1;
6973   min_portion = 20 / pixel_height;
6975   frame = XFRAME (XWINDOW (win)->frame);
6976   if (FRAME_LIVE_P (frame))
6977     {
6978       int i;
6979       EmacsView *view = FRAME_NS_VIEW (frame);
6980       NSView *sview = [[view window] contentView];
6981       NSArray *subs = [sview subviews];
6983       /* disable optimization stopping redraw of other scrollbars */
6984       view->scrollbarsNeedingUpdate = 0;
6985       for (i =[subs count]-1; i >= 0; i--)
6986         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6987           view->scrollbarsNeedingUpdate++;
6988       [sview addSubview: self];
6989     }
6991 /*  [self setFrame: r]; */
6993   return self;
6997 - (void)setFrame: (NSRect)newRect
6999   NSTRACE (EmacsScroller_setFrame);
7000 /*  block_input (); */
7001   pixel_height = NSHeight (newRect);
7002   if (pixel_height == 0) pixel_height = 1;
7003   min_portion = 20 / pixel_height;
7004   [super setFrame: newRect];
7005   [self display];
7006 /*  unblock_input (); */
7010 - (void)dealloc
7012   NSTRACE (EmacsScroller_dealloc);
7013   if (!NILP (win))
7014     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
7015   [super dealloc];
7019 - condemn
7021   NSTRACE (condemn);
7022   condemned =YES;
7023   return self;
7027 - reprieve
7029   NSTRACE (reprieve);
7030   condemned =NO;
7031   return self;
7035 - judge
7037   NSTRACE (judge);
7038   if (condemned)
7039     {
7040       EmacsView *view;
7041       block_input ();
7042       /* ensure other scrollbar updates after deletion */
7043       view = (EmacsView *)FRAME_NS_VIEW (frame);
7044       if (view != nil)
7045         view->scrollbarsNeedingUpdate++;
7046       [self removeFromSuperview];
7047       [self release];
7048       unblock_input ();
7049     }
7050   return self;
7054 - (void)resetCursorRects
7056   NSRect visible = [self visibleRect];
7057   NSTRACE (resetCursorRects);
7059   if (!NSIsEmptyRect (visible))
7060     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
7061   [[NSCursor arrowCursor] setOnMouseEntered: YES];
7065 - (int) checkSamePosition: (int) position portion: (int) portion
7066                     whole: (int) whole
7068   return em_position ==position && em_portion ==portion && em_whole ==whole
7069     && portion != whole; /* needed for resize empty buf */
7073 - setPosition: (int)position portion: (int)portion whole: (int)whole
7075   NSTRACE (setPosition);
7077   em_position = position;
7078   em_portion = portion;
7079   em_whole = whole;
7081   if (portion >= whole)
7082     {
7083 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
7084       [self setKnobProportion: 1.0];
7085       [self setDoubleValue: 1.0];
7086 #else
7087       [self setFloatValue: 0.0 knobProportion: 1.0];
7088 #endif
7089     }
7090   else
7091     {
7092       float pos;
7093       CGFloat por;
7094       portion = max ((float)whole*min_portion/pixel_height, portion);
7095       pos = (float)position / (whole - portion);
7096       por = (CGFloat)portion/whole;
7097 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
7098       [self setKnobProportion: por];
7099       [self setDoubleValue: pos];
7100 #else
7101       [self setFloatValue: pos knobProportion: por];
7102 #endif
7103     }
7105   /* Events may come here even if the event loop is not running.
7106      If we don't enter the event loop, the scroll bar will not update.
7107      So send SIGIO to ourselves.  */
7108   if (apploopnr == 0) raise (SIGIO);
7110   return self;
7113 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
7114      drag events will go directly to the EmacsScroller.  Leaving in for now. */
7115 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
7116                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
7118   *part = last_hit_part;
7119   *window = win;
7120   XSETINT (*y, pixel_height);
7121   if ([self floatValue] > 0.999F)
7122     XSETINT (*x, pixel_height);
7123   else
7124     XSETINT (*x, pixel_height * [self floatValue]);
7128 /* set up emacs_event */
7129 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
7131   if (!emacs_event)
7132     return;
7134   emacs_event->part = last_hit_part;
7135   emacs_event->code = 0;
7136   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
7137   emacs_event->frame_or_window = win;
7138   emacs_event->timestamp = EV_TIMESTAMP (e);
7139   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
7140   emacs_event->arg = Qnil;
7141   XSETINT (emacs_event->x, loc * pixel_height);
7142   XSETINT (emacs_event->y, pixel_height-20);
7144   if (q_event_ptr)
7145     {
7146       n_emacs_events_pending++;
7147       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7148     }
7149   else
7150     hold_event (emacs_event);
7151   EVENT_INIT (*emacs_event);
7152   ns_send_appdefined (-1);
7156 /* called manually thru timer to implement repeated button action w/hold-down */
7157 - repeatScroll: (NSTimer *)scrollEntry
7159   NSEvent *e = [[self window] currentEvent];
7160   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
7161   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7163   /* clear timer if need be */
7164   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7165     {
7166         [scroll_repeat_entry invalidate];
7167         [scroll_repeat_entry release];
7168         scroll_repeat_entry = nil;
7170         if (inKnob)
7171           return self;
7173         scroll_repeat_entry
7174           = [[NSTimer scheduledTimerWithTimeInterval:
7175                         SCROLL_BAR_CONTINUOUS_DELAY
7176                                             target: self
7177                                           selector: @selector (repeatScroll:)
7178                                           userInfo: 0
7179                                            repeats: YES]
7180               retain];
7181     }
7183   [self sendScrollEventAtLoc: 0 fromEvent: e];
7184   return self;
7188 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
7189    mouseDragged events without going into a modal loop. */
7190 - (void)mouseDown: (NSEvent *)e
7192   NSRect sr, kr;
7193   /* hitPart is only updated AFTER event is passed on */
7194   NSScrollerPart part = [self testPart: [e locationInWindow]];
7195   CGFloat inc = 0.0, loc, kloc, pos;
7196   int edge = 0;
7198   NSTRACE (EmacsScroller_mouseDown);
7200   switch (part)
7201     {
7202     case NSScrollerDecrementPage:
7203         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7204     case NSScrollerIncrementPage:
7205         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7206     case NSScrollerDecrementLine:
7207       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7208     case NSScrollerIncrementLine:
7209       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7210     case NSScrollerKnob:
7211       last_hit_part = scroll_bar_handle; break;
7212     case NSScrollerKnobSlot:  /* GNUstep-only */
7213       last_hit_part = scroll_bar_move_ratio; break;
7214     default:  /* NSScrollerNoPart? */
7215       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7216                (long) part);
7217       return;
7218     }
7220   if (inc != 0.0)
7221     {
7222       pos = 0;      /* ignored */
7224       /* set a timer to repeat, as we can't let superclass do this modally */
7225       scroll_repeat_entry
7226         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7227                                             target: self
7228                                           selector: @selector (repeatScroll:)
7229                                           userInfo: 0
7230                                            repeats: YES]
7231             retain];
7232     }
7233   else
7234     {
7235       /* handle, or on GNUstep possibly slot */
7236       NSEvent *fake_event;
7238       /* compute float loc in slot and mouse offset on knob */
7239       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7240                       toView: nil];
7241       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7242       if (loc <= 0.0)
7243         {
7244           loc = 0.0;
7245           edge = -1;
7246         }
7247       else if (loc >= NSHeight (sr))
7248         {
7249           loc = NSHeight (sr);
7250           edge = 1;
7251         }
7253       if (edge)
7254         kloc = 0.5 * edge;
7255       else
7256         {
7257           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7258                           toView: nil];
7259           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7260         }
7261       last_mouse_offset = kloc;
7263       /* if knob, tell emacs a location offset by knob pos
7264          (to indicate top of handle) */
7265       if (part == NSScrollerKnob)
7266           pos = (loc - last_mouse_offset) / NSHeight (sr);
7267       else
7268         /* else this is a slot click on GNUstep: go straight there */
7269         pos = loc / NSHeight (sr);
7271       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7272       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7273                                       location: [e locationInWindow]
7274                                  modifierFlags: [e modifierFlags]
7275                                      timestamp: [e timestamp]
7276                                   windowNumber: [e windowNumber]
7277                                        context: [e context]
7278                                    eventNumber: [e eventNumber]
7279                                     clickCount: [e clickCount]
7280                                       pressure: [e pressure]];
7281       [super mouseUp: fake_event];
7282     }
7284   if (part != NSScrollerKnob)
7285     [self sendScrollEventAtLoc: pos fromEvent: e];
7289 /* Called as we manually track scroller drags, rather than superclass. */
7290 - (void)mouseDragged: (NSEvent *)e
7292     NSRect sr;
7293     double loc, pos;
7295     NSTRACE (EmacsScroller_mouseDragged);
7297       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7298                       toView: nil];
7299       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7301       if (loc <= 0.0)
7302         {
7303           loc = 0.0;
7304         }
7305       else if (loc >= NSHeight (sr) + last_mouse_offset)
7306         {
7307           loc = NSHeight (sr) + last_mouse_offset;
7308         }
7310       pos = (loc - last_mouse_offset) / NSHeight (sr);
7311       [self sendScrollEventAtLoc: pos fromEvent: e];
7315 - (void)mouseUp: (NSEvent *)e
7317   if (scroll_repeat_entry)
7318     {
7319       [scroll_repeat_entry invalidate];
7320       [scroll_repeat_entry release];
7321       scroll_repeat_entry = nil;
7322     }
7323   last_hit_part = 0;
7327 /* treat scrollwheel events in the bar as though they were in the main window */
7328 - (void) scrollWheel: (NSEvent *)theEvent
7330   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7331   [view mouseDown: theEvent];
7334 @end  /* EmacsScroller */
7337 #ifdef NS_IMPL_GNUSTEP
7338 /* Dummy class to get rid of startup warnings.  */
7339 @implementation EmacsDocument
7341 @end
7342 #endif
7345 /* ==========================================================================
7347    Font-related functions; these used to be in nsfaces.m
7349    ========================================================================== */
7352 Lisp_Object
7353 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7355   struct font *font = XFONT_OBJECT (font_object);
7356   EmacsView *view = FRAME_NS_VIEW (f);
7358   if (fontset < 0)
7359     fontset = fontset_from_font (font_object);
7360   FRAME_FONTSET (f) = fontset;
7362   if (FRAME_FONT (f) == font)
7363     /* This font is already set in frame F.  There's nothing more to
7364        do.  */
7365     return font_object;
7367   FRAME_FONT (f) = font;
7369   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7370   FRAME_COLUMN_WIDTH (f) = font->average_width;
7371   FRAME_LINE_HEIGHT (f) = font->height;
7373   compute_fringe_widths (f, 1);
7375   /* Compute the scroll bar width in character columns.  */
7376   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7377     {
7378       int wid = FRAME_COLUMN_WIDTH (f);
7379       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7380         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7381     }
7382   else
7383     {
7384       int wid = FRAME_COLUMN_WIDTH (f);
7385       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7386     }
7388   /* Now make the frame display the given font.  */
7389   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
7390     x_set_window_size (f, 0, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
7391                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 1);
7393   return font_object;
7397 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7398 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7399          in 1.43. */
7401 const char *
7402 ns_xlfd_to_fontname (const char *xlfd)
7403 /* --------------------------------------------------------------------------
7404     Convert an X font name (XLFD) to an NS font name.
7405     Only family is used.
7406     The string returned is temporarily allocated.
7407    -------------------------------------------------------------------------- */
7409   char *name = xmalloc (180);
7410   int i, len;
7411   const char *ret;
7413   if (!strncmp (xlfd, "--", 2))
7414     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7415   else
7416     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7418   /* stopgap for malformed XLFD input */
7419   if (strlen (name) == 0)
7420     strcpy (name, "Monaco");
7422   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7423      also uppercase after '-' or ' ' */
7424   name[0] = c_toupper (name[0]);
7425   for (len =strlen (name), i =0; i<len; i++)
7426     {
7427       if (name[i] == '$')
7428         {
7429           name[i] = '-';
7430           if (i+1<len)
7431             name[i+1] = c_toupper (name[i+1]);
7432         }
7433       else if (name[i] == '_')
7434         {
7435           name[i] = ' ';
7436           if (i+1<len)
7437             name[i+1] = c_toupper (name[i+1]);
7438         }
7439     }
7440 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7441   ret = [[NSString stringWithUTF8String: name] UTF8String];
7442   xfree (name);
7443   return ret;
7447 void
7448 syms_of_nsterm (void)
7450   NSTRACE (syms_of_nsterm);
7452   ns_antialias_threshold = 10.0;
7454   /* from 23+ we need to tell emacs what modifiers there are.. */
7455   DEFSYM (Qmodifier_value, "modifier-value");
7456   DEFSYM (Qalt, "alt");
7457   DEFSYM (Qhyper, "hyper");
7458   DEFSYM (Qmeta, "meta");
7459   DEFSYM (Qsuper, "super");
7460   DEFSYM (Qcontrol, "control");
7461   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7463   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7464   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7465   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7466   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7467   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7469   DEFVAR_LISP ("ns-input-file", ns_input_file,
7470               "The file specified in the last NS event.");
7471   ns_input_file =Qnil;
7473   DEFVAR_LISP ("ns-input-text", ns_input_text,
7474               "The data received in the last NS text drag event.");
7475   ns_input_text =Qnil;
7477   DEFVAR_LISP ("ns-working-text", ns_working_text,
7478               "String for visualizing working composition sequence.");
7479   ns_working_text =Qnil;
7481   DEFVAR_LISP ("ns-input-font", ns_input_font,
7482               "The font specified in the last NS event.");
7483   ns_input_font =Qnil;
7485   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7486               "The fontsize specified in the last NS event.");
7487   ns_input_fontsize =Qnil;
7489   DEFVAR_LISP ("ns-input-line", ns_input_line,
7490                "The line specified in the last NS event.");
7491   ns_input_line =Qnil;
7493   DEFVAR_LISP ("ns-input-color", ns_input_color,
7494                "The color specified in the last NS event.");
7495   ns_input_color =Qnil;
7497   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7498                "The service name specified in the last NS event.");
7499   ns_input_spi_name =Qnil;
7501   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7502                "The service argument specified in the last NS event.");
7503   ns_input_spi_arg =Qnil;
7505   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7506                "This variable describes the behavior of the alternate or option key.\n\
7507 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7508 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7509 at all, allowing it to be used at a lower level for accented character entry.");
7510   ns_alternate_modifier = Qmeta;
7512   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7513                "This variable describes the behavior of the right alternate or option key.\n\
7514 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7515 Set to left means be the same key as `ns-alternate-modifier'.\n\
7516 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7517 at all, allowing it to be used at a lower level for accented character entry.");
7518   ns_right_alternate_modifier = Qleft;
7520   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7521                "This variable describes the behavior of the command key.\n\
7522 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7523   ns_command_modifier = Qsuper;
7525   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7526                "This variable describes the behavior of the right command key.\n\
7527 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7528 Set to left means be the same key as `ns-command-modifier'.\n\
7529 Set to none means that the command / option key is not interpreted by Emacs\n\
7530 at all, allowing it to be used at a lower level for accented character entry.");
7531   ns_right_command_modifier = Qleft;
7533   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7534                "This variable describes the behavior of the control key.\n\
7535 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7536   ns_control_modifier = Qcontrol;
7538   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7539                "This variable describes the behavior of the right control key.\n\
7540 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7541 Set to left means be the same key as `ns-control-modifier'.\n\
7542 Set to none means that the control / option key is not interpreted by Emacs\n\
7543 at all, allowing it to be used at a lower level for accented character entry.");
7544   ns_right_control_modifier = Qleft;
7546   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7547                "This variable describes the behavior of the function key (on laptops).\n\
7548 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7549 Set to none means that the function key is not interpreted by Emacs at all,\n\
7550 allowing it to be used at a lower level for accented character entry.");
7551   ns_function_modifier = Qnone;
7553   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7554                "Non-nil (the default) means to render text antialiased.");
7555   ns_antialias_text = Qt;
7557   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7558                "Whether to confirm application quit using dialog.");
7559   ns_confirm_quit = Qnil;
7561   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7562                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7563 Only works on OSX 10.6 or later.  */);
7564   ns_auto_hide_menu_bar = Qnil;
7566   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7567      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7568 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7569 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7570 Default is t for OSX >= 10.7, nil otherwise. */);
7571 #ifdef HAVE_NATIVE_FS
7572   ns_use_native_fullscreen = YES;
7573 #else
7574   ns_use_native_fullscreen = NO;
7575 #endif
7576   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7578   /* TODO: move to common code */
7579   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7580                doc: /* Which toolkit scroll bars Emacs uses, if any.
7581 A value of nil means Emacs doesn't use toolkit scroll bars.
7582 With the X Window system, the value is a symbol describing the
7583 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7584 With MS Windows or Nextstep, the value is t.  */);
7585   Vx_toolkit_scroll_bars = Qt;
7587   DEFVAR_BOOL ("x-use-underline-position-properties",
7588                x_use_underline_position_properties,
7589      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7590 A value of nil means ignore them.  If you encounter fonts with bogus
7591 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7592 to 4.1, set this to nil. */);
7593   x_use_underline_position_properties = 0;
7595   DEFVAR_BOOL ("x-underline-at-descent-line",
7596                x_underline_at_descent_line,
7597      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7598 A value of nil means to draw the underline according to the value of the
7599 variable `x-use-underline-position-properties', which is usually at the
7600 baseline level.  The default value is nil.  */);
7601   x_underline_at_descent_line = 0;
7603   /* Tell Emacs about this window system.  */
7604   Fprovide (Qns, Qnil);
7606   DEFSYM (Qcocoa, "cocoa");
7607   DEFSYM (Qgnustep, "gnustep");
7609   syms_of_nsfont ();
7610 #ifdef NS_IMPL_COCOA
7611   Fprovide (Qcocoa, Qnil);
7612 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
7613   syms_of_macfont ();
7614 #endif
7615 #else
7616   Fprovide (Qgnustep, Qnil);
7617 #endif