Install the actual changes missing in previous revision
[emacs.git] / src / nsterm.m
blobe58ac9b927780f5f8be9c4c7260e469fe8bd2af3
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, int change_grav, int cols, int rows, bool pixelwise)
1244 /* --------------------------------------------------------------------------
1245      Adjust window pixel size based on given character grid size
1246      Impl is a bit more complex than other terms, need to do some
1247      internal clipping.
1248    -------------------------------------------------------------------------- */
1250   EmacsView *view = FRAME_NS_VIEW (f);
1251   NSWindow *window = [view window];
1252   NSRect wr = [window frame];
1253   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1254   int pixelwidth, pixelheight;
1256   NSTRACE (x_set_window_size);
1258   if (view == nil)
1259     return;
1261 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1263   block_input ();
1265   check_frame_size (f, &cols, &rows, 0);
1267   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1268   compute_fringe_widths (f, 0);
1270   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1271   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1273   /* If we have a toolbar, take its height into account. */
1274   if (tb && ! [view isFullscreen])
1275     {
1276     /* NOTE: previously this would generate wrong result if toolbar not
1277              yet displayed and fixing toolbar_height=32 helped, but
1278              now (200903) seems no longer needed */
1279     FRAME_TOOLBAR_HEIGHT (f) =
1280       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1281         - FRAME_NS_TITLEBAR_HEIGHT (f);
1282 #ifdef NS_IMPL_GNUSTEP
1283       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1284 #endif
1285     }
1286   else
1287     FRAME_TOOLBAR_HEIGHT (f) = 0;
1289   wr.size.width = pixelwidth + f->border_width;
1290   wr.size.height = pixelheight;
1291   if (! [view isFullscreen])
1292     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1293       + FRAME_TOOLBAR_HEIGHT (f);
1295   /* Do not try to constrain to this screen.  We may have multiple
1296      screens, and want Emacs to span those.  Constraining to screen
1297      prevents that, and that is not nice to the user.  */
1298  if (f->output_data.ns->zooming)
1299    f->output_data.ns->zooming = 0;
1300  else
1301    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1303   [view setRows: rows andColumns: cols];
1304   [window setFrame: wr display: YES];
1306 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1308   /* This is a trick to compensate for Emacs' managing the scrollbar area
1309      as a fixed number of standard character columns.  Instead of leaving
1310      blank space for the extra, we chopped it off above.  Now for
1311      left-hand scrollbars, we shift all rendering to the left by the
1312      difference between the real width and Emacs' imagined one.  For
1313      right-hand bars, don't worry about it since the extra is never used.
1314      (Obviously doesn't work for vertically split windows tho..) */
1315   {
1316     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1317       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1318                      - NS_SCROLL_BAR_WIDTH (f), 0)
1319       : NSMakePoint (0, 0);
1320     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1321     [view setBoundsOrigin: origin];
1322   }
1324   change_frame_size (f, cols, rows, 0, 1, 0, 0); /* pretend, delay, safe */
1325   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1326   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1327 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1329   mark_window_cursors_off (XWINDOW (f->root_window));
1330   cancel_mouse_face (f);
1332   unblock_input ();
1336 static void
1337 ns_fullscreen_hook (struct frame *f)
1339   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1341   if (!FRAME_VISIBLE_P (f))
1342     return;
1344    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1345     {
1346       /* Old style fs don't initiate correctly if created from
1347          init/default-frame alist, so use a timer (not nice...).
1348       */
1349       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1350                                      selector: @selector (handleFS)
1351                                      userInfo: nil repeats: NO];
1352       return;
1353     }
1355   block_input ();
1356   [view handleFS];
1357   unblock_input ();
1360 /* ==========================================================================
1362     Color management
1364    ========================================================================== */
1367 NSColor *
1368 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1370   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1371   if (idx < 1 || idx >= color_table->avail)
1372     return nil;
1373   return color_table->colors[idx];
1377 unsigned long
1378 ns_index_color (NSColor *color, struct frame *f)
1380   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1381   ptrdiff_t idx;
1382   ptrdiff_t i;
1384   if (!color_table->colors)
1385     {
1386       color_table->size = NS_COLOR_CAPACITY;
1387       color_table->avail = 1; /* skip idx=0 as marker */
1388       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1389       color_table->colors[0] = nil;
1390       color_table->empty_indices = [[NSMutableSet alloc] init];
1391     }
1393   /* Do we already have this color?  */
1394   for (i = 1; i < color_table->avail; i++)
1395     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1396       return i;
1398   if ([color_table->empty_indices count] > 0)
1399     {
1400       NSNumber *index = [color_table->empty_indices anyObject];
1401       [color_table->empty_indices removeObject: index];
1402       idx = [index unsignedLongValue];
1403     }
1404   else
1405     {
1406       if (color_table->avail == color_table->size)
1407         color_table->colors =
1408           xpalloc (color_table->colors, &color_table->size, 1,
1409                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1410       idx = color_table->avail++;
1411     }
1413   color_table->colors[idx] = color;
1414   [color retain];
1415 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1416   return idx;
1420 void
1421 ns_free_indexed_color (unsigned long idx, struct frame *f)
1423   struct ns_color_table *color_table;
1424   NSColor *color;
1425   NSNumber *index;
1427   if (!f)
1428     return;
1430   color_table = FRAME_DISPLAY_INFO (f)->color_table;
1432   if (idx <= 0 || idx >= color_table->size) {
1433     message1 ("ns_free_indexed_color: Color index out of range.\n");
1434     return;
1435   }
1437   index = [NSNumber numberWithUnsignedInt: idx];
1438   if ([color_table->empty_indices containsObject: index]) {
1439     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1440     return;
1441   }
1443   color = color_table->colors[idx];
1444   [color release];
1445   color_table->colors[idx] = nil;
1446   [color_table->empty_indices addObject: index];
1447 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1451 static int
1452 ns_get_color (const char *name, NSColor **col)
1453 /* --------------------------------------------------------------------------
1454      Parse a color name
1455    -------------------------------------------------------------------------- */
1456 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1457    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1458    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1460   NSColor *new = nil;
1461   static char hex[20];
1462   int scaling;
1463   float r = -1.0, g, b;
1464   NSString *nsname = [NSString stringWithUTF8String: name];
1466 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1467   block_input ();
1469   if ([nsname isEqualToString: @"ns_selection_bg_color"])
1470     {
1471 #ifdef NS_IMPL_COCOA
1472       NSString *defname = [[NSUserDefaults standardUserDefaults]
1473                             stringForKey: @"AppleHighlightColor"];
1474       if (defname != nil)
1475         nsname = defname;
1476       else
1477 #endif
1478       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1479         {
1480           *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1481           unblock_input ();
1482           return 0;
1483         }
1484       else
1485         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1487       name = [nsname UTF8String];
1488     }
1489   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1490     {
1491       /* NOTE: OSX applications normally don't set foreground selection, but
1492          text may be unreadable if we don't.
1493       */
1494       if ((new = [NSColor selectedTextColor]) != nil)
1495         {
1496           *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1497           unblock_input ();
1498           return 0;
1499         }
1501       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1502       name = [nsname UTF8String];
1503     }
1505   /* First, check for some sort of numeric specification. */
1506   hex[0] = '\0';
1508   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1509     {
1510       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1511       [scanner scanFloat: &r];
1512       [scanner scanFloat: &g];
1513       [scanner scanFloat: &b];
1514     }
1515   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1516     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1517   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1518     {
1519       int len = (strlen(name) - 1);
1520       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1521       int i;
1522       scaling = strlen(name+start) / 3;
1523       for (i = 0; i < 3; i++)
1524         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1525                  name + start + i * scaling);
1526       hex[3 * (scaling + 1) - 1] = '\0';
1527     }
1529   if (hex[0])
1530     {
1531       int rr, gg, bb;
1532       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1533       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1534         {
1535           r = rr / fscale;
1536           g = gg / fscale;
1537           b = bb / fscale;
1538         }
1539     }
1541   if (r >= 0.0F)
1542     {
1543       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1544       unblock_input ();
1545       return 0;
1546     }
1548   /* Otherwise, color is expected to be from a list */
1549   {
1550     NSEnumerator *lenum, *cenum;
1551     NSString *name;
1552     NSColorList *clist;
1554 #ifdef NS_IMPL_GNUSTEP
1555     /* XXX: who is wrong, the requestor or the implementation? */
1556     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1557         == NSOrderedSame)
1558       nsname = @"highlightColor";
1559 #endif
1561     lenum = [[NSColorList availableColorLists] objectEnumerator];
1562     while ( (clist = [lenum nextObject]) && new == nil)
1563       {
1564         cenum = [[clist allKeys] objectEnumerator];
1565         while ( (name = [cenum nextObject]) && new == nil )
1566           {
1567             if ([name compare: nsname
1568                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1569               new = [clist colorWithKey: name];
1570           }
1571       }
1572   }
1574   if (new)
1575     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1576   unblock_input ();
1577   return new ? 0 : 1;
1582 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1583 /* --------------------------------------------------------------------------
1584      Convert a Lisp string object to a NS color
1585    -------------------------------------------------------------------------- */
1587   NSTRACE (ns_lisp_to_color);
1588   if (STRINGP (color))
1589     return ns_get_color (SSDATA (color), col);
1590   else if (SYMBOLP (color))
1591     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1592   return 1;
1596 Lisp_Object
1597 ns_color_to_lisp (NSColor *col)
1598 /* --------------------------------------------------------------------------
1599      Convert a color to a lisp string with the RGB equivalent
1600    -------------------------------------------------------------------------- */
1602   EmacsCGFloat red, green, blue, alpha, gray;
1603   char buf[1024];
1604   const char *str;
1605   NSTRACE (ns_color_to_lisp);
1607   block_input ();
1608   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1610       if ((str =[[col colorNameComponent] UTF8String]))
1611         {
1612           unblock_input ();
1613           return build_string ((char *)str);
1614         }
1616     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1617         getRed: &red green: &green blue: &blue alpha: &alpha];
1618   if (red ==green && red ==blue)
1619     {
1620       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1621             getWhite: &gray alpha: &alpha];
1622       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1623                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1624       unblock_input ();
1625       return build_string (buf);
1626     }
1628   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1629             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1631   unblock_input ();
1632   return build_string (buf);
1636 void
1637 ns_query_color(void *col, XColor *color_def, int setPixel)
1638 /* --------------------------------------------------------------------------
1639          Get ARGB values out of NSColor col and put them into color_def.
1640          If setPixel, set the pixel to a concatenated version.
1641          and set color_def pixel to the resulting index.
1642    -------------------------------------------------------------------------- */
1644   EmacsCGFloat r, g, b, a;
1646   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1647   color_def->red   = r * 65535;
1648   color_def->green = g * 65535;
1649   color_def->blue  = b * 65535;
1651   if (setPixel == YES)
1652     color_def->pixel
1653       = ARGB_TO_ULONG((int)(a*255),
1654                       (int)(r*255), (int)(g*255), (int)(b*255));
1658 bool
1659 ns_defined_color (struct frame *f,
1660                   const char *name,
1661                   XColor *color_def,
1662                   bool alloc,
1663                   bool makeIndex)
1664 /* --------------------------------------------------------------------------
1665          Return true if named color found, and set color_def rgb accordingly.
1666          If makeIndex and alloc are nonzero put the color in the color_table,
1667          and set color_def pixel to the resulting index.
1668          If makeIndex is zero, set color_def pixel to ARGB.
1669          Return false if not found
1670    -------------------------------------------------------------------------- */
1672   NSColor *col;
1673   NSTRACE (ns_defined_color);
1675   block_input ();
1676   if (ns_get_color (name, &col) != 0) /* Color not found  */
1677     {
1678       unblock_input ();
1679       return 0;
1680     }
1681   if (makeIndex && alloc)
1682     color_def->pixel = ns_index_color (col, f);
1683   ns_query_color (col, color_def, !makeIndex);
1684   unblock_input ();
1685   return 1;
1689 void
1690 x_set_frame_alpha (struct frame *f)
1691 /* --------------------------------------------------------------------------
1692      change the entire-frame transparency
1693    -------------------------------------------------------------------------- */
1695   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1696   double alpha = 1.0;
1697   double alpha_min = 1.0;
1699   if (dpyinfo->x_highlight_frame == f)
1700     alpha = f->alpha[0];
1701   else
1702     alpha = f->alpha[1];
1704   if (FLOATP (Vframe_alpha_lower_limit))
1705     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1706   else if (INTEGERP (Vframe_alpha_lower_limit))
1707     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1709   if (alpha < 0.0)
1710     return;
1711   else if (1.0 < alpha)
1712     alpha = 1.0;
1713   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1714     alpha = alpha_min;
1716 #ifdef NS_IMPL_COCOA
1717   {
1718     EmacsView *view = FRAME_NS_VIEW (f);
1719   [[view window] setAlphaValue: alpha];
1720   }
1721 #endif
1725 /* ==========================================================================
1727     Mouse handling
1729    ========================================================================== */
1732 void
1733 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1734 /* --------------------------------------------------------------------------
1735      Programmatically reposition mouse pointer in pixel coordinates
1736    -------------------------------------------------------------------------- */
1738   NSTRACE (x_set_mouse_pixel_position);
1739   ns_raise_frame (f);
1740 #if 0
1741   /* FIXME: this does not work, and what about GNUstep? */
1742 #ifdef NS_IMPL_COCOA
1743   [FRAME_NS_VIEW (f) lockFocus];
1744   PSsetmouse ((float)pix_x, (float)pix_y);
1745   [FRAME_NS_VIEW (f) unlockFocus];
1746 #endif
1747 #endif
1751 void
1752 x_set_mouse_position (struct frame *f, int h, int v)
1753 /* --------------------------------------------------------------------------
1754      Programmatically reposition mouse pointer in character coordinates
1755    -------------------------------------------------------------------------- */
1757   int pix_x, pix_y;
1759   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1760   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1762   if (pix_x < 0) pix_x = 0;
1763   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1765   if (pix_y < 0) pix_y = 0;
1766   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1768   x_set_mouse_pixel_position (f, pix_x, pix_y);
1772 static int
1773 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1774 /*   ------------------------------------------------------------------------
1775      Called by EmacsView on mouseMovement events.  Passes on
1776      to emacs mainstream code if we moved off of a rect of interest
1777      known as last_mouse_glyph.
1778      ------------------------------------------------------------------------ */
1780   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1781   NSRect *r;
1783 //  NSTRACE (note_mouse_movement);
1785   dpyinfo->last_mouse_motion_frame = frame;
1786   r = &dpyinfo->last_mouse_glyph;
1788   /* Note, this doesn't get called for enter/leave, since we don't have a
1789      position.  Those are taken care of in the corresponding NSView methods. */
1791   /* has movement gone beyond last rect we were tracking? */
1792   if (x < r->origin.x || x >= r->origin.x + r->size.width
1793       || y < r->origin.y || y >= r->origin.y + r->size.height)
1794     {
1795       ns_update_begin (frame);
1796       frame->mouse_moved = 1;
1797       note_mouse_highlight (frame, x, y);
1798       remember_mouse_glyph (frame, x, y, r);
1799       ns_update_end (frame);
1800       return 1;
1801     }
1803   return 0;
1807 static void
1808 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1809                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1810                    Time *time)
1811 /* --------------------------------------------------------------------------
1812     External (hook): inform emacs about mouse position and hit parts.
1813     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1814     x & y should be position in the scrollbar (the whole bar, not the handle)
1815     and length of scrollbar respectively
1816    -------------------------------------------------------------------------- */
1818   id view;
1819   NSPoint position;
1820   Lisp_Object frame, tail;
1821   struct frame *f;
1822   struct ns_display_info *dpyinfo;
1824   NSTRACE (ns_mouse_position);
1826   if (*fp == NULL)
1827     {
1828       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1829       return;
1830     }
1832   dpyinfo = FRAME_DISPLAY_INFO (*fp);
1834   block_input ();
1836   if (dpyinfo->last_mouse_scroll_bar != nil && insist == 0)
1837     {
1838       /* TODO: we do not use this path at the moment because drag events will
1839            go directly to the EmacsScroller.  Leaving code in for now. */
1840       [dpyinfo->last_mouse_scroll_bar
1841           getMouseMotionPart: (int *)part window: bar_window x: x y: y];
1842       if (time)
1843         *time = dpyinfo->last_mouse_movement_time;
1844       dpyinfo->last_mouse_scroll_bar = nil;
1845     }
1846   else
1847     {
1848       /* Clear the mouse-moved flag for every frame on this display.  */
1849       FOR_EACH_FRAME (tail, frame)
1850         if (FRAME_NS_P (XFRAME (frame))
1851             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1852           XFRAME (frame)->mouse_moved = 0;
1854       dpyinfo->last_mouse_scroll_bar = nil;
1855       if (dpyinfo->last_mouse_frame
1856           && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
1857         f = dpyinfo->last_mouse_frame;
1858       else
1859         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1860                                     : SELECTED_FRAME ();
1862       if (f && FRAME_NS_P (f))
1863         {
1864           view = FRAME_NS_VIEW (*fp);
1866           position = [[view window] mouseLocationOutsideOfEventStream];
1867           position = [view convertPoint: position fromView: nil];
1868           remember_mouse_glyph (f, position.x, position.y,
1869                                 &dpyinfo->last_mouse_glyph);
1870 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1872           if (bar_window) *bar_window = Qnil;
1873           if (part) *part = 0; /*scroll_bar_handle; */
1875           if (x) XSETINT (*x, lrint (position.x));
1876           if (y) XSETINT (*y, lrint (position.y));
1877           if (time)
1878             *time = dpyinfo->last_mouse_movement_time;
1879           *fp = f;
1880         }
1881     }
1883   unblock_input ();
1887 static void
1888 ns_frame_up_to_date (struct frame *f)
1889 /* --------------------------------------------------------------------------
1890     External (hook): Fix up mouse highlighting right after a full update.
1891     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1892    -------------------------------------------------------------------------- */
1894   NSTRACE (ns_frame_up_to_date);
1896   if (FRAME_NS_P (f))
1897     {
1898       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1899       if (f == hlinfo->mouse_face_mouse_frame)
1900         {
1901           block_input ();
1902           ns_update_begin(f);
1903           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1904                                 hlinfo->mouse_face_mouse_x,
1905                                 hlinfo->mouse_face_mouse_y);
1906           ns_update_end(f);
1907           unblock_input ();
1908         }
1909     }
1913 static void
1914 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1915 /* --------------------------------------------------------------------------
1916     External (RIF): set frame mouse pointer type.
1917    -------------------------------------------------------------------------- */
1919   NSTRACE (ns_define_frame_cursor);
1920   if (FRAME_POINTER_TYPE (f) != cursor)
1921     {
1922       EmacsView *view = FRAME_NS_VIEW (f);
1923       FRAME_POINTER_TYPE (f) = cursor;
1924       [[view window] invalidateCursorRectsForView: view];
1925       /* Redisplay assumes this function also draws the changed frame
1926          cursor, but this function doesn't, so do it explicitly.  */
1927       x_update_cursor (f, 1);
1928     }
1933 /* ==========================================================================
1935     Keyboard handling
1937    ========================================================================== */
1940 static unsigned
1941 ns_convert_key (unsigned code)
1942 /* --------------------------------------------------------------------------
1943     Internal call used by NSView-keyDown.
1944    -------------------------------------------------------------------------- */
1946   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1947                                 / sizeof (convert_ns_to_X_keysym[0]));
1948   unsigned keysym;
1949   /* An array would be faster, but less easy to read. */
1950   for (keysym = 0; keysym < last_keysym; keysym += 2)
1951     if (code == convert_ns_to_X_keysym[keysym])
1952       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1953   return 0;
1954 /* if decide to use keyCode and Carbon table, use this line:
1955      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1959 char *
1960 x_get_keysym_name (int keysym)
1961 /* --------------------------------------------------------------------------
1962     Called by keyboard.c.  Not sure if the return val is important, except
1963     that it be unique.
1964    -------------------------------------------------------------------------- */
1966   static char value[16];
1967   NSTRACE (x_get_keysym_name);
1968   sprintf (value, "%d", keysym);
1969   return value;
1974 /* ==========================================================================
1976     Block drawing operations
1978    ========================================================================== */
1981 static void
1982 ns_redraw_scroll_bars (struct frame *f)
1984   int i;
1985   id view;
1986   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1987   NSTRACE (ns_redraw_scroll_bars);
1988   for (i =[subviews count]-1; i >= 0; i--)
1989     {
1990       view = [subviews objectAtIndex: i];
1991       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1992       [view display];
1993     }
1997 void
1998 ns_clear_frame (struct frame *f)
1999 /* --------------------------------------------------------------------------
2000       External (hook): Erase the entire frame
2001    -------------------------------------------------------------------------- */
2003   NSView *view = FRAME_NS_VIEW (f);
2004   NSRect r;
2006   NSTRACE (ns_clear_frame);
2008  /* comes on initial frame because we have
2009     after-make-frame-functions = select-frame */
2010  if (!FRAME_DEFAULT_FACE (f))
2011    return;
2013   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2015   r = [view bounds];
2017   block_input ();
2018   ns_focus (f, &r, 1);
2019   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2020   NSRectFill (r);
2021   ns_unfocus (f);
2023   /* as of 2006/11 or so this is now needed */
2024   ns_redraw_scroll_bars (f);
2025   unblock_input ();
2029 static void
2030 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2031 /* --------------------------------------------------------------------------
2032     External (RIF):  Clear section of frame
2033    -------------------------------------------------------------------------- */
2035   NSRect r = NSMakeRect (x, y, width, height);
2036   NSView *view = FRAME_NS_VIEW (f);
2037   struct face *face = FRAME_DEFAULT_FACE (f);
2039   if (!view || !face)
2040     return;
2042   NSTRACE (ns_clear_frame_area);
2044   r = NSIntersectionRect (r, [view frame]);
2045   ns_focus (f, &r, 1);
2046   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2048   NSRectFill (r);
2050   ns_unfocus (f);
2051   return;
2055 static void
2056 ns_scroll_run (struct window *w, struct run *run)
2057 /* --------------------------------------------------------------------------
2058     External (RIF):  Insert or delete n lines at line vpos
2059    -------------------------------------------------------------------------- */
2061   struct frame *f = XFRAME (w->frame);
2062   int x, y, width, height, from_y, to_y, bottom_y;
2064   NSTRACE (ns_scroll_run);
2066   /* begin copy from other terms */
2067   /* Get frame-relative bounding box of the text display area of W,
2068      without mode lines.  Include in this box the left and right
2069      fringe of W.  */
2070   window_box (w, ANY_AREA, &x, &y, &width, &height);
2072   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2073   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2074   bottom_y = y + height;
2076   if (to_y < from_y)
2077     {
2078       /* Scrolling up.  Make sure we don't copy part of the mode
2079          line at the bottom.  */
2080       if (from_y + run->height > bottom_y)
2081         height = bottom_y - from_y;
2082       else
2083         height = run->height;
2084     }
2085   else
2086     {
2087       /* Scrolling down.  Make sure we don't copy over the mode line.
2088          at the bottom.  */
2089       if (to_y + run->height > bottom_y)
2090         height = bottom_y - to_y;
2091       else
2092         height = run->height;
2093     }
2094   /* end copy from other terms */
2096   if (height == 0)
2097       return;
2099   block_input ();
2101   x_clear_cursor (w);
2103   {
2104     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2105     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2106     NSPoint dstOrigin = NSMakePoint (x, to_y);
2108     ns_focus (f, &dstRect, 1);
2109     NSCopyBits (0, srcRect , dstOrigin);
2110     ns_unfocus (f);
2111   }
2113   unblock_input ();
2117 static void
2118 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2119 /* --------------------------------------------------------------------------
2120     External (RIF): preparatory to fringe update after text was updated
2121    -------------------------------------------------------------------------- */
2123   struct frame *f;
2124   int width, height;
2126   NSTRACE (ns_after_update_window_line);
2128   /* begin copy from other terms */
2129   eassert (w);
2131   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2132     desired_row->redraw_fringe_bitmaps_p = 1;
2134   /* When a window has disappeared, make sure that no rest of
2135      full-width rows stays visible in the internal border.  */
2136   if (windows_or_buffers_changed
2137       && desired_row->full_width_p
2138       && (f = XFRAME (w->frame),
2139           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2140           width != 0)
2141       && (height = desired_row->visible_height,
2142           height > 0))
2143     {
2144       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2146       block_input ();
2147       ns_clear_frame_area (f, 0, y, width, height);
2148       ns_clear_frame_area (f,
2149                            FRAME_PIXEL_WIDTH (f) - width,
2150                            y, width, height);
2151       unblock_input ();
2152     }
2156 static void
2157 ns_shift_glyphs_for_insert (struct frame *f,
2158                            int x, int y, int width, int height,
2159                            int shift_by)
2160 /* --------------------------------------------------------------------------
2161     External (RIF): copy an area horizontally, don't worry about clearing src
2162    -------------------------------------------------------------------------- */
2164   NSRect srcRect = NSMakeRect (x, y, width, height);
2165   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2166   NSPoint dstOrigin = dstRect.origin;
2168   NSTRACE (ns_shift_glyphs_for_insert);
2170   ns_focus (f, &dstRect, 1);
2171   NSCopyBits (0, srcRect, dstOrigin);
2172   ns_unfocus (f);
2177 /* ==========================================================================
2179     Character encoding and metrics
2181    ========================================================================== */
2184 static void
2185 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2186 /* --------------------------------------------------------------------------
2187      External (RIF); compute left/right overhang of whole string and set in s
2188    -------------------------------------------------------------------------- */
2190   struct font *font = s->font;
2192   if (s->char2b)
2193     {
2194       struct font_metrics metrics;
2195       unsigned int codes[2];
2196       codes[0] = *(s->char2b);
2197       codes[1] = *(s->char2b + s->nchars - 1);
2199       font->driver->text_extents (font, codes, 2, &metrics);
2200       s->left_overhang = -metrics.lbearing;
2201       s->right_overhang
2202         = metrics.rbearing > metrics.width
2203         ? metrics.rbearing - metrics.width : 0;
2204     }
2205   else
2206     {
2207       s->left_overhang = 0;
2208       if (EQ (font->driver->type, Qns))
2209         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2210           FONT_HEIGHT (font) * 0.2 : 0;
2211       else
2212         s->right_overhang = 0;
2213     }
2218 /* ==========================================================================
2220     Fringe and cursor drawing
2222    ========================================================================== */
2225 extern int max_used_fringe_bitmap;
2226 static void
2227 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2228                       struct draw_fringe_bitmap_params *p)
2229 /* --------------------------------------------------------------------------
2230     External (RIF); fringe-related
2231    -------------------------------------------------------------------------- */
2233   struct frame *f = XFRAME (WINDOW_FRAME (w));
2234   struct face *face = p->face;
2235   static EmacsImage **bimgs = NULL;
2236   static int nBimgs = 0;
2238   /* grow bimgs if needed */
2239   if (nBimgs < max_used_fringe_bitmap)
2240     {
2241       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2242       memset (bimgs + nBimgs, 0,
2243               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2244       nBimgs = max_used_fringe_bitmap;
2245     }
2247   /* Must clip because of partially visible lines.  */
2248   ns_clip_to_row (w, row, ANY_AREA, YES);
2250   if (!p->overlay_p)
2251     {
2252       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2254       /* If the fringe is adjacent to the left (right) scroll bar of a
2255          leftmost (rightmost, respectively) window, then extend its
2256          background to the gap between the fringe and the bar.  */
2257       if ((WINDOW_LEFTMOST_P (w)
2258            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2259           || (WINDOW_RIGHTMOST_P (w)
2260               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2261         {
2262           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2264           if (sb_width > 0)
2265             {
2266               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2267               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2268                                     * FRAME_COLUMN_WIDTH (f));
2270               if (bx < 0)
2271                 {
2272                   /* Bitmap fills the fringe.  */
2273                   if (bar_area_x + bar_area_width == p->x)
2274                     bx = bar_area_x + sb_width;
2275                   else if (p->x + p->wd == bar_area_x)
2276                     bx = bar_area_x;
2277                   if (bx >= 0)
2278                     {
2279                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2281                       nx = bar_area_width - sb_width;
2282                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2283                                                             row->y));
2284                       ny = row->visible_height;
2285                     }
2286                 }
2287               else
2288                 {
2289                   if (bar_area_x + bar_area_width == bx)
2290                     {
2291                       bx = bar_area_x + sb_width;
2292                       nx += bar_area_width - sb_width;
2293                     }
2294                   else if (bx + nx == bar_area_x)
2295                     nx += bar_area_width - sb_width;
2296                 }
2297             }
2298         }
2300       if (bx >= 0 && nx > 0)
2301         {
2302           NSRect r = NSMakeRect (bx, by, nx, ny);
2303           NSRectClip (r);
2304           [ns_lookup_indexed_color (face->background, f) set];
2305           NSRectFill (r);
2306         }
2307     }
2309   if (p->which)
2310     {
2311       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2312       EmacsImage *img = bimgs[p->which - 1];
2314       if (!img)
2315         {
2316           unsigned short *bits = p->bits + p->dh;
2317           int len = p->h;
2318           int i;
2319           unsigned char *cbits = xmalloc (len);
2321           for (i = 0; i < len; i++)
2322             cbits[i] = ~(bits[i] & 0xff);
2323           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2324                                            flip: NO];
2325           bimgs[p->which - 1] = img;
2326           xfree (cbits);
2327         }
2329       NSRectClip (r);
2330       /* Since we composite the bitmap instead of just blitting it, we need
2331          to erase the whole background. */
2332       [ns_lookup_indexed_color(face->background, f) set];
2333       NSRectFill (r);
2334       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2335 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2336       [img drawInRect: r
2337               fromRect: NSZeroRect
2338              operation: NSCompositeSourceOver
2339               fraction: 1.0
2340            respectFlipped: YES
2341                 hints: nil];
2342 #else
2343       {
2344         NSPoint pt = r.origin;
2345         pt.y += p->h;
2346         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2347       }
2348 #endif
2349     }
2350   ns_unfocus (f);
2354 static void
2355 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2356                        int x, int y, enum text_cursor_kinds cursor_type,
2357                        int cursor_width, bool on_p, bool active_p)
2358 /* --------------------------------------------------------------------------
2359      External call (RIF): draw cursor.
2360      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2361    -------------------------------------------------------------------------- */
2363   NSRect r, s;
2364   int fx, fy, h, cursor_height;
2365   struct frame *f = WINDOW_XFRAME (w);
2366   struct glyph *phys_cursor_glyph;
2367   struct glyph *cursor_glyph;
2368   struct face *face;
2369   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2371   /* If cursor is out of bounds, don't draw garbage.  This can happen
2372      in mini-buffer windows when switching between echo area glyphs
2373      and mini-buffer.  */
2375   NSTRACE (dumpcursor);
2377   if (!on_p)
2378     return;
2380   w->phys_cursor_type = cursor_type;
2381   w->phys_cursor_on_p = on_p;
2383   if (cursor_type == NO_CURSOR)
2384     {
2385       w->phys_cursor_width = 0;
2386       return;
2387     }
2389   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2390     {
2391       if (glyph_row->exact_window_width_line_p
2392           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2393         {
2394           glyph_row->cursor_in_fringe_p = 1;
2395           draw_fringe_bitmap (w, glyph_row, 0);
2396         }
2397       return;
2398     }
2400   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2401      (other terminals do it the other way round).  We must set
2402      w->phys_cursor_width to the cursor width.  For bar cursors, that
2403      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2404   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2406   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2407      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2408   if (cursor_type == BAR_CURSOR)
2409     {
2410       if (cursor_width < 1)
2411         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2412       w->phys_cursor_width = cursor_width;
2413     }
2414   /* If we have an HBAR, "cursor_width" MAY specify height. */
2415   else if (cursor_type == HBAR_CURSOR)
2416     {
2417       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2418       fy += h - cursor_height;
2419       h = cursor_height;
2420     }
2422   r.origin.x = fx, r.origin.y = fy;
2423   r.size.height = h;
2424   r.size.width = w->phys_cursor_width;
2426   /* TODO: only needed in rare cases with last-resort font in HELLO..
2427      should we do this more efficiently? */
2428   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2431   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2432   if (face && NS_FACE_BACKGROUND (face)
2433       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2434     {
2435       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2436       hollow_color = FRAME_CURSOR_COLOR (f);
2437     }
2438   else
2439     [FRAME_CURSOR_COLOR (f) set];
2441 #ifdef NS_IMPL_COCOA
2442   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2443            atomic.  Cleaner ways of doing this should be investigated.
2444            One way would be to set a global variable DRAWING_CURSOR
2445            when making the call to draw_phys..(), don't focus in that
2446            case, then move the ns_unfocus() here after that call. */
2447   NSDisableScreenUpdates ();
2448 #endif
2450   switch (cursor_type)
2451     {
2452     case NO_CURSOR:
2453       break;
2454     case FILLED_BOX_CURSOR:
2455       NSRectFill (r);
2456       break;
2457     case HOLLOW_BOX_CURSOR:
2458       NSRectFill (r);
2459       [hollow_color set];
2460       NSRectFill (NSInsetRect (r, 1, 1));
2461       [FRAME_CURSOR_COLOR (f) set];
2462       break;
2463     case HBAR_CURSOR:
2464       NSRectFill (r);
2465       break;
2466     case BAR_CURSOR:
2467       s = r;
2468       /* If the character under cursor is R2L, draw the bar cursor
2469          on the right of its glyph, rather than on the left.  */
2470       cursor_glyph = get_phys_cursor_glyph (w);
2471       if ((cursor_glyph->resolved_level & 1) != 0)
2472         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2474       NSRectFill (s);
2475       break;
2476     }
2477   ns_unfocus (f);
2479   /* draw the character under the cursor */
2480   if (cursor_type != NO_CURSOR)
2481     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2483 #ifdef NS_IMPL_COCOA
2484   NSEnableScreenUpdates ();
2485 #endif
2490 static void
2491 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2492 /* --------------------------------------------------------------------------
2493      External (RIF): Draw a vertical line.
2494    -------------------------------------------------------------------------- */
2496   struct frame *f = XFRAME (WINDOW_FRAME (w));
2497   struct face *face;
2498   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2500   NSTRACE (ns_draw_vertical_window_border);
2502   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2503   if (face)
2504       [ns_lookup_indexed_color(face->foreground, f) set];
2506   ns_focus (f, &r, 1);
2507   NSRectFill(r);
2508   ns_unfocus (f);
2512 static void
2513 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2514 /* --------------------------------------------------------------------------
2515      External (RIF): Draw a window divider.
2516    -------------------------------------------------------------------------- */
2518   struct frame *f = XFRAME (WINDOW_FRAME (w));
2519   struct face *face;
2520   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2522   NSTRACE (ns_draw_window_divider);
2524   face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2525   if (face)
2526       [ns_lookup_indexed_color(face->foreground, f) set];
2528   ns_focus (f, &r, 1);
2529   NSRectFill(r);
2530   ns_unfocus (f);
2534 void
2535 show_hourglass (struct atimer *timer)
2537   if (hourglass_shown_p)
2538     return;
2540   block_input ();
2542   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2544   hourglass_shown_p = 1;
2545   unblock_input ();
2549 void
2550 hide_hourglass (void)
2552   if (!hourglass_shown_p)
2553     return;
2555   block_input ();
2557   /* TODO: remove NSProgressIndicator from all frames */
2559   hourglass_shown_p = 0;
2560   unblock_input ();
2565 /* ==========================================================================
2567     Glyph drawing operations
2569    ========================================================================== */
2571 static int
2572 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2573 /* --------------------------------------------------------------------------
2574     Wrapper utility to account for internal border width on full-width lines,
2575     and allow top full-width rows to hit the frame top.  nr should be pointer
2576     to two successive NSRects.  Number of rects actually used is returned.
2577    -------------------------------------------------------------------------- */
2579   int n = get_glyph_string_clip_rects (s, nr, 2);
2580   return n;
2583 /* --------------------------------------------------------------------
2584    Draw a wavy line under glyph string s. The wave fills wave_height
2585    pixels from y.
2587                     x          wave_length = 2
2588                                  --
2589                 y    *   *   *   *   *
2590                      |* * * * * * * * *
2591     wave_height = 3  | *   *   *   *
2592   --------------------------------------------------------------------- */
2594 static void
2595 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2597   int wave_height = 3, wave_length = 2;
2598   int y, dx, dy, odd, xmax;
2599   NSPoint a, b;
2600   NSRect waveClip;
2602   dx = wave_length;
2603   dy = wave_height - 1;
2604   y =  s->ybase - wave_height + 3;
2605   xmax = x + width;
2607   /* Find and set clipping rectangle */
2608   waveClip = NSMakeRect (x, y, width, wave_height);
2609   [[NSGraphicsContext currentContext] saveGraphicsState];
2610   NSRectClip (waveClip);
2612   /* Draw the waves */
2613   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2614   b.x = a.x + dx;
2615   odd = (int)(a.x/dx) % 2;
2616   a.y = b.y = y + 0.5;
2618   if (odd)
2619     a.y += dy;
2620   else
2621     b.y += dy;
2623   while (a.x <= xmax)
2624     {
2625       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2626       a.x = b.x, a.y = b.y;
2627       b.x += dx, b.y = y + 0.5 + odd*dy;
2628       odd = !odd;
2629     }
2631   /* Restore previous clipping rectangle(s) */
2632   [[NSGraphicsContext currentContext] restoreGraphicsState];
2637 void
2638 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2639                          NSColor *defaultCol, CGFloat width, CGFloat x)
2640 /* --------------------------------------------------------------------------
2641    Draw underline, overline, and strike-through on glyph string s.
2642    -------------------------------------------------------------------------- */
2644   if (s->for_overlaps)
2645     return;
2647   /* Do underline. */
2648   if (face->underline_p)
2649     {
2650       if (s->face->underline_type == FACE_UNDER_WAVE)
2651         {
2652           if (face->underline_defaulted_p)
2653             [defaultCol set];
2654           else
2655             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2657           ns_draw_underwave (s, width, x);
2658         }
2659       else if (s->face->underline_type == FACE_UNDER_LINE)
2660         {
2662           NSRect r;
2663           unsigned long thickness, position;
2665           /* If the prev was underlined, match its appearance. */
2666           if (s->prev && s->prev->face->underline_p
2667               && s->prev->face->underline_type == FACE_UNDER_LINE
2668               && s->prev->underline_thickness > 0)
2669             {
2670               thickness = s->prev->underline_thickness;
2671               position = s->prev->underline_position;
2672             }
2673           else
2674             {
2675               struct font *font;
2676               unsigned long descent;
2678               font=s->font;
2679               descent = s->y + s->height - s->ybase;
2681               /* Use underline thickness of font, defaulting to 1. */
2682               thickness = (font && font->underline_thickness > 0)
2683                 ? font->underline_thickness : 1;
2685               /* Determine the offset of underlining from the baseline. */
2686               if (x_underline_at_descent_line)
2687                 position = descent - thickness;
2688               else if (x_use_underline_position_properties
2689                        && font && font->underline_position >= 0)
2690                 position = font->underline_position;
2691               else if (font)
2692                 position = lround (font->descent / 2);
2693               else
2694                 position = underline_minimum_offset;
2696               position = max (position, underline_minimum_offset);
2698               /* Ensure underlining is not cropped. */
2699               if (descent <= position)
2700                 {
2701                   position = descent - 1;
2702                   thickness = 1;
2703                 }
2704               else if (descent < position + thickness)
2705                 thickness = 1;
2706             }
2708           s->underline_thickness = thickness;
2709           s->underline_position = position;
2711           r = NSMakeRect (x, s->ybase + position, width, thickness);
2713           if (face->underline_defaulted_p)
2714             [defaultCol set];
2715           else
2716             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2717           NSRectFill (r);
2718         }
2719     }
2720   /* Do overline. We follow other terms in using a thickness of 1
2721      and ignoring overline_margin. */
2722   if (face->overline_p)
2723     {
2724       NSRect r;
2725       r = NSMakeRect (x, s->y, width, 1);
2727       if (face->overline_color_defaulted_p)
2728         [defaultCol set];
2729       else
2730         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2731       NSRectFill (r);
2732     }
2734   /* Do strike-through.  We follow other terms for thickness and
2735      vertical position.*/
2736   if (face->strike_through_p)
2737     {
2738       NSRect r;
2739       unsigned long dy;
2741       dy = lrint ((s->height - 1) / 2);
2742       r = NSMakeRect (x, s->y + dy, width, 1);
2744       if (face->strike_through_color_defaulted_p)
2745         [defaultCol set];
2746       else
2747         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2748       NSRectFill (r);
2749     }
2752 static void
2753 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2754              char left_p, char right_p)
2755 /* --------------------------------------------------------------------------
2756     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2757     Note we can't just use an NSDrawRect command, because of the possibility
2758     of some sides not being drawn, and because the rect will be filled.
2759    -------------------------------------------------------------------------- */
2761   NSRect s = r;
2762   [col set];
2764   /* top, bottom */
2765   s.size.height = thickness;
2766   NSRectFill (s);
2767   s.origin.y += r.size.height - thickness;
2768   NSRectFill (s);
2770   s.size.height = r.size.height;
2771   s.origin.y = r.origin.y;
2773   /* left, right (optional) */
2774   s.size.width = thickness;
2775   if (left_p)
2776     NSRectFill (s);
2777   if (right_p)
2778     {
2779       s.origin.x += r.size.width - thickness;
2780       NSRectFill (s);
2781     }
2785 static void
2786 ns_draw_relief (NSRect r, int thickness, char raised_p,
2787                char top_p, char bottom_p, char left_p, char right_p,
2788                struct glyph_string *s)
2789 /* --------------------------------------------------------------------------
2790     Draw a relief rect inside r, optionally leaving some sides open.
2791     Note we can't just use an NSDrawBezel command, because of the possibility
2792     of some sides not being drawn, and because the rect will be filled.
2793    -------------------------------------------------------------------------- */
2795   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2796   NSColor *newBaseCol = nil;
2797   NSRect sr = r;
2799   NSTRACE (ns_draw_relief);
2801   /* set up colors */
2803   if (s->face->use_box_color_for_shadows_p)
2804     {
2805       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2806     }
2807 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2808            && s->img->pixmap
2809            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2810        {
2811          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2812        } */
2813   else
2814     {
2815       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2816     }
2818   if (newBaseCol == nil)
2819     newBaseCol = [NSColor grayColor];
2821   if (newBaseCol != baseCol)  /* TODO: better check */
2822     {
2823       [baseCol release];
2824       baseCol = [newBaseCol retain];
2825       [lightCol release];
2826       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2827       [darkCol release];
2828       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2829     }
2831   [(raised_p ? lightCol : darkCol) set];
2833   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2835   /* top */
2836   sr.size.height = thickness;
2837   if (top_p) NSRectFill (sr);
2839   /* left */
2840   sr.size.height = r.size.height;
2841   sr.size.width = thickness;
2842   if (left_p) NSRectFill (sr);
2844   [(raised_p ? darkCol : lightCol) set];
2846   /* bottom */
2847   sr.size.width = r.size.width;
2848   sr.size.height = thickness;
2849   sr.origin.y += r.size.height - thickness;
2850   if (bottom_p) NSRectFill (sr);
2852   /* right */
2853   sr.size.height = r.size.height;
2854   sr.origin.y = r.origin.y;
2855   sr.size.width = thickness;
2856   sr.origin.x += r.size.width - thickness;
2857   if (right_p) NSRectFill (sr);
2861 static void
2862 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2863 /* --------------------------------------------------------------------------
2864       Function modeled after x_draw_glyph_string_box ().
2865       Sets up parameters for drawing.
2866    -------------------------------------------------------------------------- */
2868   int right_x, last_x;
2869   char left_p, right_p;
2870   struct glyph *last_glyph;
2871   NSRect r;
2872   int thickness;
2873   struct face *face;
2875   if (s->hl == DRAW_MOUSE_FACE)
2876     {
2877       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2878       if (!face)
2879         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2880     }
2881   else
2882     face = s->face;
2884   thickness = face->box_line_width;
2886   NSTRACE (ns_dumpglyphs_box_or_relief);
2888   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2889             ? WINDOW_RIGHT_EDGE_X (s->w)
2890             : window_box_right (s->w, s->area));
2891   last_glyph = (s->cmp || s->img
2892                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2894   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2895               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2897   left_p = (s->first_glyph->left_box_line_p
2898             || (s->hl == DRAW_MOUSE_FACE
2899                 && (s->prev == NULL || s->prev->hl != s->hl)));
2900   right_p = (last_glyph->right_box_line_p
2901              || (s->hl == DRAW_MOUSE_FACE
2902                  && (s->next == NULL || s->next->hl != s->hl)));
2904   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2906   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2907   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2908     {
2909       ns_draw_box (r, abs (thickness),
2910                    ns_lookup_indexed_color (face->box_color, s->f),
2911                   left_p, right_p);
2912     }
2913   else
2914     {
2915       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2916                      1, 1, left_p, right_p, s);
2917     }
2921 static void
2922 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2923 /* --------------------------------------------------------------------------
2924       Modeled after x_draw_glyph_string_background, which draws BG in
2925       certain cases.  Others are left to the text rendering routine.
2926    -------------------------------------------------------------------------- */
2928   NSTRACE (ns_maybe_dumpglyphs_background);
2930   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2931     {
2932       int box_line_width = max (s->face->box_line_width, 0);
2933       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2934           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2935         {
2936           struct face *face;
2937           if (s->hl == DRAW_MOUSE_FACE)
2938             {
2939               face = FACE_FROM_ID (s->f,
2940                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2941               if (!face)
2942                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2943             }
2944           else
2945             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2946           if (!face->stipple)
2947             [(NS_FACE_BACKGROUND (face) != 0
2948               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2949               : FRAME_BACKGROUND_COLOR (s->f)) set];
2950           else
2951             {
2952               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
2953               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2954             }
2956           if (s->hl != DRAW_CURSOR)
2957             {
2958               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2959                                     s->background_width,
2960                                     s->height-2*box_line_width);
2961               NSRectFill (r);
2962             }
2964           s->background_filled_p = 1;
2965         }
2966     }
2970 static void
2971 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2972 /* --------------------------------------------------------------------------
2973       Renders an image and associated borders.
2974    -------------------------------------------------------------------------- */
2976   EmacsImage *img = s->img->pixmap;
2977   int box_line_vwidth = max (s->face->box_line_width, 0);
2978   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2979   int bg_x, bg_y, bg_height;
2980   int th;
2981   char raised_p;
2982   NSRect br;
2983   struct face *face;
2984   NSColor *tdCol;
2986   NSTRACE (ns_dumpglyphs_image);
2988   if (s->face->box != FACE_NO_BOX
2989       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2990     x += abs (s->face->box_line_width);
2992   bg_x = x;
2993   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2994   bg_height = s->height;
2995   /* other terms have this, but was causing problems w/tabbar mode */
2996   /* - 2 * box_line_vwidth; */
2998   if (s->slice.x == 0) x += s->img->hmargin;
2999   if (s->slice.y == 0) y += s->img->vmargin;
3001   /* Draw BG: if we need larger area than image itself cleared, do that,
3002      otherwise, since we composite the image under NS (instead of mucking
3003      with its background color), we must clear just the image area. */
3004   if (s->hl == DRAW_MOUSE_FACE)
3005     {
3006       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3007       if (!face)
3008        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3009     }
3010   else
3011     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3013   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3015   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3016       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3017     {
3018       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3019       s->background_filled_p = 1;
3020     }
3021   else
3022     {
3023       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3024     }
3026   NSRectFill (br);
3028   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3029   if (img != nil)
3030     {
3031 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
3032       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3033       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3034                               s->slice.width, s->slice.height);
3035       [img drawInRect: dr
3036              fromRect: ir
3037              operation: NSCompositeSourceOver
3038               fraction: 1.0
3039            respectFlipped: YES
3040                 hints: nil];
3041 #else
3042       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3043                   operation: NSCompositeSourceOver];
3044 #endif
3045     }
3047   if (s->hl == DRAW_CURSOR)
3048     {
3049     [FRAME_CURSOR_COLOR (s->f) set];
3050     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3051       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3052     else
3053       /* Currently on NS img->mask is always 0. Since
3054          get_window_cursor_type specifies a hollow box cursor when on
3055          a non-masked image we never reach this clause. But we put it
3056          in in anticipation of better support for image masks on
3057          NS. */
3058       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3059     }
3060   else
3061     {
3062       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3063     }
3065   /* Draw underline, overline, strike-through. */
3066   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3068   /* Draw relief, if requested */
3069   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3070     {
3071       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3072         {
3073           th = tool_bar_button_relief >= 0 ?
3074             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3075           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3076         }
3077       else
3078         {
3079           th = abs (s->img->relief);
3080           raised_p = (s->img->relief > 0);
3081         }
3083       r.origin.x = x - th;
3084       r.origin.y = y - th;
3085       r.size.width = s->slice.width + 2*th-1;
3086       r.size.height = s->slice.height + 2*th-1;
3087       ns_draw_relief (r, th, raised_p,
3088                       s->slice.y == 0,
3089                       s->slice.y + s->slice.height == s->img->height,
3090                       s->slice.x == 0,
3091                       s->slice.x + s->slice.width == s->img->width, s);
3092     }
3094   /* If there is no mask, the background won't be seen,
3095      so draw a rectangle on the image for the cursor.
3096      Do this for all images, getting transparency right is not reliable.  */
3097   if (s->hl == DRAW_CURSOR)
3098     {
3099       int thickness = abs (s->img->relief);
3100       if (thickness == 0) thickness = 1;
3101       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3102     }
3106 static void
3107 ns_dumpglyphs_stretch (struct glyph_string *s)
3109   NSRect r[2];
3110   int n, i;
3111   struct face *face;
3112   NSColor *fgCol, *bgCol;
3114   if (!s->background_filled_p)
3115     {
3116       n = ns_get_glyph_string_clip_rect (s, r);
3117       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3119       ns_focus (s->f, r, n);
3121       if (s->hl == DRAW_MOUSE_FACE)
3122        {
3123          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3124          if (!face)
3125            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3126        }
3127       else
3128        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3130       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3131       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3133       for (i = 0; i < n; ++i)
3134         {
3135           if (!s->row->full_width_p)
3136             {
3137               int overrun, leftoverrun;
3139               /* truncate to avoid overwriting fringe and/or scrollbar */
3140               overrun = max (0, (s->x + s->background_width)
3141                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3142                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3143               r[i].size.width -= overrun;
3145               /* truncate to avoid overwriting to left of the window box */
3146               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3147                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3149               if (leftoverrun > 0)
3150                 {
3151                   r[i].origin.x += leftoverrun;
3152                   r[i].size.width -= leftoverrun;
3153                 }
3155               /* XXX: Try to work between problem where a stretch glyph on
3156                  a partially-visible bottom row will clear part of the
3157                  modeline, and another where list-buffers headers and similar
3158                  rows erroneously have visible_height set to 0.  Not sure
3159                  where this is coming from as other terms seem not to show. */
3160               r[i].size.height = min (s->height, s->row->visible_height);
3161             }
3163           [bgCol set];
3165           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3166              overwriting cursor (usually when cursor on a tab) */
3167           if (s->hl == DRAW_CURSOR)
3168             {
3169               CGFloat x, width;
3171               x = r[i].origin.x;
3172               width = s->w->phys_cursor_width;
3173               r[i].size.width -= width;
3174               r[i].origin.x += width;
3176               NSRectFill (r[i]);
3178               /* Draw overlining, etc. on the cursor. */
3179               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3180                 ns_draw_text_decoration (s, face, bgCol, width, x);
3181               else
3182                 ns_draw_text_decoration (s, face, fgCol, width, x);
3183             }
3184           else
3185             {
3186               NSRectFill (r[i]);
3187             }
3189           /* Draw overlining, etc. on the stretch glyph (or the part
3190              of the stretch glyph after the cursor). */
3191           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3192                                    r[i].origin.x);
3193         }
3194       ns_unfocus (s->f);
3195       s->background_filled_p = 1;
3196     }
3200 static void
3201 ns_draw_glyph_string (struct glyph_string *s)
3202 /* --------------------------------------------------------------------------
3203       External (RIF): Main draw-text call.
3204    -------------------------------------------------------------------------- */
3206   /* TODO (optimize): focus for box and contents draw */
3207   NSRect r[2];
3208   int n, flags;
3209   char box_drawn_p = 0;
3210   struct font *font = s->face->font;
3211   if (! font) font = FRAME_FONT (s->f);
3213   NSTRACE (ns_draw_glyph_string);
3215   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3216     {
3217       int width;
3218       struct glyph_string *next;
3220       for (width = 0, next = s->next;
3221            next && width < s->right_overhang;
3222            width += next->width, next = next->next)
3223         if (next->first_glyph->type != IMAGE_GLYPH)
3224           {
3225             if (next->first_glyph->type != STRETCH_GLYPH)
3226               {
3227                 n = ns_get_glyph_string_clip_rect (s->next, r);
3228                 ns_focus (s->f, r, n);
3229                 ns_maybe_dumpglyphs_background (s->next, 1);
3230                 ns_unfocus (s->f);
3231               }
3232             else
3233               {
3234                 ns_dumpglyphs_stretch (s->next);
3235               }
3236             next->num_clips = 0;
3237           }
3238     }
3240   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3241         && (s->first_glyph->type == CHAR_GLYPH
3242             || s->first_glyph->type == COMPOSITE_GLYPH))
3243     {
3244       n = ns_get_glyph_string_clip_rect (s, r);
3245       ns_focus (s->f, r, n);
3246       ns_maybe_dumpglyphs_background (s, 1);
3247       ns_dumpglyphs_box_or_relief (s);
3248       ns_unfocus (s->f);
3249       box_drawn_p = 1;
3250     }
3252   switch (s->first_glyph->type)
3253     {
3255     case IMAGE_GLYPH:
3256       n = ns_get_glyph_string_clip_rect (s, r);
3257       ns_focus (s->f, r, n);
3258       ns_dumpglyphs_image (s, r[0]);
3259       ns_unfocus (s->f);
3260       break;
3262     case STRETCH_GLYPH:
3263       ns_dumpglyphs_stretch (s);
3264       break;
3266     case CHAR_GLYPH:
3267     case COMPOSITE_GLYPH:
3268       n = ns_get_glyph_string_clip_rect (s, r);
3269       ns_focus (s->f, r, n);
3271       if (s->for_overlaps || (s->cmp_from > 0
3272                               && ! s->first_glyph->u.cmp.automatic))
3273         s->background_filled_p = 1;
3274       else
3275         ns_maybe_dumpglyphs_background
3276           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3278       flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3279         (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3280          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3281           NS_DUMPGLYPH_NORMAL));
3283       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3284         {
3285           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3286           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3287           NS_FACE_FOREGROUND (s->face) = tmp;
3288         }
3290       font->driver->draw
3291         (s, 0, s->nchars, s->x, s->y,
3292          (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3293          || flags == NS_DUMPGLYPH_MOUSEFACE);
3295       {
3296         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3297                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3298                                                    s->f)
3299                         : FRAME_FOREGROUND_COLOR (s->f));
3300         [col set];
3302         /* Draw underline, overline, strike-through. */
3303         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3304       }
3306       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3307         {
3308           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3309           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3310           NS_FACE_FOREGROUND (s->face) = tmp;
3311         }
3313       ns_unfocus (s->f);
3314       break;
3316     case GLYPHLESS_GLYPH:
3317       n = ns_get_glyph_string_clip_rect (s, r);
3318       ns_focus (s->f, r, n);
3320       if (s->for_overlaps || (s->cmp_from > 0
3321                               && ! s->first_glyph->u.cmp.automatic))
3322         s->background_filled_p = 1;
3323       else
3324         ns_maybe_dumpglyphs_background
3325           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3326       /* ... */
3327       /* Not yet implemented.  */
3328       /* ... */
3329       ns_unfocus (s->f);
3330       break;
3332     default:
3333       emacs_abort ();
3334     }
3336   /* Draw box if not done already. */
3337   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3338     {
3339       n = ns_get_glyph_string_clip_rect (s, r);
3340       ns_focus (s->f, r, n);
3341       ns_dumpglyphs_box_or_relief (s);
3342       ns_unfocus (s->f);
3343     }
3345   s->num_clips = 0;
3350 /* ==========================================================================
3352     Event loop
3354    ========================================================================== */
3357 static void
3358 ns_send_appdefined (int value)
3359 /* --------------------------------------------------------------------------
3360     Internal: post an appdefined event which EmacsApp-sendEvent will
3361               recognize and take as a command to halt the event loop.
3362    -------------------------------------------------------------------------- */
3364   /*NSTRACE (ns_send_appdefined); */
3366 #ifdef NS_IMPL_GNUSTEP
3367   // GNUStep needs postEvent to happen on the main thread.
3368   if (! [[NSThread currentThread] isMainThread])
3369     {
3370       EmacsApp *app = (EmacsApp *)NSApp;
3371       app->nextappdefined = value;
3372       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3373                             withObject:nil
3374                          waitUntilDone:YES];
3375       return;
3376     }
3377 #endif
3379   /* Only post this event if we haven't already posted one.  This will end
3380        the [NXApp run] main loop after having processed all events queued at
3381        this moment.  */
3382   if (send_appdefined)
3383     {
3384       NSEvent *nxev;
3386       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3387       send_appdefined = NO;
3389       /* Don't need wakeup timer any more */
3390       if (timed_entry)
3391         {
3392           [timed_entry invalidate];
3393           [timed_entry release];
3394           timed_entry = nil;
3395         }
3397       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3398                                 location: NSMakePoint (0, 0)
3399                            modifierFlags: 0
3400                                timestamp: 0
3401                             windowNumber: [[NSApp mainWindow] windowNumber]
3402                                  context: [NSApp context]
3403                                  subtype: 0
3404                                    data1: value
3405                                    data2: 0];
3407       /* Post an application defined event on the event queue.  When this is
3408          received the [NXApp run] will return, thus having processed all
3409          events which are currently queued.  */
3410       [NSApp postEvent: nxev atStart: NO];
3411     }
3414 #ifdef HAVE_NATIVE_FS
3415 static void
3416 check_native_fs ()
3418   Lisp_Object frame, tail;
3420   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3421     return;
3423   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3425   FOR_EACH_FRAME (tail, frame)
3426     {
3427       struct frame *f = XFRAME (frame);
3428       if (FRAME_NS_P (f))
3429         {
3430           EmacsView *view = FRAME_NS_VIEW (f);
3431           [view updateCollectionBehaviour];
3432         }
3433     }
3435 #endif
3437 /* GNUStep and OSX <= 10.4 does not have cancelTracking.  */
3438 #if defined (NS_IMPL_COCOA) && \
3439   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
3440 /* Check if menu open should be cancelled or continued as normal.  */
3441 void
3442 ns_check_menu_open (NSMenu *menu)
3444   /* Click in menu bar? */
3445   NSArray *a = [[NSApp mainMenu] itemArray];
3446   int i;
3447   BOOL found = NO;
3449   if (menu == nil) // Menu tracking ended.
3450     {
3451       if (menu_will_open_state == MENU_OPENING)
3452         menu_will_open_state = MENU_NONE;
3453       return;
3454     }
3456   for (i = 0; ! found && i < [a count]; i++)
3457     found = menu == [[a objectAtIndex:i] submenu];
3458   if (found)
3459     {
3460       if (menu_will_open_state == MENU_NONE && emacs_event)
3461         {
3462           NSEvent *theEvent = [NSApp currentEvent];
3463           struct frame *emacsframe = SELECTED_FRAME ();
3465           [menu cancelTracking];
3466           menu_will_open_state = MENU_PENDING;
3467           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3468           EV_TRAILER (theEvent);
3470           CGEventRef ourEvent = CGEventCreate (NULL);
3471           menu_mouse_point = CGEventGetLocation (ourEvent);
3472           CFRelease (ourEvent);
3473         }
3474       else if (menu_will_open_state == MENU_OPENING)
3475         {
3476           menu_will_open_state = MENU_NONE;
3477         }
3478     }
3481 /* Redo saved menu click if state is MENU_PENDING.  */
3482 void
3483 ns_check_pending_open_menu ()
3485   if (menu_will_open_state == MENU_PENDING)
3486     {
3487       CGEventSourceRef source
3488         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3490       CGEventRef event = CGEventCreateMouseEvent (source,
3491                                                   kCGEventLeftMouseDown,
3492                                                   menu_mouse_point,
3493                                                   kCGMouseButtonLeft);
3494       CGEventSetType (event, kCGEventLeftMouseDown);
3495       CGEventPost (kCGHIDEventTap, event);
3496       CFRelease (event);
3497       CFRelease (source);
3499       menu_will_open_state = MENU_OPENING;
3500     }
3502 #endif /* NS_IMPL_COCOA) && >= MAC_OS_X_VERSION_10_5 */
3504 static int
3505 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3506 /* --------------------------------------------------------------------------
3507      External (hook): Post an event to ourself and keep reading events until
3508      we read it back again.  In effect process all events which were waiting.
3509      From 21+ we have to manage the event buffer ourselves.
3510    -------------------------------------------------------------------------- */
3512   struct input_event ev;
3513   int nevents;
3515 /* NSTRACE (ns_read_socket); */
3517 #ifdef HAVE_NATIVE_FS
3518   check_native_fs ();
3519 #endif
3521   if ([NSApp modalWindow] != nil)
3522     return -1;
3524   if (hold_event_q.nr > 0)
3525     {
3526       int i;
3527       for (i = 0; i < hold_event_q.nr; ++i)
3528         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3529       hold_event_q.nr = 0;
3530       return i;
3531     }
3533   block_input ();
3534   n_emacs_events_pending = 0;
3535   EVENT_INIT (ev);
3536   emacs_event = &ev;
3537   q_event_ptr = hold_quit;
3539   /* we manage autorelease pools by allocate/reallocate each time around
3540      the loop; strict nesting is occasionally violated but seems not to
3541      matter.. earlier methods using full nesting caused major memory leaks */
3542   [outerpool release];
3543   outerpool = [[NSAutoreleasePool alloc] init];
3545   /* If have pending open-file requests, attend to the next one of those. */
3546   if (ns_pending_files && [ns_pending_files count] != 0
3547       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3548     {
3549       [ns_pending_files removeObjectAtIndex: 0];
3550     }
3551   /* Deal with pending service requests. */
3552   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3553     && [(EmacsApp *)
3554          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3555                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3556     {
3557       [ns_pending_service_names removeObjectAtIndex: 0];
3558       [ns_pending_service_args removeObjectAtIndex: 0];
3559     }
3560   else
3561     {
3562       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3563          to ourself, otherwise [NXApp run] will never exit.  */
3564       send_appdefined = YES;
3565       ns_send_appdefined (-1);
3567       if (++apploopnr != 1)
3568         {
3569           emacs_abort ();
3570         }
3571       [NSApp run];
3572       --apploopnr;
3573     }
3575   nevents = n_emacs_events_pending;
3576   n_emacs_events_pending = 0;
3577   emacs_event = q_event_ptr = NULL;
3578   unblock_input ();
3580   return nevents;
3585 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3586            fd_set *exceptfds, struct timespec const *timeout,
3587            sigset_t const *sigmask)
3588 /* --------------------------------------------------------------------------
3589      Replacement for select, checking for events
3590    -------------------------------------------------------------------------- */
3592   int result;
3593   int t, k, nr = 0;
3594   struct input_event event;
3595   char c;
3597 /*  NSTRACE (ns_select); */
3599 #ifdef HAVE_NATIVE_FS
3600   check_native_fs ();
3601 #endif
3603   if (hold_event_q.nr > 0)
3604     {
3605       /* We already have events pending. */
3606       raise (SIGIO);
3607       errno = EINTR;
3608       return -1;
3609     }
3611   for (k = 0; k < nfds+1; k++)
3612     {
3613       if (readfds && FD_ISSET(k, readfds)) ++nr;
3614       if (writefds && FD_ISSET(k, writefds)) ++nr;
3615     }
3617   if (NSApp == nil
3618       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3619     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3621   [outerpool release];
3622   outerpool = [[NSAutoreleasePool alloc] init];
3625   send_appdefined = YES;
3626   if (nr > 0)
3627     {
3628       pthread_mutex_lock (&select_mutex);
3629       select_nfds = nfds;
3630       select_valid = 0;
3631       if (readfds)
3632         {
3633           select_readfds = *readfds;
3634           select_valid += SELECT_HAVE_READ;
3635         }
3636       if (writefds)
3637         {
3638           select_writefds = *writefds;
3639           select_valid += SELECT_HAVE_WRITE;
3640         }
3642       if (timeout)
3643         {
3644           select_timeout = *timeout;
3645           select_valid += SELECT_HAVE_TMO;
3646         }
3648       pthread_mutex_unlock (&select_mutex);
3650       /* Inform fd_handler that select should be called */
3651       c = 'g';
3652       emacs_write_sig (selfds[1], &c, 1);
3653     }
3654   else if (nr == 0 && timeout)
3655     {
3656       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3657       double time = timespectod (*timeout);
3658       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3659                                                       target: NSApp
3660                                                     selector:
3661                                   @selector (timeout_handler:)
3662                                                     userInfo: 0
3663                                                      repeats: NO]
3664                       retain];
3665     }
3666   else /* No timeout and no file descriptors, can this happen?  */
3667     {
3668       /* Send appdefined so we exit from the loop */
3669       ns_send_appdefined (-1);
3670     }
3672   EVENT_INIT (event);
3673   block_input ();
3674   emacs_event = &event;
3675   if (++apploopnr != 1)
3676     {
3677       emacs_abort ();
3678     }
3679   [NSApp run];
3680   --apploopnr;
3681   emacs_event = NULL;
3682   if (nr > 0 && readfds)
3683     {
3684       c = 's';
3685       emacs_write_sig (selfds[1], &c, 1);
3686     }
3687   unblock_input ();
3689   t = last_appdefined_event_data;
3691   if (t != NO_APPDEFINED_DATA)
3692     {
3693       last_appdefined_event_data = NO_APPDEFINED_DATA;
3695       if (t == -2)
3696         {
3697           /* The NX_APPDEFINED event we received was a timeout. */
3698           result = 0;
3699         }
3700       else if (t == -1)
3701         {
3702           /* The NX_APPDEFINED event we received was the result of
3703              at least one real input event arriving.  */
3704           errno = EINTR;
3705           result = -1;
3706         }
3707       else
3708         {
3709           /* Received back from select () in fd_handler; copy the results */
3710           pthread_mutex_lock (&select_mutex);
3711           if (readfds) *readfds = select_readfds;
3712           if (writefds) *writefds = select_writefds;
3713           pthread_mutex_unlock (&select_mutex);
3714           result = t;
3715         }
3716     }
3717   else
3718     {
3719       errno = EINTR;
3720       result = -1;
3721     }
3723   return result;
3728 /* ==========================================================================
3730     Scrollbar handling
3732    ========================================================================== */
3735 static void
3736 ns_set_vertical_scroll_bar (struct window *window,
3737                            int portion, int whole, int position)
3738 /* --------------------------------------------------------------------------
3739       External (hook): Update or add scrollbar
3740    -------------------------------------------------------------------------- */
3742   Lisp_Object win;
3743   NSRect r, v;
3744   struct frame *f = XFRAME (WINDOW_FRAME (window));
3745   EmacsView *view = FRAME_NS_VIEW (f);
3746   int window_y, window_height;
3747   int top, left, height, width, sb_width, sb_left;
3748   EmacsScroller *bar;
3749   BOOL fringe_extended_p;
3751   /* optimization; display engine sends WAY too many of these.. */
3752   if (!NILP (window->vertical_scroll_bar))
3753     {
3754       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3755       if ([bar checkSamePosition: position portion: portion whole: whole])
3756         {
3757           if (view->scrollbarsNeedingUpdate == 0)
3758             {
3759               if (!windows_or_buffers_changed)
3760                   return;
3761             }
3762           else
3763             view->scrollbarsNeedingUpdate--;
3764         }
3765     }
3767   NSTRACE (ns_set_vertical_scroll_bar);
3769   /* Get dimensions.  */
3770   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3771   top = window_y;
3772   height = window_height;
3773   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3774   left = WINDOW_SCROLL_BAR_AREA_X (window);
3776   /* allow for displaying a skinnier scrollbar than char area allotted */
3777   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3778     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3779   sb_left = left;
3781   r = NSMakeRect (sb_left, top, sb_width, height);
3782   /* the parent view is flipped, so we need to flip y value */
3783   v = [view frame];
3784   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3786   fringe_extended_p = WINDOW_FRINGE_EXTENDED_P (window);
3788   XSETWINDOW (win, window);
3789   block_input ();
3791   /* we want at least 5 lines to display a scrollbar */
3792   if (WINDOW_TOTAL_LINES (window) < 5)
3793     {
3794       if (!NILP (window->vertical_scroll_bar))
3795         {
3796           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3797           [bar removeFromSuperview];
3798           wset_vertical_scroll_bar (window, Qnil);
3799         }
3800       ns_clear_frame_area (f, sb_left, top, width, height);
3801       unblock_input ();
3802       return;
3803     }
3805   if (NILP (window->vertical_scroll_bar))
3806     {
3807       if (width > 0 && height > 0)
3808         {
3809           if (fringe_extended_p)
3810             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3811           else
3812             ns_clear_frame_area (f, left, top, width, height);
3813         }
3815       bar = [[EmacsScroller alloc] initFrame: r window: win];
3816       wset_vertical_scroll_bar (window, make_save_ptr (bar));
3817     }
3818   else
3819     {
3820       NSRect oldRect;
3821       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3822       oldRect = [bar frame];
3823       r.size.width = oldRect.size.width;
3824       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3825         {
3826           if (oldRect.origin.x != r.origin.x)
3827               ns_clear_frame_area (f, sb_left, top, width, height);
3828           [bar setFrame: r];
3829         }
3830     }
3832   [bar setPosition: position portion: portion whole: whole];
3833   unblock_input ();
3837 static void
3838 ns_condemn_scroll_bars (struct frame *f)
3839 /* --------------------------------------------------------------------------
3840      External (hook): arrange for all frame's scrollbars to be removed
3841      at next call to judge_scroll_bars, except for those redeemed.
3842    -------------------------------------------------------------------------- */
3844   int i;
3845   id view;
3846   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3848   NSTRACE (ns_condemn_scroll_bars);
3850   for (i =[subviews count]-1; i >= 0; i--)
3851     {
3852       view = [subviews objectAtIndex: i];
3853       if ([view isKindOfClass: [EmacsScroller class]])
3854         [view condemn];
3855     }
3859 static void
3860 ns_redeem_scroll_bar (struct window *window)
3861 /* --------------------------------------------------------------------------
3862      External (hook): arrange to spare this window's scrollbar
3863      at next call to judge_scroll_bars.
3864    -------------------------------------------------------------------------- */
3866   id bar;
3867   NSTRACE (ns_redeem_scroll_bar);
3868   if (!NILP (window->vertical_scroll_bar))
3869     {
3870       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3871       [bar reprieve];
3872     }
3876 static void
3877 ns_judge_scroll_bars (struct frame *f)
3878 /* --------------------------------------------------------------------------
3879      External (hook): destroy all scrollbars on frame that weren't
3880      redeemed after call to condemn_scroll_bars.
3881    -------------------------------------------------------------------------- */
3883   int i;
3884   id view;
3885   EmacsView *eview = FRAME_NS_VIEW (f);
3886   NSArray *subviews = [[eview superview] subviews];
3887   BOOL removed = NO;
3889   NSTRACE (ns_judge_scroll_bars);
3890   for (i = [subviews count]-1; i >= 0; --i)
3891     {
3892       view = [subviews objectAtIndex: i];
3893       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3894       [view judge];
3895       removed = YES;
3896     }
3898   if (removed)
3899     [eview updateFrameSize: NO];
3902 /* ==========================================================================
3904     Initialization
3906    ========================================================================== */
3909 x_display_pixel_height (struct ns_display_info *dpyinfo)
3911   NSArray *screens = [NSScreen screens];
3912   NSEnumerator *enumerator = [screens objectEnumerator];
3913   NSScreen *screen;
3914   NSRect frame;
3916   frame = NSZeroRect;
3917   while ((screen = [enumerator nextObject]) != nil)
3918     frame = NSUnionRect (frame, [screen frame]);
3920   return NSHeight (frame);
3924 x_display_pixel_width (struct ns_display_info *dpyinfo)
3926   NSArray *screens = [NSScreen screens];
3927   NSEnumerator *enumerator = [screens objectEnumerator];
3928   NSScreen *screen;
3929   NSRect frame;
3931   frame = NSZeroRect;
3932   while ((screen = [enumerator nextObject]) != nil)
3933     frame = NSUnionRect (frame, [screen frame]);
3935   return NSWidth (frame);
3939 static Lisp_Object ns_string_to_lispmod (const char *s)
3940 /* --------------------------------------------------------------------------
3941      Convert modifier name to lisp symbol
3942    -------------------------------------------------------------------------- */
3944   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3945     return Qmeta;
3946   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3947     return Qsuper;
3948   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3949     return Qcontrol;
3950   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3951     return Qalt;
3952   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3953     return Qhyper;
3954   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3955     return Qnone;
3956   else
3957     return Qnil;
3961 static void
3962 ns_default (const char *parameter, Lisp_Object *result,
3963            Lisp_Object yesval, Lisp_Object noval,
3964            BOOL is_float, BOOL is_modstring)
3965 /* --------------------------------------------------------------------------
3966       Check a parameter value in user's preferences
3967    -------------------------------------------------------------------------- */
3969   const char *value = ns_get_defaults_value (parameter);
3971   if (value)
3972     {
3973       double f;
3974       char *pos;
3975       if (c_strcasecmp (value, "YES") == 0)
3976         *result = yesval;
3977       else if (c_strcasecmp (value, "NO") == 0)
3978         *result = noval;
3979       else if (is_float && (f = strtod (value, &pos), pos != value))
3980         *result = make_float (f);
3981       else if (is_modstring && value)
3982         *result = ns_string_to_lispmod (value);
3983       else fprintf (stderr,
3984                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3985     }
3989 static void
3990 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3991 /* --------------------------------------------------------------------------
3992       Initialize global info and storage for display.
3993    -------------------------------------------------------------------------- */
3995     NSScreen *screen = [NSScreen mainScreen];
3996     NSWindowDepth depth = [screen depth];
3998     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3999     dpyinfo->resy = 72.27;
4000     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4001                                                   NSColorSpaceFromDepth (depth)]
4002                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4003                                                  NSColorSpaceFromDepth (depth)];
4004     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4005     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4006     dpyinfo->color_table->colors = NULL;
4007     dpyinfo->root_window = 42; /* a placeholder.. */
4008     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4009     dpyinfo->n_fonts = 0;
4010     dpyinfo->smallest_font_height = 1;
4011     dpyinfo->smallest_char_width = 1;
4013     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4017 /* This and next define (many of the) public functions in this file. */
4018 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4019          with using despite presence in the "system dependent" redisplay
4020          interface.  In addition, many of the ns_ methods have code that is
4021          shared with all terms, indicating need for further refactoring. */
4022 extern frame_parm_handler ns_frame_parm_handlers[];
4023 static struct redisplay_interface ns_redisplay_interface =
4025   ns_frame_parm_handlers,
4026   x_produce_glyphs,
4027   x_write_glyphs,
4028   x_insert_glyphs,
4029   x_clear_end_of_line,
4030   ns_scroll_run,
4031   ns_after_update_window_line,
4032   ns_update_window_begin,
4033   ns_update_window_end,
4034   0, /* flush_display */
4035   x_clear_window_mouse_face,
4036   x_get_glyph_overhangs,
4037   x_fix_overlapping_area,
4038   ns_draw_fringe_bitmap,
4039   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4040   0, /* destroy_fringe_bitmap */
4041   ns_compute_glyph_string_overhangs,
4042   ns_draw_glyph_string,
4043   ns_define_frame_cursor,
4044   ns_clear_frame_area,
4045   ns_draw_window_cursor,
4046   ns_draw_vertical_window_border,
4047   ns_draw_window_divider,
4048   ns_shift_glyphs_for_insert
4052 static void
4053 ns_delete_display (struct ns_display_info *dpyinfo)
4055   /* TODO... */
4059 /* This function is called when the last frame on a display is deleted. */
4060 static void
4061 ns_delete_terminal (struct terminal *terminal)
4063   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4065   /* Protect against recursive calls.  delete_frame in
4066      delete_terminal calls us back when it deletes our last frame.  */
4067   if (!terminal->name)
4068     return;
4070   block_input ();
4072   x_destroy_all_bitmaps (dpyinfo);
4073   ns_delete_display (dpyinfo);
4074   unblock_input ();
4078 static struct terminal *
4079 ns_create_terminal (struct ns_display_info *dpyinfo)
4080 /* --------------------------------------------------------------------------
4081       Set up use of NS before we make the first connection.
4082    -------------------------------------------------------------------------- */
4084   struct terminal *terminal;
4086   NSTRACE (ns_create_terminal);
4088   terminal = create_terminal ();
4090   terminal->type = output_ns;
4091   terminal->display_info.ns = dpyinfo;
4092   dpyinfo->terminal = terminal;
4094   terminal->rif = &ns_redisplay_interface;
4096   terminal->clear_frame_hook = ns_clear_frame;
4097   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4098   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
4099   terminal->ring_bell_hook = ns_ring_bell;
4100   terminal->reset_terminal_modes_hook = NULL;
4101   terminal->set_terminal_modes_hook = NULL;
4102   terminal->update_begin_hook = ns_update_begin;
4103   terminal->update_end_hook = ns_update_end;
4104   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4105   terminal->read_socket_hook = ns_read_socket;
4106   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4107   terminal->mouse_position_hook = ns_mouse_position;
4108   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4109   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4111   terminal->fullscreen_hook = ns_fullscreen_hook;
4113   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4114   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4115   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4116   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4118   terminal->delete_frame_hook = x_destroy_window;
4119   terminal->delete_terminal_hook = ns_delete_terminal;
4121   return terminal;
4125 struct ns_display_info *
4126 ns_term_init (Lisp_Object display_name)
4127 /* --------------------------------------------------------------------------
4128      Start the Application and get things rolling.
4129    -------------------------------------------------------------------------- */
4131   struct terminal *terminal;
4132   struct ns_display_info *dpyinfo;
4133   static int ns_initialized = 0;
4134   Lisp_Object tmp;
4136   if (ns_initialized) return x_display_list;
4137   ns_initialized = 1;
4139   NSTRACE (ns_term_init);
4141   [outerpool release];
4142   outerpool = [[NSAutoreleasePool alloc] init];
4144   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4145   /*GSDebugAllocationActive (YES); */
4146   block_input ();
4148   baud_rate = 38400;
4149   Fset_input_interrupt_mode (Qnil);
4151   if (selfds[0] == -1)
4152     {
4153       if (emacs_pipe (selfds) != 0)
4154         {
4155           fprintf (stderr, "Failed to create pipe: %s\n",
4156                    emacs_strerror (errno));
4157           emacs_abort ();
4158         }
4160       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4161       FD_ZERO (&select_readfds);
4162       FD_ZERO (&select_writefds);
4163       pthread_mutex_init (&select_mutex, NULL);
4164     }
4166   ns_pending_files = [[NSMutableArray alloc] init];
4167   ns_pending_service_names = [[NSMutableArray alloc] init];
4168   ns_pending_service_args = [[NSMutableArray alloc] init];
4170 /* Start app and create the main menu, window, view.
4171      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4172      The view will then ask the NSApp to stop and return to Emacs. */
4173   [EmacsApp sharedApplication];
4174   if (NSApp == nil)
4175     return NULL;
4176   [NSApp setDelegate: NSApp];
4178   /* Start the select thread.  */
4179   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4180                            toTarget:NSApp
4181                          withObject:nil];
4183   /* debugging: log all notifications */
4184   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4185                                          selector: @selector (logNotification:)
4186                                              name: nil object: nil]; */
4188   dpyinfo = xzalloc (sizeof *dpyinfo);
4190   ns_initialize_display_info (dpyinfo);
4191   terminal = ns_create_terminal (dpyinfo);
4193   terminal->kboard = allocate_kboard (Qns);
4194   /* Don't let the initial kboard remain current longer than necessary.
4195      That would cause problems if a file loaded on startup tries to
4196      prompt in the mini-buffer.  */
4197   if (current_kboard == initial_kboard)
4198     current_kboard = terminal->kboard;
4199   terminal->kboard->reference_count++;
4201   dpyinfo->next = x_display_list;
4202   x_display_list = dpyinfo;
4204   dpyinfo->name_list_element = Fcons (display_name, Qnil);
4206   terminal->name = xstrdup (SSDATA (display_name));
4208   unblock_input ();
4210   if (!inhibit_x_resources)
4211     {
4212       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4213                  Qt, Qnil, NO, NO);
4214       tmp = Qnil;
4215       /* this is a standard variable */
4216       ns_default ("AppleAntiAliasingThreshold", &tmp,
4217                  make_float (10.0), make_float (6.0), YES, NO);
4218       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4219     }
4221   {
4222     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4224     if ( cl == nil )
4225       {
4226         Lisp_Object color_file, color_map, color;
4227         unsigned long c;
4228         char *name;
4230         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4231                          Fsymbol_value (intern ("data-directory")));
4233         color_map = Fx_load_color_file (color_file);
4234         if (NILP (color_map))
4235           fatal ("Could not read %s.\n", SDATA (color_file));
4237         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4238         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4239           {
4240             color = XCAR (color_map);
4241             name = SSDATA (XCAR (color));
4242             c = XINT (XCDR (color));
4243             [cl setColor:
4244                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4245                                             green: GREEN_FROM_ULONG (c) / 255.0
4246                                              blue: BLUE_FROM_ULONG (c) / 255.0
4247                                             alpha: 1.0]
4248                   forKey: [NSString stringWithUTF8String: name]];
4249           }
4250         [cl writeToFile: nil];
4251       }
4252   }
4254   {
4255 #ifdef NS_IMPL_GNUSTEP
4256     Vwindow_system_version = build_string (gnustep_base_version);
4257 #else
4258     /*PSnextrelease (128, c); */
4259     char c[DBL_BUFSIZE_BOUND];
4260     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4261     Vwindow_system_version = make_unibyte_string (c, len);
4262 #endif
4263   }
4265   delete_keyboard_wait_descriptor (0);
4267   ns_app_name = [[NSProcessInfo processInfo] processName];
4269 /* Set up OS X app menu */
4270 #ifdef NS_IMPL_COCOA
4271   {
4272     NSMenu *appMenu;
4273     NSMenuItem *item;
4274     /* set up the application menu */
4275     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4276     [svcsMenu setAutoenablesItems: NO];
4277     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4278     [appMenu setAutoenablesItems: NO];
4279     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4280     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4282     [appMenu insertItemWithTitle: @"About Emacs"
4283                           action: @selector (orderFrontStandardAboutPanel:)
4284                    keyEquivalent: @""
4285                          atIndex: 0];
4286     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4287     [appMenu insertItemWithTitle: @"Preferences..."
4288                           action: @selector (showPreferencesWindow:)
4289                    keyEquivalent: @","
4290                          atIndex: 2];
4291     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4292     item = [appMenu insertItemWithTitle: @"Services"
4293                                  action: @selector (menuDown:)
4294                           keyEquivalent: @""
4295                                 atIndex: 4];
4296     [appMenu setSubmenu: svcsMenu forItem: item];
4297     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4298     [appMenu insertItemWithTitle: @"Hide Emacs"
4299                           action: @selector (hide:)
4300                    keyEquivalent: @"h"
4301                          atIndex: 6];
4302     item =  [appMenu insertItemWithTitle: @"Hide Others"
4303                           action: @selector (hideOtherApplications:)
4304                    keyEquivalent: @"h"
4305                          atIndex: 7];
4306     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4307     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4308     [appMenu insertItemWithTitle: @"Quit Emacs"
4309                           action: @selector (terminate:)
4310                    keyEquivalent: @"q"
4311                          atIndex: 9];
4313     item = [mainMenu insertItemWithTitle: ns_app_name
4314                                   action: @selector (menuDown:)
4315                            keyEquivalent: @""
4316                                  atIndex: 0];
4317     [mainMenu setSubmenu: appMenu forItem: item];
4318     [dockMenu insertItemWithTitle: @"New Frame"
4319                            action: @selector (newFrame:)
4320                     keyEquivalent: @""
4321                           atIndex: 0];
4323     [NSApp setMainMenu: mainMenu];
4324     [NSApp setAppleMenu: appMenu];
4325     [NSApp setServicesMenu: svcsMenu];
4326     /* Needed at least on Cocoa, to get dock menu to show windows */
4327     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4329     [[NSNotificationCenter defaultCenter]
4330       addObserver: mainMenu
4331          selector: @selector (trackingNotification:)
4332              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4333     [[NSNotificationCenter defaultCenter]
4334       addObserver: mainMenu
4335          selector: @selector (trackingNotification:)
4336              name: NSMenuDidEndTrackingNotification object: mainMenu];
4337   }
4338 #endif /* MAC OS X menu setup */
4340   /* Register our external input/output types, used for determining
4341      applicable services and also drag/drop eligibility. */
4342   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4343   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4344                       retain];
4345   ns_drag_types = [[NSArray arrayWithObjects:
4346                             NSStringPboardType,
4347                             NSTabularTextPboardType,
4348                             NSFilenamesPboardType,
4349                             NSURLPboardType,
4350                             NSColorPboardType,
4351                             NSFontPboardType, nil] retain];
4353   /* If fullscreen is in init/default-frame-alist, focus isn't set
4354      right for fullscreen windows, so set this.  */
4355   [NSApp activateIgnoringOtherApps:YES];
4357   [NSApp run];
4358   ns_do_open_file = YES;
4360 #ifdef NS_IMPL_GNUSTEP
4361   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4362      We must re-catch it so subprocess works.  */
4363   catch_child_signal ();
4364 #endif
4365   return dpyinfo;
4369 void
4370 ns_term_shutdown (int sig)
4372   [[NSUserDefaults standardUserDefaults] synchronize];
4374   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4375   if (STRINGP (Vauto_save_list_file_name))
4376     unlink (SSDATA (Vauto_save_list_file_name));
4378   if (sig == 0 || sig == SIGTERM)
4379     {
4380       [NSApp terminate: NSApp];
4381     }
4382   else // force a stack trace to happen
4383     {
4384       emacs_abort ();
4385     }
4389 /* ==========================================================================
4391     EmacsApp implementation
4393    ========================================================================== */
4396 @implementation EmacsApp
4398 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
4399 - (id)init
4401   if (self = [super init])
4402     self->isFirst = YES;
4404   return self;
4407 - (void)run
4409     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4411     if (isFirst) [self finishLaunching];
4412     isFirst = NO;
4414     shouldKeepRunning = YES;
4415     do
4416       {
4417         [pool release];
4418         pool = [[NSAutoreleasePool alloc] init];
4420         NSEvent *event =
4421           [self nextEventMatchingMask:NSAnyEventMask
4422                             untilDate:[NSDate distantFuture]
4423                                inMode:NSDefaultRunLoopMode
4424                               dequeue:YES];
4425         [self sendEvent:event];
4426         [self updateWindows];
4427     } while (shouldKeepRunning);
4429     [pool release];
4432 - (void)stop: (id)sender
4434     shouldKeepRunning = NO;
4435     // Stop possible dialog also.  Noop if no dialog present.
4436     // The file dialog still leaks 7k - 10k on 10.9 though.
4437     [super stop:sender];
4439 #endif
4441 - (void)logNotification: (NSNotification *)notification
4443   const char *name = [[notification name] UTF8String];
4444   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4445       && !strstr (name, "WindowNumber"))
4446     NSLog (@"notification: '%@'", [notification name]);
4450 - (void)sendEvent: (NSEvent *)theEvent
4451 /* --------------------------------------------------------------------------
4452      Called when NSApp is running for each event received.  Used to stop
4453      the loop when we choose, since there's no way to just run one iteration.
4454    -------------------------------------------------------------------------- */
4456   int type = [theEvent type];
4457   NSWindow *window = [theEvent window];
4459 /*  NSTRACE (sendEvent); */
4460 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4462 #ifdef NS_IMPL_GNUSTEP
4463   // Keyboard events aren't propagated to file dialogs for some reason.
4464   if ([NSApp modalWindow] != nil &&
4465       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4466     {
4467       [[NSApp modalWindow] sendEvent: theEvent];
4468       return;
4469     }
4470 #endif
4472   if (type == NSApplicationDefined)
4473     {
4474       switch ([theEvent data2])
4475         {
4476 #ifdef NS_IMPL_COCOA
4477         case NSAPP_DATA2_RUNASSCRIPT:
4478           ns_run_ascript ();
4479           [self stop: self];
4480           return;
4481 #endif
4482         case NSAPP_DATA2_RUNFILEDIALOG:
4483           ns_run_file_dialog ();
4484           [self stop: self];
4485           return;
4486         }
4487     }
4489   if (type == NSCursorUpdate && window == nil)
4490     {
4491       fprintf (stderr, "Dropping external cursor update event.\n");
4492       return;
4493     }
4495   if (type == NSApplicationDefined)
4496     {
4497       /* Events posted by ns_send_appdefined interrupt the run loop here.
4498          But, if a modal window is up, an appdefined can still come through,
4499          (e.g., from a makeKeyWindow event) but stopping self also stops the
4500          modal loop. Just defer it until later. */
4501       if ([NSApp modalWindow] == nil)
4502         {
4503           last_appdefined_event_data = [theEvent data1];
4504           [self stop: self];
4505         }
4506       else
4507         {
4508           send_appdefined = YES;
4509         }
4510     }
4513 #ifdef NS_IMPL_COCOA
4514   /* If no dialog and none of our frames have focus and it is a move, skip it.
4515      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4516      such as Wifi, sound, date or similar.
4517      This prevents "spooky" highlighting in the frame under the menu.  */
4518   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4519     {
4520       struct ns_display_info *di;
4521       BOOL has_focus = NO;
4522       for (di = x_display_list; ! has_focus && di; di = di->next)
4523         has_focus = di->x_focus_frame != 0;
4524       if (! has_focus)
4525         return;
4526     }
4527 #endif
4529   [super sendEvent: theEvent];
4533 - (void)showPreferencesWindow: (id)sender
4535   struct frame *emacsframe = SELECTED_FRAME ();
4536   NSEvent *theEvent = [NSApp currentEvent];
4538   if (!emacs_event)
4539     return;
4540   emacs_event->kind = NS_NONKEY_EVENT;
4541   emacs_event->code = KEY_NS_SHOW_PREFS;
4542   emacs_event->modifiers = 0;
4543   EV_TRAILER (theEvent);
4547 - (void)newFrame: (id)sender
4549   struct frame *emacsframe = SELECTED_FRAME ();
4550   NSEvent *theEvent = [NSApp currentEvent];
4552   if (!emacs_event)
4553     return;
4554   emacs_event->kind = NS_NONKEY_EVENT;
4555   emacs_event->code = KEY_NS_NEW_FRAME;
4556   emacs_event->modifiers = 0;
4557   EV_TRAILER (theEvent);
4561 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4562 - (BOOL) openFile: (NSString *)fileName
4564   struct frame *emacsframe = SELECTED_FRAME ();
4565   NSEvent *theEvent = [NSApp currentEvent];
4567   if (!emacs_event)
4568     return NO;
4570   emacs_event->kind = NS_NONKEY_EVENT;
4571   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4572   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4573   ns_input_line = Qnil; /* can be start or cons start,end */
4574   emacs_event->modifiers =0;
4575   EV_TRAILER (theEvent);
4577   return YES;
4581 /* **************************************************************************
4583       EmacsApp delegate implementation
4585    ************************************************************************** */
4587 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4588 /* --------------------------------------------------------------------------
4589      When application is loaded, terminate event loop in ns_term_init
4590    -------------------------------------------------------------------------- */
4592   NSTRACE (applicationDidFinishLaunching);
4593   [NSApp setServicesProvider: NSApp];
4594   ns_send_appdefined (-2);
4598 /* Termination sequences:
4599     C-x C-c:
4600     Cmd-Q:
4601     MenuBar | File | Exit:
4602     Select Quit from App menubar:
4603         -terminate
4604         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4605         ns_term_shutdown()
4607     Select Quit from Dock menu:
4608     Logout attempt:
4609         -appShouldTerminate
4610           Cancel -> Nothing else
4611           Accept ->
4613           -terminate
4614           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4615           ns_term_shutdown()
4619 - (void) terminate: (id)sender
4621   struct frame *emacsframe = SELECTED_FRAME ();
4623   if (!emacs_event)
4624     return;
4626   emacs_event->kind = NS_NONKEY_EVENT;
4627   emacs_event->code = KEY_NS_POWER_OFF;
4628   emacs_event->arg = Qt; /* mark as non-key event */
4629   EV_TRAILER ((id)nil);
4633 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4635   int ret;
4637   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4638     return NSTerminateNow;
4640     ret = NSRunAlertPanel(ns_app_name,
4641                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4642                           @"Save Buffers and Exit", @"Cancel", nil);
4644     if (ret == NSAlertDefaultReturn)
4645         return NSTerminateNow;
4646     else if (ret == NSAlertAlternateReturn)
4647         return NSTerminateCancel;
4648     return NSTerminateNow;  /* just in case */
4651 static int
4652 not_in_argv (NSString *arg)
4654   int k;
4655   const char *a = [arg UTF8String];
4656   for (k = 1; k < initial_argc; ++k)
4657     if (strcmp (a, initial_argv[k]) == 0) return 0;
4658   return 1;
4661 /*   Notification from the Workspace to open a file */
4662 - (BOOL)application: sender openFile: (NSString *)file
4664   if (ns_do_open_file || not_in_argv (file))
4665     [ns_pending_files addObject: file];
4666   return YES;
4670 /*   Open a file as a temporary file */
4671 - (BOOL)application: sender openTempFile: (NSString *)file
4673   if (ns_do_open_file || not_in_argv (file))
4674     [ns_pending_files addObject: file];
4675   return YES;
4679 /*   Notification from the Workspace to open a file noninteractively (?) */
4680 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4682   if (ns_do_open_file || not_in_argv (file))
4683     [ns_pending_files addObject: file];
4684   return YES;
4687 /*   Notification from the Workspace to open multiple files */
4688 - (void)application: sender openFiles: (NSArray *)fileList
4690   NSEnumerator *files = [fileList objectEnumerator];
4691   NSString *file;
4692   /* Don't open files from the command line unconditionally,
4693      Cocoa parses the command line wrong, --option value tries to open value
4694      if --option is the last option.  */
4695   while ((file = [files nextObject]) != nil)
4696     if (ns_do_open_file || not_in_argv (file))
4697       [ns_pending_files addObject: file];
4699   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4704 /* Handle dock menu requests.  */
4705 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4707   return dockMenu;
4711 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4712 - (void)applicationWillBecomeActive: (NSNotification *)notification
4714   //ns_app_active=YES;
4716 - (void)applicationDidBecomeActive: (NSNotification *)notification
4718   NSTRACE (applicationDidBecomeActive);
4720   //ns_app_active=YES;
4722   ns_update_auto_hide_menu_bar ();
4723   // No constraining takes place when the application is not active.
4724   ns_constrain_all_frames ();
4726 - (void)applicationDidResignActive: (NSNotification *)notification
4728   //ns_app_active=NO;
4729   ns_send_appdefined (-1);
4734 /* ==========================================================================
4736     EmacsApp aux handlers for managing event loop
4738    ========================================================================== */
4741 - (void)timeout_handler: (NSTimer *)timedEntry
4742 /* --------------------------------------------------------------------------
4743      The timeout specified to ns_select has passed.
4744    -------------------------------------------------------------------------- */
4746   /*NSTRACE (timeout_handler); */
4747   ns_send_appdefined (-2);
4750 #ifdef NS_IMPL_GNUSTEP
4751 - (void)sendFromMainThread:(id)unused
4753   ns_send_appdefined (nextappdefined);
4755 #endif
4757 - (void)fd_handler:(id)unused
4758 /* --------------------------------------------------------------------------
4759      Check data waiting on file descriptors and terminate if so
4760    -------------------------------------------------------------------------- */
4762   int result;
4763   int waiting = 1, nfds;
4764   char c;
4766   fd_set readfds, writefds, *wfds;
4767   struct timespec timeout, *tmo;
4768   NSAutoreleasePool *pool = nil;
4770   /* NSTRACE (fd_handler); */
4772   for (;;)
4773     {
4774       [pool release];
4775       pool = [[NSAutoreleasePool alloc] init];
4777       if (waiting)
4778         {
4779           fd_set fds;
4780           FD_ZERO (&fds);
4781           FD_SET (selfds[0], &fds);
4782           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4783           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4784             waiting = 0;
4785         }
4786       else
4787         {
4788           pthread_mutex_lock (&select_mutex);
4789           nfds = select_nfds;
4791           if (select_valid & SELECT_HAVE_READ)
4792             readfds = select_readfds;
4793           else
4794             FD_ZERO (&readfds);
4796           if (select_valid & SELECT_HAVE_WRITE)
4797             {
4798               writefds = select_writefds;
4799               wfds = &writefds;
4800             }
4801           else
4802             wfds = NULL;
4803           if (select_valid & SELECT_HAVE_TMO)
4804             {
4805               timeout = select_timeout;
4806               tmo = &timeout;
4807             }
4808           else
4809             tmo = NULL;
4811           pthread_mutex_unlock (&select_mutex);
4813           FD_SET (selfds[0], &readfds);
4814           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4816           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4818           if (result == 0)
4819             ns_send_appdefined (-2);
4820           else if (result > 0)
4821             {
4822               if (FD_ISSET (selfds[0], &readfds))
4823                 {
4824                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4825                     waiting = 1;
4826                 }
4827               else
4828                 {
4829                   pthread_mutex_lock (&select_mutex);
4830                   if (select_valid & SELECT_HAVE_READ)
4831                     select_readfds = readfds;
4832                   if (select_valid & SELECT_HAVE_WRITE)
4833                     select_writefds = writefds;
4834                   if (select_valid & SELECT_HAVE_TMO)
4835                     select_timeout = timeout;
4836                   pthread_mutex_unlock (&select_mutex);
4838                   ns_send_appdefined (result);
4839                 }
4840             }
4841           waiting = 1;
4842         }
4843     }
4848 /* ==========================================================================
4850     Service provision
4852    ========================================================================== */
4854 /* called from system: queue for next pass through event loop */
4855 - (void)requestService: (NSPasteboard *)pboard
4856               userData: (NSString *)userData
4857                  error: (NSString **)error
4859   [ns_pending_service_names addObject: userData];
4860   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4861       SSDATA (ns_string_from_pasteboard (pboard))]];
4865 /* called from ns_read_socket to clear queue */
4866 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4868   struct frame *emacsframe = SELECTED_FRAME ();
4869   NSEvent *theEvent = [NSApp currentEvent];
4871   if (!emacs_event)
4872     return NO;
4874   emacs_event->kind = NS_NONKEY_EVENT;
4875   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4876   ns_input_spi_name = build_string ([name UTF8String]);
4877   ns_input_spi_arg = build_string ([arg UTF8String]);
4878   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4879   EV_TRAILER (theEvent);
4881   return YES;
4885 @end  /* EmacsApp */
4889 /* ==========================================================================
4891     EmacsView implementation
4893    ========================================================================== */
4896 @implementation EmacsView
4898 /* needed to inform when window closed from LISP */
4899 - (void) setWindowClosing: (BOOL)closing
4901   windowClosing = closing;
4905 - (void)dealloc
4907   NSTRACE (EmacsView_dealloc);
4908   [toolbar release];
4909   if (fs_state == FULLSCREEN_BOTH)
4910     [nonfs_window release];
4911   [super dealloc];
4915 /* called on font panel selection */
4916 - (void)changeFont: (id)sender
4918   NSEvent *e = [[self window] currentEvent];
4919   struct face *face = FRAME_DEFAULT_FACE (emacsframe);
4920   struct font *font = face->font;
4921   id newFont;
4922   CGFloat size;
4923   NSFont *nsfont;
4925   NSTRACE (changeFont);
4927   if (!emacs_event)
4928     return;
4930   if (EQ (font->driver->type, Qns))
4931     nsfont = ((struct nsfont_info *)font)->nsfont;
4932 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
4933   else
4934     nsfont = (NSFont *) macfont_get_nsctfont (font);
4935 #endif
4937   if ((newFont = [sender convertFont: nsfont]))
4938     {
4939       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4941       emacs_event->kind = NS_NONKEY_EVENT;
4942       emacs_event->modifiers = 0;
4943       emacs_event->code = KEY_NS_CHANGE_FONT;
4945       size = [newFont pointSize];
4946       ns_input_fontsize = make_number (lrint (size));
4947       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4948       EV_TRAILER (e);
4949     }
4953 - (BOOL)acceptsFirstResponder
4955   NSTRACE (acceptsFirstResponder);
4956   return YES;
4960 - (void)resetCursorRects
4962   NSRect visible = [self visibleRect];
4963   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4964   NSTRACE (resetCursorRects);
4966   if (currentCursor == nil)
4967     currentCursor = [NSCursor arrowCursor];
4969   if (!NSIsEmptyRect (visible))
4970     [self addCursorRect: visible cursor: currentCursor];
4971   [currentCursor setOnMouseEntered: YES];
4976 /*****************************************************************************/
4977 /* Keyboard handling. */
4978 #define NS_KEYLOG 0
4980 - (void)keyDown: (NSEvent *)theEvent
4982   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4983   int code;
4984   unsigned fnKeysym = 0;
4985   static NSMutableArray *nsEvArray;
4986 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4987   static BOOL firstTime = YES;
4988 #endif
4989   int left_is_none;
4990   unsigned int flags = [theEvent modifierFlags];
4992   NSTRACE (keyDown);
4994   /* Rhapsody and OS X give up and down events for the arrow keys */
4995   if (ns_fake_keydown == YES)
4996     ns_fake_keydown = NO;
4997   else if ([theEvent type] != NSKeyDown)
4998     return;
5000   if (!emacs_event)
5001     return;
5003  if (![[self window] isKeyWindow]
5004      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5005      /* we must avoid an infinite loop here. */
5006      && (EmacsView *)[[theEvent window] delegate] != self)
5007    {
5008      /* XXX: There is an occasional condition in which, when Emacs display
5009          updates a different frame from the current one, and temporarily
5010          selects it, then processes some interrupt-driven input
5011          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5012          for some reason that window has its first responder set to the NSView
5013          most recently updated (I guess), which is not the correct one. */
5014      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5015      return;
5016    }
5018   if (nsEvArray == nil)
5019     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5021   [NSCursor setHiddenUntilMouseMoves: YES];
5023   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5024     {
5025       clear_mouse_face (hlinfo);
5026       hlinfo->mouse_face_hidden = 1;
5027     }
5029   if (!processingCompose)
5030     {
5031       /* When using screen sharing, no left or right information is sent,
5032          so use Left key in those cases.  */
5033       int is_left_key, is_right_key;
5035       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5036         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5038       /* (Carbon way: [theEvent keyCode]) */
5040       /* is it a "function key"? */
5041       fnKeysym = (code < 0x00ff && (flags&NSNumericPadKeyMask))
5042         ? ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask)
5043         : ns_convert_key (code);
5045       if (fnKeysym)
5046         {
5047           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5048              because Emacs treats Delete and KP-Delete same (in simple.el). */
5049           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5050 #ifdef NS_IMPL_GNUSTEP
5051               /*  GNUstep uses incompatible keycodes, even for those that are
5052                   supposed to be hardware independent.  Just check for delete.
5053                   Keypad delete does not have keysym 0xFFFF.
5054                   See http://savannah.gnu.org/bugs/?25395
5055               */
5056               || (fnKeysym == 0xFFFF && code == 127)
5057 #endif
5058             )
5059             code = 0xFF08; /* backspace */
5060           else
5061             code = fnKeysym;
5062         }
5064       /* are there modifiers? */
5065       emacs_event->modifiers = 0;
5067       if (flags & NSHelpKeyMask)
5068           emacs_event->modifiers |= hyper_modifier;
5070       if (flags & NSShiftKeyMask)
5071         emacs_event->modifiers |= shift_modifier;
5073       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5074       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5075         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5077       if (is_right_key)
5078         emacs_event->modifiers |= parse_solitary_modifier
5079           (EQ (ns_right_command_modifier, Qleft)
5080            ? ns_command_modifier
5081            : ns_right_command_modifier);
5083       if (is_left_key)
5084         {
5085           emacs_event->modifiers |= parse_solitary_modifier
5086             (ns_command_modifier);
5088           /* if super (default), take input manager's word so things like
5089              dvorak / qwerty layout work */
5090           if (EQ (ns_command_modifier, Qsuper)
5091               && !fnKeysym
5092               && [[theEvent characters] length] != 0)
5093             {
5094               /* XXX: the code we get will be unshifted, so if we have
5095                  a shift modifier, must convert ourselves */
5096               if (!(flags & NSShiftKeyMask))
5097                 code = [[theEvent characters] characterAtIndex: 0];
5098 #if 0
5099               /* this is ugly and also requires linking w/Carbon framework
5100                  (for LMGetKbdType) so for now leave this rare (?) case
5101                  undealt with.. in future look into CGEvent methods */
5102               else
5103                 {
5104                   long smv = GetScriptManagerVariable (smKeyScript);
5105                   Handle uchrHandle = GetResource
5106                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5107                   UInt32 dummy = 0;
5108                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5109                                  [[theEvent characters] characterAtIndex: 0],
5110                                  kUCKeyActionDisplay,
5111                                  (flags & ~NSCommandKeyMask) >> 8,
5112                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5113                                  &dummy, 1, &dummy, &code);
5114                   code &= 0xFF;
5115                 }
5116 #endif
5117             }
5118         }
5120       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5121       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5122         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5124       if (is_right_key)
5125           emacs_event->modifiers |= parse_solitary_modifier
5126               (EQ (ns_right_control_modifier, Qleft)
5127                ? ns_control_modifier
5128                : ns_right_control_modifier);
5130       if (is_left_key)
5131         emacs_event->modifiers |= parse_solitary_modifier
5132           (ns_control_modifier);
5134       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5135           emacs_event->modifiers |=
5136             parse_solitary_modifier (ns_function_modifier);
5138       left_is_none = NILP (ns_alternate_modifier)
5139         || EQ (ns_alternate_modifier, Qnone);
5141       is_right_key = (flags & NSRightAlternateKeyMask)
5142         == NSRightAlternateKeyMask;
5143       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5144         || (! is_right_key
5145             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5147       if (is_right_key)
5148         {
5149           if ((NILP (ns_right_alternate_modifier)
5150                || EQ (ns_right_alternate_modifier, Qnone)
5151                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5152               && !fnKeysym)
5153             {   /* accept pre-interp alt comb */
5154               if ([[theEvent characters] length] > 0)
5155                 code = [[theEvent characters] characterAtIndex: 0];
5156               /*HACK: clear lone shift modifier to stop next if from firing */
5157               if (emacs_event->modifiers == shift_modifier)
5158                 emacs_event->modifiers = 0;
5159             }
5160           else
5161             emacs_event->modifiers |= parse_solitary_modifier
5162               (EQ (ns_right_alternate_modifier, Qleft)
5163                ? ns_alternate_modifier
5164                : ns_right_alternate_modifier);
5165         }
5167       if (is_left_key) /* default = meta */
5168         {
5169           if (left_is_none && !fnKeysym)
5170             {   /* accept pre-interp alt comb */
5171               if ([[theEvent characters] length] > 0)
5172                 code = [[theEvent characters] characterAtIndex: 0];
5173               /*HACK: clear lone shift modifier to stop next if from firing */
5174               if (emacs_event->modifiers == shift_modifier)
5175                 emacs_event->modifiers = 0;
5176             }
5177           else
5178               emacs_event->modifiers |=
5179                 parse_solitary_modifier (ns_alternate_modifier);
5180         }
5182   if (NS_KEYLOG)
5183     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5184              code, fnKeysym, flags, emacs_event->modifiers);
5186       /* if it was a function key or had modifiers, pass it directly to emacs */
5187       if (fnKeysym || (emacs_event->modifiers
5188                        && (emacs_event->modifiers != shift_modifier)
5189                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5190 /*[[theEvent characters] length] */
5191         {
5192           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5193           if (code < 0x20)
5194             code |= (1<<28)|(3<<16);
5195           else if (code == 0x7f)
5196             code |= (1<<28)|(3<<16);
5197           else if (!fnKeysym)
5198             emacs_event->kind = code > 0xFF
5199               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5201           emacs_event->code = code;
5202           EV_TRAILER (theEvent);
5203           processingCompose = NO;
5204           return;
5205         }
5206     }
5209 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5210   /* if we get here we should send the key for input manager processing */
5211   /* Disable warning, there is nothing a user can do about it anyway, and
5212      it does not seem to matter.  */
5213 #if 0
5214   if (firstTime && [[NSInputManager currentInputManager]
5215                      wantsToDelayTextChangeNotifications] == NO)
5216     fprintf (stderr,
5217           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5218 #endif
5219   firstTime = NO;
5220 #endif
5221   if (NS_KEYLOG && !processingCompose)
5222     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5224   processingCompose = YES;
5225   [nsEvArray addObject: theEvent];
5226   [self interpretKeyEvents: nsEvArray];
5227   [nsEvArray removeObject: theEvent];
5231 #ifdef NS_IMPL_COCOA
5232 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5233    decided not to send key-down for.
5234    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5235    This only applies on Tiger and earlier.
5236    If it matches one of these, send it on to keyDown. */
5237 -(void)keyUp: (NSEvent *)theEvent
5239   int flags = [theEvent modifierFlags];
5240   int code = [theEvent keyCode];
5241   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5242       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5243     {
5244       if (NS_KEYLOG)
5245         fprintf (stderr, "keyUp: passed test");
5246       ns_fake_keydown = YES;
5247       [self keyDown: theEvent];
5248     }
5250 #endif
5253 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5256 /* <NSTextInput>: called when done composing;
5257    NOTE: also called when we delete over working text, followed immed.
5258          by doCommandBySelector: deleteBackward: */
5259 - (void)insertText: (id)aString
5261   int code;
5262   int len = [(NSString *)aString length];
5263   int i;
5265   if (NS_KEYLOG)
5266     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5267   processingCompose = NO;
5269   if (!emacs_event)
5270     return;
5272   /* first, clear any working text */
5273   if (workingText != nil)
5274     [self deleteWorkingText];
5276   /* now insert the string as keystrokes */
5277   for (i =0; i<len; i++)
5278     {
5279       code = [aString characterAtIndex: i];
5280       /* TODO: still need this? */
5281       if (code == 0x2DC)
5282         code = '~'; /* 0x7E */
5283       if (code != 32) /* Space */
5284         emacs_event->modifiers = 0;
5285       emacs_event->kind
5286         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5287       emacs_event->code = code;
5288       EV_TRAILER ((id)nil);
5289     }
5293 /* <NSTextInput>: inserts display of composing characters */
5294 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5296   NSString *str = [aString respondsToSelector: @selector (string)] ?
5297     [aString string] : aString;
5298   if (NS_KEYLOG)
5299     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5300            str, (unsigned long)[str length],
5301            (unsigned long)selRange.length,
5302            (unsigned long)selRange.location);
5304   if (workingText != nil)
5305     [self deleteWorkingText];
5306   if ([str length] == 0)
5307     return;
5309   if (!emacs_event)
5310     return;
5312   processingCompose = YES;
5313   workingText = [str copy];
5314   ns_working_text = build_string ([workingText UTF8String]);
5316   emacs_event->kind = NS_TEXT_EVENT;
5317   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5318   EV_TRAILER ((id)nil);
5322 /* delete display of composing characters [not in <NSTextInput>] */
5323 - (void)deleteWorkingText
5325   if (workingText == nil)
5326     return;
5327   if (NS_KEYLOG)
5328     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5329   [workingText release];
5330   workingText = nil;
5331   processingCompose = NO;
5333   if (!emacs_event)
5334     return;
5336   emacs_event->kind = NS_TEXT_EVENT;
5337   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5338   EV_TRAILER ((id)nil);
5342 - (BOOL)hasMarkedText
5344   return workingText != nil;
5348 - (NSRange)markedRange
5350   NSRange rng = workingText != nil
5351     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5352   if (NS_KEYLOG)
5353     NSLog (@"markedRange request");
5354   return rng;
5358 - (void)unmarkText
5360   if (NS_KEYLOG)
5361     NSLog (@"unmark (accept) text");
5362   [self deleteWorkingText];
5363   processingCompose = NO;
5367 /* used to position char selection windows, etc. */
5368 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5370   NSRect rect;
5371   NSPoint pt;
5372   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5373   if (NS_KEYLOG)
5374     NSLog (@"firstRectForCharRange request");
5376   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5377   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5378   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5379   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5380                                        +FRAME_LINE_HEIGHT (emacsframe));
5382   pt = [self convertPoint: pt toView: nil];
5383   pt = [[self window] convertBaseToScreen: pt];
5384   rect.origin = pt;
5385   return rect;
5389 - (NSInteger)conversationIdentifier
5391   return (NSInteger)self;
5395 - (void)doCommandBySelector: (SEL)aSelector
5397   if (NS_KEYLOG)
5398     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5400   processingCompose = NO;
5401   if (aSelector == @selector (deleteBackward:))
5402     {
5403       /* happens when user backspaces over an ongoing composition:
5404          throw a 'delete' into the event queue */
5405       if (!emacs_event)
5406         return;
5407       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5408       emacs_event->code = 0xFF08;
5409       EV_TRAILER ((id)nil);
5410     }
5413 - (NSArray *)validAttributesForMarkedText
5415   static NSArray *arr = nil;
5416   if (arr == nil) arr = [NSArray new];
5417  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5418   return arr;
5421 - (NSRange)selectedRange
5423   if (NS_KEYLOG)
5424     NSLog (@"selectedRange request");
5425   return NSMakeRange (NSNotFound, 0);
5428 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5429     GNUSTEP_GUI_MINOR_VERSION > 22
5430 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5431 #else
5432 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5433 #endif
5435   if (NS_KEYLOG)
5436     NSLog (@"characterIndexForPoint request");
5437   return 0;
5440 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5442   static NSAttributedString *str = nil;
5443   if (str == nil) str = [NSAttributedString new];
5444   if (NS_KEYLOG)
5445     NSLog (@"attributedSubstringFromRange request");
5446   return str;
5449 /* End <NSTextInput> impl. */
5450 /*****************************************************************************/
5453 /* This is what happens when the user presses a mouse button.  */
5454 - (void)mouseDown: (NSEvent *)theEvent
5456   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5457   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5459   NSTRACE (mouseDown);
5461   [self deleteWorkingText];
5463   if (!emacs_event)
5464     return;
5466   dpyinfo->last_mouse_frame = emacsframe;
5467   /* appears to be needed to prevent spurious movement events generated on
5468      button clicks */
5469   emacsframe->mouse_moved = 0;
5471   if ([theEvent type] == NSScrollWheel)
5472     {
5473       CGFloat delta = [theEvent deltaY];
5474       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5475       if (delta == 0)
5476         return;
5477       emacs_event->kind = WHEEL_EVENT;
5478       emacs_event->code = 0;
5479       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5480         ((delta > 0) ? up_modifier : down_modifier);
5481     }
5482   else
5483     {
5484       emacs_event->kind = MOUSE_CLICK_EVENT;
5485       emacs_event->code = EV_BUTTON (theEvent);
5486       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5487                              | EV_UDMODIFIERS (theEvent);
5488     }
5489   XSETINT (emacs_event->x, lrint (p.x));
5490   XSETINT (emacs_event->y, lrint (p.y));
5491   EV_TRAILER (theEvent);
5495 - (void)rightMouseDown: (NSEvent *)theEvent
5497   NSTRACE (rightMouseDown);
5498   [self mouseDown: theEvent];
5502 - (void)otherMouseDown: (NSEvent *)theEvent
5504   NSTRACE (otherMouseDown);
5505   [self mouseDown: theEvent];
5509 - (void)mouseUp: (NSEvent *)theEvent
5511   NSTRACE (mouseUp);
5512   [self mouseDown: theEvent];
5516 - (void)rightMouseUp: (NSEvent *)theEvent
5518   NSTRACE (rightMouseUp);
5519   [self mouseDown: theEvent];
5523 - (void)otherMouseUp: (NSEvent *)theEvent
5525   NSTRACE (otherMouseUp);
5526   [self mouseDown: theEvent];
5530 - (void) scrollWheel: (NSEvent *)theEvent
5532   NSTRACE (scrollWheel);
5533   [self mouseDown: theEvent];
5537 /* Tell emacs the mouse has moved. */
5538 - (void)mouseMoved: (NSEvent *)e
5540   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5541   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5542   Lisp_Object frame;
5543   NSPoint pt;
5545 //  NSTRACE (mouseMoved);
5547   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
5548   pt = [self convertPoint: [e locationInWindow] fromView: nil];
5549   dpyinfo->last_mouse_motion_x = pt.x;
5550   dpyinfo->last_mouse_motion_y = pt.y;
5552   /* update any mouse face */
5553   if (hlinfo->mouse_face_hidden)
5554     {
5555       hlinfo->mouse_face_hidden = 0;
5556       clear_mouse_face (hlinfo);
5557     }
5559   /* tooltip handling */
5560   previous_help_echo_string = help_echo_string;
5561   help_echo_string = Qnil;
5563   if (!NILP (Vmouse_autoselect_window))
5564     {
5565       NSTRACE (mouse_autoselect_window);
5566       static Lisp_Object last_mouse_window;
5567       Lisp_Object window
5568         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
5570       if (WINDOWP (window)
5571           && !EQ (window, last_mouse_window)
5572           && !EQ (window, selected_window)
5573           && (focus_follows_mouse
5574               || (EQ (XWINDOW (window)->frame,
5575                       XWINDOW (selected_window)->frame))))
5576         {
5577           NSTRACE (in_window);
5578           emacs_event->kind = SELECT_WINDOW_EVENT;
5579           emacs_event->frame_or_window = window;
5580           EV_TRAILER2 (e);
5581         }
5582       /* Remember the last window where we saw the mouse.  */
5583       last_mouse_window = window;
5584     }
5586   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
5587     help_echo_string = previous_help_echo_string;
5589   XSETFRAME (frame, emacsframe);
5590   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5591     {
5592       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5593          (note_mouse_highlight), which is called through the
5594          note_mouse_movement () call above */
5595       gen_help_event (help_echo_string, frame, help_echo_window,
5596                       help_echo_object, help_echo_pos);
5597     }
5598   else
5599     {
5600       help_echo_string = Qnil;
5601       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5602     }
5604   if (emacsframe->mouse_moved && send_appdefined)
5605     ns_send_appdefined (-1);
5609 - (void)mouseDragged: (NSEvent *)e
5611   NSTRACE (mouseDragged);
5612   [self mouseMoved: e];
5616 - (void)rightMouseDragged: (NSEvent *)e
5618   NSTRACE (rightMouseDragged);
5619   [self mouseMoved: e];
5623 - (void)otherMouseDragged: (NSEvent *)e
5625   NSTRACE (otherMouseDragged);
5626   [self mouseMoved: e];
5630 - (BOOL)windowShouldClose: (id)sender
5632   NSEvent *e =[[self window] currentEvent];
5634   NSTRACE (windowShouldClose);
5635   windowClosing = YES;
5636   if (!emacs_event)
5637     return NO;
5638   emacs_event->kind = DELETE_WINDOW_EVENT;
5639   emacs_event->modifiers = 0;
5640   emacs_event->code = 0;
5641   EV_TRAILER (e);
5642   /* Don't close this window, let this be done from lisp code.  */
5643   return NO;
5646 - (void) updateFrameSize: (BOOL) delay;
5648   NSWindow *window = [self window];
5649   NSRect wr = [window frame];
5650   int extra = 0;
5651   int gsextra = 0;
5652 #ifdef NS_IMPL_GNUSTEP
5653   gsextra = 3;
5654 #endif
5656   int oldc = cols, oldr = rows;
5657   int oldw = FRAME_PIXEL_WIDTH (emacsframe),
5658     oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5659   int neww, newh;
5661   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, wr.size.width + gsextra);
5663   if (cols < MINWIDTH)
5664     cols = MINWIDTH;
5666   if (! [self isFullscreen])
5667     {
5668       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5669         + FRAME_TOOLBAR_HEIGHT (emacsframe) - gsextra;
5670     }
5672   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, wr.size.height - extra);
5674   if (rows < MINHEIGHT)
5675     rows = MINHEIGHT;
5677   neww = (int)wr.size.width - emacsframe->border_width;
5678   newh = (int)wr.size.height - extra;
5680   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5681     {
5682       NSView *view = FRAME_NS_VIEW (emacsframe);
5683       NSWindow *win = [view window];
5684       NSSize sz = [win resizeIncrements];
5686       FRAME_PIXEL_WIDTH (emacsframe) = neww;
5687       FRAME_PIXEL_HEIGHT (emacsframe) = newh;
5688       change_frame_size (emacsframe, cols, rows, 0, delay, 0, 0);
5689       SET_FRAME_GARBAGED (emacsframe);
5690       cancel_mouse_face (emacsframe);
5692       // Did resize increments change because of a font change?
5693       if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5694           sz.height != FRAME_LINE_HEIGHT (emacsframe))
5695         {
5696           sz.width = FRAME_COLUMN_WIDTH (emacsframe);
5697           sz.height = FRAME_LINE_HEIGHT (emacsframe);
5698           [win setResizeIncrements: sz];
5699         }
5701       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5702       [self windowDidMove:nil];   // Update top/left.
5703     }
5706 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5707 /* normalize frame to gridded text size */
5709   int extra = 0;
5710   int gsextra = 0;
5711 #ifdef NS_IMPL_GNUSTEP
5712   gsextra = 3;
5713 #endif
5715   NSTRACE (windowWillResize);
5716 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5718   if (fs_state == FULLSCREEN_MAXIMIZED
5719       && (maximized_width != (int)frameSize.width
5720           || maximized_height != (int)frameSize.height))
5721     [self setFSValue: FULLSCREEN_NONE];
5722   else if (fs_state == FULLSCREEN_WIDTH
5723            && maximized_width != (int)frameSize.width)
5724     [self setFSValue: FULLSCREEN_NONE];
5725   else if (fs_state == FULLSCREEN_HEIGHT
5726            && maximized_height != (int)frameSize.height)
5727     [self setFSValue: FULLSCREEN_NONE];
5728   if (fs_state == FULLSCREEN_NONE)
5729     maximized_width = maximized_height = -1;
5731   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5732                                          frameSize.width + gsextra);
5733   if (cols < MINWIDTH)
5734     cols = MINWIDTH;
5736   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5737                                            frameSize.height - extra);
5738   if (rows < MINHEIGHT)
5739     rows = MINHEIGHT;
5740 #ifdef NS_IMPL_COCOA
5741   {
5742     /* this sets window title to have size in it; the wm does this under GS */
5743     NSRect r = [[self window] frame];
5744     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5745       {
5746         if (old_title != 0)
5747           {
5748             xfree (old_title);
5749             old_title = 0;
5750           }
5751       }
5752     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5753       {
5754         char *size_title;
5755         NSWindow *window = [self window];
5756         if (old_title == 0)
5757           {
5758             char *t = strdup ([[[self window] title] UTF8String]);
5759             char *pos = strstr (t, "  â€”  ");
5760             if (pos)
5761               *pos = '\0';
5762             old_title = t;
5763           }
5764         size_title = xmalloc (strlen (old_title) + 40);
5765         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5766         [window setTitle: [NSString stringWithUTF8String: size_title]];
5767         [window display];
5768         xfree (size_title);
5769       }
5770   }
5771 #endif /* NS_IMPL_COCOA */
5772 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5774   return frameSize;
5778 - (void)windowDidResize: (NSNotification *)notification
5780   if (! [self fsIsNative])
5781     {
5782       NSWindow *theWindow = [notification object];
5783       /* We can get notification on the non-FS window when in
5784          fullscreen mode.  */
5785       if ([self window] != theWindow) return;
5786     }
5788 #ifdef NS_IMPL_GNUSTEP
5789   NSWindow *theWindow = [notification object];
5791    /* In GNUstep, at least currently, it's possible to get a didResize
5792       without getting a willResize.. therefore we need to act as if we got
5793       the willResize now */
5794   NSSize sz = [theWindow frame].size;
5795   sz = [self windowWillResize: theWindow toSize: sz];
5796 #endif /* NS_IMPL_GNUSTEP */
5798   NSTRACE (windowDidResize);
5799 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5801 if (cols > 0 && rows > 0)
5802     {
5803       [self updateFrameSize: YES];
5804     }
5806   ns_send_appdefined (-1);
5809 #ifdef NS_IMPL_COCOA
5810 - (void)viewDidEndLiveResize
5812   [super viewDidEndLiveResize];
5813   if (old_title != 0)
5814     {
5815       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
5816       xfree (old_title);
5817       old_title = 0;
5818     }
5819   maximizing_resize = NO;
5821 #endif /* NS_IMPL_COCOA */
5824 - (void)windowDidBecomeKey: (NSNotification *)notification
5825 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5827   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5828   struct frame *old_focus = dpyinfo->x_focus_frame;
5830   NSTRACE (windowDidBecomeKey);
5832   if (emacsframe != old_focus)
5833     dpyinfo->x_focus_frame = emacsframe;
5835   ns_frame_rehighlight (emacsframe);
5837   if (emacs_event)
5838     {
5839       emacs_event->kind = FOCUS_IN_EVENT;
5840       EV_TRAILER ((id)nil);
5841     }
5845 - (void)windowDidResignKey: (NSNotification *)notification
5846 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5848   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5849   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
5850   NSTRACE (windowDidResignKey);
5852   if (is_focus_frame)
5853     dpyinfo->x_focus_frame = 0;
5855   ns_frame_rehighlight (emacsframe);
5857   /* FIXME: for some reason needed on second and subsequent clicks away
5858             from sole-frame Emacs to get hollow box to show */
5859   if (!windowClosing && [[self window] isVisible] == YES)
5860     {
5861       x_update_cursor (emacsframe, 1);
5862       x_set_frame_alpha (emacsframe);
5863     }
5865   if (emacs_event && is_focus_frame)
5866     {
5867       [self deleteWorkingText];
5868       emacs_event->kind = FOCUS_OUT_EVENT;
5869       EV_TRAILER ((id)nil);
5870     }
5874 - (void)windowWillMiniaturize: sender
5876   NSTRACE (windowWillMiniaturize);
5880 - (BOOL)isFlipped
5882   return YES;
5886 - (BOOL)isOpaque
5888   return NO;
5892 - initFrameFromEmacs: (struct frame *)f
5894   NSRect r, wr;
5895   Lisp_Object tem;
5896   NSWindow *win;
5897   NSSize sz;
5898   NSColor *col;
5899   NSString *name;
5901   NSTRACE (initFrameFromEmacs);
5903   windowClosing = NO;
5904   processingCompose = NO;
5905   scrollbarsNeedingUpdate = 0;
5906   fs_state = FULLSCREEN_NONE;
5907   fs_before_fs = next_maximized = -1;
5908 #ifdef HAVE_NATIVE_FS
5909   fs_is_native = ns_use_native_fullscreen;
5910 #else
5911   fs_is_native = NO;
5912 #endif
5913   maximized_width = maximized_height = -1;
5914   nonfs_window = nil;
5916 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5918   ns_userRect = NSMakeRect (0, 0, 0, 0);
5919   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5920                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5921   [self initWithFrame: r];
5922   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5924   FRAME_NS_VIEW (f) = self;
5925   emacsframe = f;
5926 #ifdef NS_IMPL_COCOA
5927   old_title = 0;
5928   maximizing_resize = NO;
5929 #endif
5931   win = [[EmacsWindow alloc]
5932             initWithContentRect: r
5933                       styleMask: (NSResizableWindowMask |
5934 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5935                                   NSTitledWindowMask |
5936 #endif
5937                                   NSMiniaturizableWindowMask |
5938                                   NSClosableWindowMask)
5939                         backing: NSBackingStoreBuffered
5940                           defer: YES];
5942 #ifdef HAVE_NATIVE_FS
5943     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
5944 #endif
5946   wr = [win frame];
5947   bwidth = f->border_width = wr.size.width - r.size.width;
5948   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5950   [win setAcceptsMouseMovedEvents: YES];
5951   [win setDelegate: self];
5952   [win useOptimizedDrawing: YES];
5954   sz.width = FRAME_COLUMN_WIDTH (f);
5955   sz.height = FRAME_LINE_HEIGHT (f);
5956   [win setResizeIncrements: sz];
5958   [[win contentView] addSubview: self];
5960   if (ns_drag_types)
5961     [self registerForDraggedTypes: ns_drag_types];
5963   tem = f->name;
5964   name = [NSString stringWithUTF8String:
5965                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5966   [win setTitle: name];
5968   /* toolbar support */
5969   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5970                          [NSString stringWithFormat: @"Emacs Frame %d",
5971                                    ns_window_num]];
5972   [win setToolbar: toolbar];
5973   [toolbar setVisible: NO];
5974 #ifdef NS_IMPL_COCOA
5975   {
5976     NSButton *toggleButton;
5977   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5978   [toggleButton setTarget: self];
5979   [toggleButton setAction: @selector (toggleToolbar: )];
5980   }
5981 #endif
5982   FRAME_TOOLBAR_HEIGHT (f) = 0;
5984   tem = f->icon_name;
5985   if (!NILP (tem))
5986     [win setMiniwindowTitle:
5987            [NSString stringWithUTF8String: SSDATA (tem)]];
5989   {
5990     NSScreen *screen = [win screen];
5992     if (screen != 0)
5993       [win setFrameTopLeftPoint: NSMakePoint
5994            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5995             IN_BOUND (-SCREENMAX,
5996                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5997   }
5999   [win makeFirstResponder: self];
6001   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6002                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6003   [win setBackgroundColor: col];
6004   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6005     [win setOpaque: NO];
6007   [self allocateGState];
6009   [NSApp registerServicesMenuSendTypes: ns_send_types
6010                            returnTypes: nil];
6012   ns_window_num++;
6013   return self;
6017 - (void)windowDidMove: sender
6019   NSWindow *win = [self window];
6020   NSRect r = [win frame];
6021   NSArray *screens = [NSScreen screens];
6022   NSScreen *screen = [screens objectAtIndex: 0];
6024   NSTRACE (windowDidMove);
6026   if (!emacsframe->output_data.ns)
6027     return;
6028   if (screen != nil)
6029     {
6030       emacsframe->left_pos = r.origin.x;
6031       emacsframe->top_pos =
6032         [screen frame].size.height - (r.origin.y + r.size.height);
6033     }
6037 /* Called AFTER method below, but before our windowWillResize call there leads
6038    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
6039    location so set_window_size moves the frame. */
6040 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6042   emacsframe->output_data.ns->zooming = 1;
6043   return YES;
6047 /* Override to do something slightly nonstandard, but nice.  First click on
6048    zoom button will zoom vertically.  Second will zoom completely.  Third
6049    returns to original. */
6050 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6051                         defaultFrame:(NSRect)defaultFrame
6053   NSRect result = [sender frame];
6055   NSTRACE (windowWillUseStandardFrame);
6057   if (fs_before_fs != -1) /* Entering fullscreen */
6058       {
6059         result = defaultFrame;
6060       }
6061   else if (next_maximized == FULLSCREEN_HEIGHT
6062       || (next_maximized == -1
6063           && abs (defaultFrame.size.height - result.size.height)
6064           > FRAME_LINE_HEIGHT (emacsframe)))
6065     {
6066       /* first click */
6067       ns_userRect = result;
6068       maximized_height = result.size.height = defaultFrame.size.height;
6069       maximized_width = -1;
6070       result.origin.y = defaultFrame.origin.y;
6071       [self setFSValue: FULLSCREEN_HEIGHT];
6072 #ifdef NS_IMPL_COCOA
6073       maximizing_resize = YES;
6074 #endif
6075     }
6076   else if (next_maximized == FULLSCREEN_WIDTH)
6077     {
6078       ns_userRect = result;
6079       maximized_width = result.size.width = defaultFrame.size.width;
6080       maximized_height = -1;
6081       result.origin.x = defaultFrame.origin.x;
6082       [self setFSValue: FULLSCREEN_WIDTH];
6083     }
6084   else if (next_maximized == FULLSCREEN_MAXIMIZED
6085            || (next_maximized == -1
6086                && abs (defaultFrame.size.width - result.size.width)
6087                > FRAME_COLUMN_WIDTH (emacsframe)))
6088     {
6089       result = defaultFrame;  /* second click */
6090       maximized_width = result.size.width;
6091       maximized_height = result.size.height;
6092       [self setFSValue: FULLSCREEN_MAXIMIZED];
6093 #ifdef NS_IMPL_COCOA
6094       maximizing_resize = YES;
6095 #endif
6096     }
6097   else
6098     {
6099       /* restore */
6100       result = ns_userRect.size.height ? ns_userRect : result;
6101       ns_userRect = NSMakeRect (0, 0, 0, 0);
6102 #ifdef NS_IMPL_COCOA
6103       maximizing_resize = fs_state != FULLSCREEN_NONE;
6104 #endif
6105       [self setFSValue: FULLSCREEN_NONE];
6106       maximized_width = maximized_height = -1;
6107     }
6109   if (fs_before_fs == -1) next_maximized = -1;
6110   [self windowWillResize: sender toSize: result.size];
6111   return result;
6115 - (void)windowDidDeminiaturize: sender
6117   NSTRACE (windowDidDeminiaturize);
6118   if (!emacsframe->output_data.ns)
6119     return;
6121   SET_FRAME_ICONIFIED (emacsframe, 0);
6122   SET_FRAME_VISIBLE (emacsframe, 1);
6123   windows_or_buffers_changed = 63;
6125   if (emacs_event)
6126     {
6127       emacs_event->kind = DEICONIFY_EVENT;
6128       EV_TRAILER ((id)nil);
6129     }
6133 - (void)windowDidExpose: sender
6135   NSTRACE (windowDidExpose);
6136   if (!emacsframe->output_data.ns)
6137     return;
6139   SET_FRAME_VISIBLE (emacsframe, 1);
6140   SET_FRAME_GARBAGED (emacsframe);
6142   if (send_appdefined)
6143     ns_send_appdefined (-1);
6147 - (void)windowDidMiniaturize: sender
6149   NSTRACE (windowDidMiniaturize);
6150   if (!emacsframe->output_data.ns)
6151     return;
6153   SET_FRAME_ICONIFIED (emacsframe, 1);
6154   SET_FRAME_VISIBLE (emacsframe, 0);
6156   if (emacs_event)
6157     {
6158       emacs_event->kind = ICONIFY_EVENT;
6159       EV_TRAILER ((id)nil);
6160     }
6163 #ifdef HAVE_NATIVE_FS
6164 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6165       willUseFullScreenPresentationOptions:
6166   (NSApplicationPresentationOptions)proposedOptions
6168   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6170 #endif
6172 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6174   fs_before_fs = fs_state;
6177 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6179   [self setFSValue: FULLSCREEN_BOTH];
6180   if (! [self fsIsNative])
6181     {
6182       [self windowDidBecomeKey:notification];
6183       [nonfs_window orderOut:self];
6184     }
6185   else
6186     {
6187       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
6188 #ifdef NS_IMPL_COCOA
6189 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6190       unsigned val = (unsigned)[NSApp presentationOptions];
6192       // OSX 10.7 bug fix, the menu won't appear without this.
6193       // val is non-zero on other OSX versions.
6194       if (val == 0)
6195         {
6196           NSApplicationPresentationOptions options
6197             = NSApplicationPresentationAutoHideDock
6198             | NSApplicationPresentationAutoHideMenuBar
6199             | NSApplicationPresentationFullScreen
6200             | NSApplicationPresentationAutoHideToolbar;
6202           [NSApp setPresentationOptions: options];
6203         }
6204 #endif
6205 #endif
6206       [toolbar setVisible:tbar_visible];
6207     }
6210 - (void)windowWillExitFullScreen:(NSNotification *)notification
6212   if (next_maximized != -1)
6213     fs_before_fs = next_maximized;
6216 - (void)windowDidExitFullScreen:(NSNotification *)notification
6218   [self setFSValue: fs_before_fs];
6219   fs_before_fs = -1;
6220 #ifdef HAVE_NATIVE_FS
6221   [self updateCollectionBehaviour];
6222 #endif
6223   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6224     {
6225       [toolbar setVisible:YES];
6226       update_frame_tool_bar (emacsframe);
6227       [self updateFrameSize:YES];
6228       [[self window] display];
6229     }
6230   else
6231     [toolbar setVisible:NO];
6233   if (next_maximized != -1)
6234     [[self window] performZoom:self];
6237 - (BOOL)fsIsNative
6239   return fs_is_native;
6242 - (BOOL)isFullscreen
6244   if (! fs_is_native) return nonfs_window != nil;
6245 #ifdef HAVE_NATIVE_FS
6246   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6247 #else
6248   return NO;
6249 #endif
6252 #ifdef HAVE_NATIVE_FS
6253 - (void)updateCollectionBehaviour
6255   if (! [self isFullscreen])
6256     {
6257       NSWindow *win = [self window];
6258       NSWindowCollectionBehavior b = [win collectionBehavior];
6259       if (ns_use_native_fullscreen)
6260         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6261       else
6262         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6264       [win setCollectionBehavior: b];
6265       fs_is_native = ns_use_native_fullscreen;
6266     }
6268 #endif
6270 - (void)toggleFullScreen: (id)sender
6272   NSWindow *w, *fw;
6273   BOOL onFirstScreen;
6274   struct frame *f;
6275   NSSize sz;
6276   NSRect r, wr;
6277   NSColor *col;
6279   if (fs_is_native)
6280     {
6281 #ifdef HAVE_NATIVE_FS
6282       [[self window] toggleFullScreen:sender];
6283 #endif
6284       return;
6285     }
6287   w = [self window];
6288   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6289   f = emacsframe;
6290   wr = [w frame];
6291   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6292                                  (FRAME_DEFAULT_FACE (f)),
6293                                  f);
6295   sz.width = FRAME_COLUMN_WIDTH (f);
6296   sz.height = FRAME_LINE_HEIGHT (f);
6298   if (fs_state != FULLSCREEN_BOTH)
6299     {
6300       /* Hide dock and menubar if we are on the primary screen.  */
6301       if (onFirstScreen)
6302         {
6303 #if defined (NS_IMPL_COCOA) && \
6304   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6305           NSApplicationPresentationOptions options
6306             = NSApplicationPresentationAutoHideDock
6307             | NSApplicationPresentationAutoHideMenuBar;
6309           [NSApp setPresentationOptions: options];
6310 #else
6311           [NSMenu setMenuBarVisible:NO];
6312 #endif
6313         }
6315       fw = [[EmacsFSWindow alloc]
6316                        initWithContentRect:[w contentRectForFrameRect:wr]
6317                                  styleMask:NSBorderlessWindowMask
6318                                    backing:NSBackingStoreBuffered
6319                                      defer:YES
6320                                     screen:[w screen]];
6322       [fw setContentView:[w contentView]];
6323       [fw setTitle:[w title]];
6324       [fw setDelegate:self];
6325       [fw setAcceptsMouseMovedEvents: YES];
6326       [fw useOptimizedDrawing: YES];
6327       [fw setResizeIncrements: sz];
6328       [fw setBackgroundColor: col];
6329       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6330         [fw setOpaque: NO];
6332       f->border_width = 0;
6333       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6334       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6335       FRAME_TOOLBAR_HEIGHT (f) = 0;
6337       nonfs_window = w;
6339       [self windowWillEnterFullScreen:nil];
6340       [fw makeKeyAndOrderFront:NSApp];
6341       [fw makeFirstResponder:self];
6342       [w orderOut:self];
6343       r = [fw frameRectForContentRect:[[fw screen] frame]];
6344       [fw setFrame: r display:YES animate:YES];
6345       [self windowDidEnterFullScreen:nil];
6346       [fw display];
6347     }
6348   else
6349     {
6350       fw = w;
6351       w = nonfs_window;
6352       nonfs_window = nil;
6354       if (onFirstScreen)
6355         {
6356 #if defined (NS_IMPL_COCOA) && \
6357   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6358           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6359 #else
6360           [NSMenu setMenuBarVisible:YES];
6361 #endif
6362         }
6364       [w setContentView:[fw contentView]];
6365       [w setResizeIncrements: sz];
6366       [w setBackgroundColor: col];
6367       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6368         [w setOpaque: NO];
6370       f->border_width = bwidth;
6371       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6372       if (FRAME_EXTERNAL_TOOL_BAR (f))
6373         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6375       [self windowWillExitFullScreen:nil];
6376       [fw setFrame: [w frame] display:YES animate:YES];
6377       [fw close];
6378       [w makeKeyAndOrderFront:NSApp];
6379       [self windowDidExitFullScreen:nil];
6380       [self updateFrameSize:YES];
6381     }
6384 - (void)handleFS
6386   if (fs_state != emacsframe->want_fullscreen)
6387     {
6388       if (fs_state == FULLSCREEN_BOTH)
6389         {
6390           [self toggleFullScreen:self];
6391         }
6393       switch (emacsframe->want_fullscreen)
6394         {
6395         case FULLSCREEN_BOTH:
6396           [self toggleFullScreen:self];
6397           break;
6398         case FULLSCREEN_WIDTH:
6399           next_maximized = FULLSCREEN_WIDTH;
6400           if (fs_state != FULLSCREEN_BOTH)
6401             [[self window] performZoom:self];
6402           break;
6403         case FULLSCREEN_HEIGHT:
6404           next_maximized = FULLSCREEN_HEIGHT;
6405           if (fs_state != FULLSCREEN_BOTH)
6406             [[self window] performZoom:self];
6407           break;
6408         case FULLSCREEN_MAXIMIZED:
6409           next_maximized = FULLSCREEN_MAXIMIZED;
6410           if (fs_state != FULLSCREEN_BOTH)
6411             [[self window] performZoom:self];
6412           break;
6413         case FULLSCREEN_NONE:
6414           if (fs_state != FULLSCREEN_BOTH)
6415             {
6416               next_maximized = FULLSCREEN_NONE;
6417               [[self window] performZoom:self];
6418             }
6419           break;
6420         }
6422       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6423     }
6427 - (void) setFSValue: (int)value
6429   Lisp_Object lval = Qnil;
6430   switch (value)
6431     {
6432     case FULLSCREEN_BOTH:
6433       lval = Qfullboth;
6434       break;
6435     case FULLSCREEN_WIDTH:
6436       lval = Qfullwidth;
6437       break;
6438     case FULLSCREEN_HEIGHT:
6439       lval = Qfullheight;
6440       break;
6441     case FULLSCREEN_MAXIMIZED:
6442       lval = Qmaximized;
6443       break;
6444     }
6445   store_frame_param (emacsframe, Qfullscreen, lval);
6446   fs_state = value;
6449 - (void)mouseEntered: (NSEvent *)theEvent
6451   NSTRACE (mouseEntered);
6452   if (emacsframe)
6453     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6454       = EV_TIMESTAMP (theEvent);
6458 - (void)mouseExited: (NSEvent *)theEvent
6460   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6462   NSTRACE (mouseExited);
6464   if (!hlinfo)
6465     return;
6467   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6468     = EV_TIMESTAMP (theEvent);
6470   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6471     {
6472       clear_mouse_face (hlinfo);
6473       hlinfo->mouse_face_mouse_frame = 0;
6474     }
6478 - menuDown: sender
6480   NSTRACE (menuDown);
6481   if (context_menu_value == -1)
6482     context_menu_value = [sender tag];
6483   else
6484     {
6485       NSInteger tag = [sender tag];
6486       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6487                                     emacsframe->menu_bar_vector,
6488                                     (void *)tag);
6489     }
6491   ns_send_appdefined (-1);
6492   return self;
6496 - (EmacsToolbar *)toolbar
6498   return toolbar;
6502 /* this gets called on toolbar button click */
6503 - toolbarClicked: (id)item
6505   NSEvent *theEvent;
6506   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6508   NSTRACE (toolbarClicked);
6510   if (!emacs_event)
6511     return self;
6513   /* send first event (for some reason two needed) */
6514   theEvent = [[self window] currentEvent];
6515   emacs_event->kind = TOOL_BAR_EVENT;
6516   XSETFRAME (emacs_event->arg, emacsframe);
6517   EV_TRAILER (theEvent);
6519   emacs_event->kind = TOOL_BAR_EVENT;
6520 /*   XSETINT (emacs_event->code, 0); */
6521   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6522                            idx + TOOL_BAR_ITEM_KEY);
6523   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6524   EV_TRAILER (theEvent);
6525   return self;
6529 - toggleToolbar: (id)sender
6531   if (!emacs_event)
6532     return self;
6534   emacs_event->kind = NS_NONKEY_EVENT;
6535   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6536   EV_TRAILER ((id)nil);
6537   return self;
6541 - (void)drawRect: (NSRect)rect
6543   int x = NSMinX (rect), y = NSMinY (rect);
6544   int width = NSWidth (rect), height = NSHeight (rect);
6546   NSTRACE (drawRect);
6548   if (!emacsframe || !emacsframe->output_data.ns)
6549     return;
6551   ns_clear_frame_area (emacsframe, x, y, width, height);
6552   expose_frame (emacsframe, x, y, width, height);
6554   /*
6555     drawRect: may be called (at least in OS X 10.5) for invisible
6556     views as well for some reason.  Thus, do not infer visibility
6557     here.
6559     emacsframe->async_visible = 1;
6560     emacsframe->async_iconified = 0;
6561   */
6565 /* NSDraggingDestination protocol methods.  Actually this is not really a
6566    protocol, but a category of Object.  O well...  */
6568 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6570   NSTRACE (draggingEntered);
6571   return NSDragOperationGeneric;
6575 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6577   return YES;
6581 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6583   id pb;
6584   int x, y;
6585   NSString *type;
6586   NSEvent *theEvent = [[self window] currentEvent];
6587   NSPoint position;
6589   NSTRACE (performDragOperation);
6591   if (!emacs_event)
6592     return NO;
6594   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6595   x = lrint (position.x);  y = lrint (position.y);
6597   pb = [sender draggingPasteboard];
6598   type = [pb availableTypeFromArray: ns_drag_types];
6599   if (type == 0)
6600     {
6601       return NO;
6602     }
6603   else if ([type isEqualToString: NSFilenamesPboardType])
6604     {
6605       NSArray *files;
6606       NSEnumerator *fenum;
6607       NSString *file;
6609       if (!(files = [pb propertyListForType: type]))
6610         return NO;
6612       fenum = [files objectEnumerator];
6613       while ( (file = [fenum nextObject]) )
6614         {
6615           emacs_event->kind = NS_NONKEY_EVENT;
6616           emacs_event->code = KEY_NS_DRAG_FILE;
6617           XSETINT (emacs_event->x, x);
6618           XSETINT (emacs_event->y, y);
6619           ns_input_file = append2 (ns_input_file,
6620                                    build_string ([file UTF8String]));
6621           emacs_event->modifiers = EV_MODIFIERS (theEvent);
6622           EV_TRAILER (theEvent);
6623         }
6624       return YES;
6625     }
6626   else if ([type isEqualToString: NSURLPboardType])
6627     {
6628       NSString *file;
6629       NSURL *fileURL;
6631       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6632           [fileURL isFileURL] == NO)
6633         return NO;
6635       file = [fileURL path];
6636       emacs_event->kind = NS_NONKEY_EVENT;
6637       emacs_event->code = KEY_NS_DRAG_FILE;
6638       XSETINT (emacs_event->x, x);
6639       XSETINT (emacs_event->y, y);
6640       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6641       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6642       EV_TRAILER (theEvent);
6643       return YES;
6644     }
6645   else if ([type isEqualToString: NSStringPboardType]
6646            || [type isEqualToString: NSTabularTextPboardType])
6647     {
6648       NSString *data;
6650       if (! (data = [pb stringForType: type]))
6651         return NO;
6653       emacs_event->kind = NS_NONKEY_EVENT;
6654       emacs_event->code = KEY_NS_DRAG_TEXT;
6655       XSETINT (emacs_event->x, x);
6656       XSETINT (emacs_event->y, y);
6657       ns_input_text = build_string ([data UTF8String]);
6658       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6659       EV_TRAILER (theEvent);
6660       return YES;
6661     }
6662   else if ([type isEqualToString: NSColorPboardType])
6663     {
6664       NSColor *c = [NSColor colorFromPasteboard: pb];
6665       emacs_event->kind = NS_NONKEY_EVENT;
6666       emacs_event->code = KEY_NS_DRAG_COLOR;
6667       XSETINT (emacs_event->x, x);
6668       XSETINT (emacs_event->y, y);
6669       ns_input_color = ns_color_to_lisp (c);
6670       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6671       EV_TRAILER (theEvent);
6672       return YES;
6673     }
6674   else if ([type isEqualToString: NSFontPboardType])
6675     {
6676       /* impl based on GNUstep NSTextView.m */
6677       NSData *data = [pb dataForType: NSFontPboardType];
6678       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6679       NSFont *font = [dict objectForKey: NSFontAttributeName];
6680       char fontSize[10];
6682       if (font == nil)
6683         return NO;
6685       emacs_event->kind = NS_NONKEY_EVENT;
6686       emacs_event->code = KEY_NS_CHANGE_FONT;
6687       XSETINT (emacs_event->x, x);
6688       XSETINT (emacs_event->y, y);
6689       ns_input_font = build_string ([[font fontName] UTF8String]);
6690       snprintf (fontSize, 10, "%f", [font pointSize]);
6691       ns_input_fontsize = build_string (fontSize);
6692       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6693       EV_TRAILER (theEvent);
6694       return YES;
6695     }
6696   else
6697     {
6698       error ("Invalid data type in dragging pasteboard.");
6699       return NO;
6700     }
6704 - (id) validRequestorForSendType: (NSString *)typeSent
6705                       returnType: (NSString *)typeReturned
6707   NSTRACE (validRequestorForSendType);
6708   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6709       && typeReturned == nil)
6710     {
6711       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6712         return self;
6713     }
6715   return [super validRequestorForSendType: typeSent
6716                                returnType: typeReturned];
6720 /* The next two methods are part of NSServicesRequests informal protocol,
6721    supposedly called when a services menu item is chosen from this app.
6722    But this should not happen because we override the services menu with our
6723    own entries which call ns-perform-service.
6724    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6725    So let's at least stub them out until further investigation can be done. */
6727 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6729   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6730      be written into the buffer in place of the existing selection..
6731      ordinary service calls go through functions defined in ns-win.el */
6732   return NO;
6735 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6737   NSArray *typesDeclared;
6738   Lisp_Object val;
6740   /* We only support NSStringPboardType */
6741   if ([types containsObject:NSStringPboardType] == NO) {
6742     return NO;
6743   }
6745   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6746   if (CONSP (val) && SYMBOLP (XCAR (val)))
6747     {
6748       val = XCDR (val);
6749       if (CONSP (val) && NILP (XCDR (val)))
6750         val = XCAR (val);
6751     }
6752   if (! STRINGP (val))
6753     return NO;
6755   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6756   [pb declareTypes:typesDeclared owner:nil];
6757   ns_string_to_pasteboard (pb, val);
6758   return YES;
6762 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6763    (gives a miniaturized version of the window); currently we use the latter for
6764    frames whose active buffer doesn't correspond to any file
6765    (e.g., '*scratch*') */
6766 - setMiniwindowImage: (BOOL) setMini
6768   id image = [[self window] miniwindowImage];
6769   NSTRACE (setMiniwindowImage);
6771   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6772      about "AppleDockIconEnabled" notwithstanding, however the set message
6773      below has its effect nonetheless. */
6774   if (image != emacsframe->output_data.ns->miniimage)
6775     {
6776       if (image && [image isKindOfClass: [EmacsImage class]])
6777         [image release];
6778       [[self window] setMiniwindowImage:
6779                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6780     }
6782   return self;
6786 - (void) setRows: (int) r andColumns: (int) c
6788   rows = r;
6789   cols = c;
6792 @end  /* EmacsView */
6796 /* ==========================================================================
6798     EmacsWindow implementation
6800    ========================================================================== */
6802 @implementation EmacsWindow
6804 #ifdef NS_IMPL_COCOA
6805 - (id)accessibilityAttributeValue:(NSString *)attribute
6807   Lisp_Object str = Qnil;
6808   struct frame *f = SELECTED_FRAME ();
6809   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
6811   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6812     return NSAccessibilityTextFieldRole;
6814   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6815       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6816     {
6817       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6818     }
6819   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6820     {
6821       if (! NILP (BVAR (curbuf, mark_active)))
6822           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6824       if (NILP (str))
6825         {
6826           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6827           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6828           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6830           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6831             str = make_uninit_multibyte_string (range, byte_range);
6832           else
6833             str = make_uninit_string (range);
6834           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6835              Is this a problem?  */
6836           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6837         }
6838     }
6841   if (! NILP (str))
6842     {
6843       if (CONSP (str) && SYMBOLP (XCAR (str)))
6844         {
6845           str = XCDR (str);
6846           if (CONSP (str) && NILP (XCDR (str)))
6847             str = XCAR (str);
6848         }
6849       if (STRINGP (str))
6850         {
6851           const char *utfStr = SSDATA (str);
6852           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6853           return nsStr;
6854         }
6855     }
6857   return [super accessibilityAttributeValue:attribute];
6859 #endif /* NS_IMPL_COCOA */
6861 /* If we have multiple monitors, one above the other, we don't want to
6862    restrict the height to just one monitor.  So we override this.  */
6863 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6865   /* When making the frame visible for the first time or if there is just
6866      one screen, we want to constrain.  Other times not.  */
6867   NSUInteger nr_screens = [[NSScreen screens] count];
6868   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6869   NSTRACE (constrainFrameRect);
6871   if (nr_screens == 1)
6872     {
6873       NSRect r = [super constrainFrameRect:frameRect toScreen:screen];
6874       return r;
6875     }
6877   if (f->output_data.ns->dont_constrain
6878       || ns_menu_bar_should_be_hidden ())
6879     return frameRect;
6881   f->output_data.ns->dont_constrain = 1;
6882   return [super constrainFrameRect:frameRect toScreen:screen];
6885 @end /* EmacsWindow */
6888 @implementation EmacsFSWindow
6890 - (BOOL)canBecomeKeyWindow
6892   return YES;
6895 - (BOOL)canBecomeMainWindow
6897   return YES;
6900 @end
6902 /* ==========================================================================
6904     EmacsScroller implementation
6906    ========================================================================== */
6909 @implementation EmacsScroller
6911 /* for repeat button push */
6912 #define SCROLL_BAR_FIRST_DELAY 0.5
6913 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6915 + (CGFloat) scrollerWidth
6917   /* TODO: if we want to allow variable widths, this is the place to do it,
6918            however neither GNUstep nor Cocoa support it very well */
6919   return [NSScroller scrollerWidth];
6923 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6925   NSTRACE (EmacsScroller_initFrame);
6927   r.size.width = [EmacsScroller scrollerWidth];
6928   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6929   [self setContinuous: YES];
6930   [self setEnabled: YES];
6932   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6933      locked against the top and bottom edges, and right edge on OS X, where
6934      scrollers are on right. */
6935 #ifdef NS_IMPL_GNUSTEP
6936   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6937 #else
6938   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6939 #endif
6941   win = nwin;
6942   condemned = NO;
6943   pixel_height = NSHeight (r);
6944   if (pixel_height == 0) pixel_height = 1;
6945   min_portion = 20 / pixel_height;
6947   frame = XFRAME (XWINDOW (win)->frame);
6948   if (FRAME_LIVE_P (frame))
6949     {
6950       int i;
6951       EmacsView *view = FRAME_NS_VIEW (frame);
6952       NSView *sview = [[view window] contentView];
6953       NSArray *subs = [sview subviews];
6955       /* disable optimization stopping redraw of other scrollbars */
6956       view->scrollbarsNeedingUpdate = 0;
6957       for (i =[subs count]-1; i >= 0; i--)
6958         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6959           view->scrollbarsNeedingUpdate++;
6960       [sview addSubview: self];
6961     }
6963 /*  [self setFrame: r]; */
6965   return self;
6969 - (void)setFrame: (NSRect)newRect
6971   NSTRACE (EmacsScroller_setFrame);
6972 /*  block_input (); */
6973   pixel_height = NSHeight (newRect);
6974   if (pixel_height == 0) pixel_height = 1;
6975   min_portion = 20 / pixel_height;
6976   [super setFrame: newRect];
6977   [self display];
6978 /*  unblock_input (); */
6982 - (void)dealloc
6984   NSTRACE (EmacsScroller_dealloc);
6985   if (!NILP (win))
6986     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
6987   [super dealloc];
6991 - condemn
6993   NSTRACE (condemn);
6994   condemned =YES;
6995   return self;
6999 - reprieve
7001   NSTRACE (reprieve);
7002   condemned =NO;
7003   return self;
7007 - judge
7009   NSTRACE (judge);
7010   if (condemned)
7011     {
7012       EmacsView *view;
7013       block_input ();
7014       /* ensure other scrollbar updates after deletion */
7015       view = (EmacsView *)FRAME_NS_VIEW (frame);
7016       if (view != nil)
7017         view->scrollbarsNeedingUpdate++;
7018       [self removeFromSuperview];
7019       [self release];
7020       unblock_input ();
7021     }
7022   return self;
7026 - (void)resetCursorRects
7028   NSRect visible = [self visibleRect];
7029   NSTRACE (resetCursorRects);
7031   if (!NSIsEmptyRect (visible))
7032     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
7033   [[NSCursor arrowCursor] setOnMouseEntered: YES];
7037 - (int) checkSamePosition: (int) position portion: (int) portion
7038                     whole: (int) whole
7040   return em_position ==position && em_portion ==portion && em_whole ==whole
7041     && portion != whole; /* needed for resize empty buf */
7045 - setPosition: (int)position portion: (int)portion whole: (int)whole
7047   NSTRACE (setPosition);
7049   em_position = position;
7050   em_portion = portion;
7051   em_whole = whole;
7053   if (portion >= whole)
7054     {
7055 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
7056       [self setKnobProportion: 1.0];
7057       [self setDoubleValue: 1.0];
7058 #else
7059       [self setFloatValue: 0.0 knobProportion: 1.0];
7060 #endif
7061     }
7062   else
7063     {
7064       float pos;
7065       CGFloat por;
7066       portion = max ((float)whole*min_portion/pixel_height, portion);
7067       pos = (float)position / (whole - portion);
7068       por = (CGFloat)portion/whole;
7069 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
7070       [self setKnobProportion: por];
7071       [self setDoubleValue: pos];
7072 #else
7073       [self setFloatValue: pos knobProportion: por];
7074 #endif
7075     }
7077   /* Events may come here even if the event loop is not running.
7078      If we don't enter the event loop, the scroll bar will not update.
7079      So send SIGIO to ourselves.  */
7080   if (apploopnr == 0) raise (SIGIO);
7082   return self;
7085 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
7086      drag events will go directly to the EmacsScroller.  Leaving in for now. */
7087 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
7088                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
7090   *part = last_hit_part;
7091   *window = win;
7092   XSETINT (*y, pixel_height);
7093   if ([self floatValue] > 0.999F)
7094     XSETINT (*x, pixel_height);
7095   else
7096     XSETINT (*x, pixel_height * [self floatValue]);
7100 /* set up emacs_event */
7101 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
7103   if (!emacs_event)
7104     return;
7106   emacs_event->part = last_hit_part;
7107   emacs_event->code = 0;
7108   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
7109   emacs_event->frame_or_window = win;
7110   emacs_event->timestamp = EV_TIMESTAMP (e);
7111   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
7112   emacs_event->arg = Qnil;
7113   XSETINT (emacs_event->x, loc * pixel_height);
7114   XSETINT (emacs_event->y, pixel_height-20);
7116   if (q_event_ptr)
7117     {
7118       n_emacs_events_pending++;
7119       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7120     }
7121   else
7122     hold_event (emacs_event);
7123   EVENT_INIT (*emacs_event);
7124   ns_send_appdefined (-1);
7128 /* called manually thru timer to implement repeated button action w/hold-down */
7129 - repeatScroll: (NSTimer *)scrollEntry
7131   NSEvent *e = [[self window] currentEvent];
7132   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
7133   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7135   /* clear timer if need be */
7136   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7137     {
7138         [scroll_repeat_entry invalidate];
7139         [scroll_repeat_entry release];
7140         scroll_repeat_entry = nil;
7142         if (inKnob)
7143           return self;
7145         scroll_repeat_entry
7146           = [[NSTimer scheduledTimerWithTimeInterval:
7147                         SCROLL_BAR_CONTINUOUS_DELAY
7148                                             target: self
7149                                           selector: @selector (repeatScroll:)
7150                                           userInfo: 0
7151                                            repeats: YES]
7152               retain];
7153     }
7155   [self sendScrollEventAtLoc: 0 fromEvent: e];
7156   return self;
7160 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
7161    mouseDragged events without going into a modal loop. */
7162 - (void)mouseDown: (NSEvent *)e
7164   NSRect sr, kr;
7165   /* hitPart is only updated AFTER event is passed on */
7166   NSScrollerPart part = [self testPart: [e locationInWindow]];
7167   CGFloat inc = 0.0, loc, kloc, pos;
7168   int edge = 0;
7170   NSTRACE (EmacsScroller_mouseDown);
7172   switch (part)
7173     {
7174     case NSScrollerDecrementPage:
7175         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7176     case NSScrollerIncrementPage:
7177         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7178     case NSScrollerDecrementLine:
7179       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7180     case NSScrollerIncrementLine:
7181       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7182     case NSScrollerKnob:
7183       last_hit_part = scroll_bar_handle; break;
7184     case NSScrollerKnobSlot:  /* GNUstep-only */
7185       last_hit_part = scroll_bar_move_ratio; break;
7186     default:  /* NSScrollerNoPart? */
7187       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7188                (long) part);
7189       return;
7190     }
7192   if (inc != 0.0)
7193     {
7194       pos = 0;      /* ignored */
7196       /* set a timer to repeat, as we can't let superclass do this modally */
7197       scroll_repeat_entry
7198         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7199                                             target: self
7200                                           selector: @selector (repeatScroll:)
7201                                           userInfo: 0
7202                                            repeats: YES]
7203             retain];
7204     }
7205   else
7206     {
7207       /* handle, or on GNUstep possibly slot */
7208       NSEvent *fake_event;
7210       /* compute float loc in slot and mouse offset on knob */
7211       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7212                       toView: nil];
7213       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7214       if (loc <= 0.0)
7215         {
7216           loc = 0.0;
7217           edge = -1;
7218         }
7219       else if (loc >= NSHeight (sr))
7220         {
7221           loc = NSHeight (sr);
7222           edge = 1;
7223         }
7225       if (edge)
7226         kloc = 0.5 * edge;
7227       else
7228         {
7229           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7230                           toView: nil];
7231           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7232         }
7233       last_mouse_offset = kloc;
7235       /* if knob, tell emacs a location offset by knob pos
7236          (to indicate top of handle) */
7237       if (part == NSScrollerKnob)
7238           pos = (loc - last_mouse_offset) / NSHeight (sr);
7239       else
7240         /* else this is a slot click on GNUstep: go straight there */
7241         pos = loc / NSHeight (sr);
7243       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7244       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7245                                       location: [e locationInWindow]
7246                                  modifierFlags: [e modifierFlags]
7247                                      timestamp: [e timestamp]
7248                                   windowNumber: [e windowNumber]
7249                                        context: [e context]
7250                                    eventNumber: [e eventNumber]
7251                                     clickCount: [e clickCount]
7252                                       pressure: [e pressure]];
7253       [super mouseUp: fake_event];
7254     }
7256   if (part != NSScrollerKnob)
7257     [self sendScrollEventAtLoc: pos fromEvent: e];
7261 /* Called as we manually track scroller drags, rather than superclass. */
7262 - (void)mouseDragged: (NSEvent *)e
7264     NSRect sr;
7265     double loc, pos;
7267     NSTRACE (EmacsScroller_mouseDragged);
7269       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7270                       toView: nil];
7271       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7273       if (loc <= 0.0)
7274         {
7275           loc = 0.0;
7276         }
7277       else if (loc >= NSHeight (sr) + last_mouse_offset)
7278         {
7279           loc = NSHeight (sr) + last_mouse_offset;
7280         }
7282       pos = (loc - last_mouse_offset) / NSHeight (sr);
7283       [self sendScrollEventAtLoc: pos fromEvent: e];
7287 - (void)mouseUp: (NSEvent *)e
7289   if (scroll_repeat_entry)
7290     {
7291       [scroll_repeat_entry invalidate];
7292       [scroll_repeat_entry release];
7293       scroll_repeat_entry = nil;
7294     }
7295   last_hit_part = 0;
7299 /* treat scrollwheel events in the bar as though they were in the main window */
7300 - (void) scrollWheel: (NSEvent *)theEvent
7302   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7303   [view mouseDown: theEvent];
7306 @end  /* EmacsScroller */
7309 #ifdef NS_IMPL_GNUSTEP
7310 /* Dummy class to get rid of startup warnings.  */
7311 @implementation EmacsDocument
7313 @end
7314 #endif
7317 /* ==========================================================================
7319    Font-related functions; these used to be in nsfaces.m
7321    ========================================================================== */
7324 Lisp_Object
7325 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7327   struct font *font = XFONT_OBJECT (font_object);
7329   if (fontset < 0)
7330     fontset = fontset_from_font (font_object);
7331   FRAME_FONTSET (f) = fontset;
7333   if (FRAME_FONT (f) == font)
7334     /* This font is already set in frame F.  There's nothing more to
7335        do.  */
7336     return font_object;
7338   FRAME_FONT (f) = font;
7340   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7341   FRAME_COLUMN_WIDTH (f) = font->average_width;
7342   FRAME_LINE_HEIGHT (f) = font->height;
7344   compute_fringe_widths (f, 1);
7346   /* Compute the scroll bar width in character columns.  */
7347   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7348     {
7349       int wid = FRAME_COLUMN_WIDTH (f);
7350       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7351         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7352     }
7353   else
7354     {
7355       int wid = FRAME_COLUMN_WIDTH (f);
7356       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7357     }
7359   /* Now make the frame display the given font.  */
7360   if (FRAME_NS_WINDOW (f) != 0)
7361     x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f), 0);
7363   return font_object;
7367 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7368 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7369          in 1.43. */
7371 const char *
7372 ns_xlfd_to_fontname (const char *xlfd)
7373 /* --------------------------------------------------------------------------
7374     Convert an X font name (XLFD) to an NS font name.
7375     Only family is used.
7376     The string returned is temporarily allocated.
7377    -------------------------------------------------------------------------- */
7379   char *name = xmalloc (180);
7380   int i, len;
7381   const char *ret;
7383   if (!strncmp (xlfd, "--", 2))
7384     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7385   else
7386     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7388   /* stopgap for malformed XLFD input */
7389   if (strlen (name) == 0)
7390     strcpy (name, "Monaco");
7392   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7393      also uppercase after '-' or ' ' */
7394   name[0] = c_toupper (name[0]);
7395   for (len =strlen (name), i =0; i<len; i++)
7396     {
7397       if (name[i] == '$')
7398         {
7399           name[i] = '-';
7400           if (i+1<len)
7401             name[i+1] = c_toupper (name[i+1]);
7402         }
7403       else if (name[i] == '_')
7404         {
7405           name[i] = ' ';
7406           if (i+1<len)
7407             name[i+1] = c_toupper (name[i+1]);
7408         }
7409     }
7410 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7411   ret = [[NSString stringWithUTF8String: name] UTF8String];
7412   xfree (name);
7413   return ret;
7417 void
7418 syms_of_nsterm (void)
7420   NSTRACE (syms_of_nsterm);
7422   ns_antialias_threshold = 10.0;
7424   /* from 23+ we need to tell emacs what modifiers there are.. */
7425   DEFSYM (Qmodifier_value, "modifier-value");
7426   DEFSYM (Qalt, "alt");
7427   DEFSYM (Qhyper, "hyper");
7428   DEFSYM (Qmeta, "meta");
7429   DEFSYM (Qsuper, "super");
7430   DEFSYM (Qcontrol, "control");
7431   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7433   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7434   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7435   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7436   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7437   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7439   DEFVAR_LISP ("ns-input-file", ns_input_file,
7440               "The file specified in the last NS event.");
7441   ns_input_file =Qnil;
7443   DEFVAR_LISP ("ns-input-text", ns_input_text,
7444               "The data received in the last NS text drag event.");
7445   ns_input_text =Qnil;
7447   DEFVAR_LISP ("ns-working-text", ns_working_text,
7448               "String for visualizing working composition sequence.");
7449   ns_working_text =Qnil;
7451   DEFVAR_LISP ("ns-input-font", ns_input_font,
7452               "The font specified in the last NS event.");
7453   ns_input_font =Qnil;
7455   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7456               "The fontsize specified in the last NS event.");
7457   ns_input_fontsize =Qnil;
7459   DEFVAR_LISP ("ns-input-line", ns_input_line,
7460                "The line specified in the last NS event.");
7461   ns_input_line =Qnil;
7463   DEFVAR_LISP ("ns-input-color", ns_input_color,
7464                "The color specified in the last NS event.");
7465   ns_input_color =Qnil;
7467   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7468                "The service name specified in the last NS event.");
7469   ns_input_spi_name =Qnil;
7471   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7472                "The service argument specified in the last NS event.");
7473   ns_input_spi_arg =Qnil;
7475   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7476                "This variable describes the behavior of the alternate or option key.\n\
7477 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7478 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7479 at all, allowing it to be used at a lower level for accented character entry.");
7480   ns_alternate_modifier = Qmeta;
7482   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7483                "This variable describes the behavior of the right alternate or option key.\n\
7484 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7485 Set to left means be the same key as `ns-alternate-modifier'.\n\
7486 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7487 at all, allowing it to be used at a lower level for accented character entry.");
7488   ns_right_alternate_modifier = Qleft;
7490   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7491                "This variable describes the behavior of the command key.\n\
7492 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7493   ns_command_modifier = Qsuper;
7495   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7496                "This variable describes the behavior of the right command key.\n\
7497 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7498 Set to left means be the same key as `ns-command-modifier'.\n\
7499 Set to none means that the command / option key is not interpreted by Emacs\n\
7500 at all, allowing it to be used at a lower level for accented character entry.");
7501   ns_right_command_modifier = Qleft;
7503   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7504                "This variable describes the behavior of the control key.\n\
7505 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7506   ns_control_modifier = Qcontrol;
7508   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7509                "This variable describes the behavior of the right control key.\n\
7510 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7511 Set to left means be the same key as `ns-control-modifier'.\n\
7512 Set to none means that the control / option key is not interpreted by Emacs\n\
7513 at all, allowing it to be used at a lower level for accented character entry.");
7514   ns_right_control_modifier = Qleft;
7516   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7517                "This variable describes the behavior of the function key (on laptops).\n\
7518 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7519 Set to none means that the function key is not interpreted by Emacs at all,\n\
7520 allowing it to be used at a lower level for accented character entry.");
7521   ns_function_modifier = Qnone;
7523   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7524                "Non-nil (the default) means to render text antialiased.");
7525   ns_antialias_text = Qt;
7527   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7528                "Whether to confirm application quit using dialog.");
7529   ns_confirm_quit = Qnil;
7531   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7532                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7533 Only works on OSX 10.6 or later.  */);
7534   ns_auto_hide_menu_bar = Qnil;
7536   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7537      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7538 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7539 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7540 Default is t for OSX >= 10.7, nil otherwise. */);
7541 #ifdef HAVE_NATIVE_FS
7542   ns_use_native_fullscreen = YES;
7543 #else
7544   ns_use_native_fullscreen = NO;
7545 #endif
7546   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7548   /* TODO: move to common code */
7549   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7550                doc: /* Which toolkit scroll bars Emacs uses, if any.
7551 A value of nil means Emacs doesn't use toolkit scroll bars.
7552 With the X Window system, the value is a symbol describing the
7553 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7554 With MS Windows or Nextstep, the value is t.  */);
7555   Vx_toolkit_scroll_bars = Qt;
7557   DEFVAR_BOOL ("x-use-underline-position-properties",
7558                x_use_underline_position_properties,
7559      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7560 A value of nil means ignore them.  If you encounter fonts with bogus
7561 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7562 to 4.1, set this to nil. */);
7563   x_use_underline_position_properties = 0;
7565   DEFVAR_BOOL ("x-underline-at-descent-line",
7566                x_underline_at_descent_line,
7567      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7568 A value of nil means to draw the underline according to the value of the
7569 variable `x-use-underline-position-properties', which is usually at the
7570 baseline level.  The default value is nil.  */);
7571   x_underline_at_descent_line = 0;
7573   /* Tell Emacs about this window system.  */
7574   Fprovide (Qns, Qnil);
7576   DEFSYM (Qcocoa, "cocoa");
7577   DEFSYM (Qgnustep, "gnustep");
7579   syms_of_nsfont ();
7580 #ifdef NS_IMPL_COCOA
7581   Fprovide (Qcocoa, Qnil);
7582 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
7583   syms_of_macfont ();
7584 #endif
7585 #else
7586   Fprovide (Qgnustep, Qnil);
7587 #endif