Amend to fontify /regexp/s in actions correctly.
[emacs.git] / src / nsterm.m
blob3544cfd79a0fae4117f4a800d0e29bacd025b697
1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2013 Free Software
4 Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30    interpretation of even the system includes. */
31 #include <config.h>
33 #include <fcntl.h>
34 #include <math.h>
35 #include <pthread.h>
36 #include <sys/types.h>
37 #include <time.h>
38 #include <signal.h>
39 #include <unistd.h>
41 #include <c-ctype.h>
42 #include <c-strcase.h>
43 #include <ftoastr.h>
45 #include "lisp.h"
46 #include "blockinput.h"
47 #include "sysselect.h"
48 #include "nsterm.h"
49 #include "systime.h"
50 #include "character.h"
51 #include "fontset.h"
52 #include "composite.h"
53 #include "ccl.h"
55 #include "termhooks.h"
56 #include "termchar.h"
58 #include "window.h"
59 #include "keyboard.h"
60 #include "buffer.h"
61 #include "font.h"
63 /* call tracing */
64 #if 0
65 int term_trace_num = 0;
66 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
67                                 __FILE__, __LINE__, ++term_trace_num)
68 #else
69 #define NSTRACE(x)
70 #endif
72 #if defined (NS_IMPL_COCOA) && \
73   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
74 #define NEW_STYLE_FS
75 #endif
77 extern NSString *NSMenuDidBeginTrackingNotification;
79 /* ==========================================================================
81     Local declarations
83    ========================================================================== */
85 /* Convert a symbol indexed with an NSxxx value to a value as defined
86    in keyboard.c (lispy_function_key). I hope this is a correct way
87    of doing things... */
88 static unsigned convert_ns_to_X_keysym[] =
90   NSHomeFunctionKey,            0x50,
91   NSLeftArrowFunctionKey,       0x51,
92   NSUpArrowFunctionKey,         0x52,
93   NSRightArrowFunctionKey,      0x53,
94   NSDownArrowFunctionKey,       0x54,
95   NSPageUpFunctionKey,          0x55,
96   NSPageDownFunctionKey,        0x56,
97   NSEndFunctionKey,             0x57,
98   NSBeginFunctionKey,           0x58,
99   NSSelectFunctionKey,          0x60,
100   NSPrintFunctionKey,           0x61,
101   NSClearLineFunctionKey,       0x0B,
102   NSExecuteFunctionKey,         0x62,
103   NSInsertFunctionKey,          0x63,
104   NSUndoFunctionKey,            0x65,
105   NSRedoFunctionKey,            0x66,
106   NSMenuFunctionKey,            0x67,
107   NSFindFunctionKey,            0x68,
108   NSHelpFunctionKey,            0x6A,
109   NSBreakFunctionKey,           0x6B,
111   NSF1FunctionKey,              0xBE,
112   NSF2FunctionKey,              0xBF,
113   NSF3FunctionKey,              0xC0,
114   NSF4FunctionKey,              0xC1,
115   NSF5FunctionKey,              0xC2,
116   NSF6FunctionKey,              0xC3,
117   NSF7FunctionKey,              0xC4,
118   NSF8FunctionKey,              0xC5,
119   NSF9FunctionKey,              0xC6,
120   NSF10FunctionKey,             0xC7,
121   NSF11FunctionKey,             0xC8,
122   NSF12FunctionKey,             0xC9,
123   NSF13FunctionKey,             0xCA,
124   NSF14FunctionKey,             0xCB,
125   NSF15FunctionKey,             0xCC,
126   NSF16FunctionKey,             0xCD,
127   NSF17FunctionKey,             0xCE,
128   NSF18FunctionKey,             0xCF,
129   NSF19FunctionKey,             0xD0,
130   NSF20FunctionKey,             0xD1,
131   NSF21FunctionKey,             0xD2,
132   NSF22FunctionKey,             0xD3,
133   NSF23FunctionKey,             0xD4,
134   NSF24FunctionKey,             0xD5,
136   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
137   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
138   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
140   NSTabCharacter,               0x09,
141   0x19,                         0x09,  /* left tab->regular since pass shift */
142   NSCarriageReturnCharacter,    0x0D,
143   NSNewlineCharacter,           0x0D,
144   NSEnterCharacter,             0x8D,
146   0x41|NSNumericPadKeyMask,     0xAE,  /* KP_Decimal */
147   0x43|NSNumericPadKeyMask,     0xAA,  /* KP_Multiply */
148   0x45|NSNumericPadKeyMask,     0xAB,  /* KP_Add */
149   0x4B|NSNumericPadKeyMask,     0xAF,  /* KP_Divide */
150   0x4E|NSNumericPadKeyMask,     0xAD,  /* KP_Subtract */
151   0x51|NSNumericPadKeyMask,     0xBD,  /* KP_Equal */
152   0x52|NSNumericPadKeyMask,     0xB0,  /* KP_0 */
153   0x53|NSNumericPadKeyMask,     0xB1,  /* KP_1 */
154   0x54|NSNumericPadKeyMask,     0xB2,  /* KP_2 */
155   0x55|NSNumericPadKeyMask,     0xB3,  /* KP_3 */
156   0x56|NSNumericPadKeyMask,     0xB4,  /* KP_4 */
157   0x57|NSNumericPadKeyMask,     0xB5,  /* KP_5 */
158   0x58|NSNumericPadKeyMask,     0xB6,  /* KP_6 */
159   0x59|NSNumericPadKeyMask,     0xB7,  /* KP_7 */
160   0x5B|NSNumericPadKeyMask,     0xB8,  /* KP_8 */
161   0x5C|NSNumericPadKeyMask,     0xB9,  /* KP_9 */
163   0x1B,                         0x1B   /* escape */
166 static Lisp_Object Qmodifier_value;
167 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
168 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
170 static Lisp_Object QUTF8_STRING;
172 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
173    the maximum font size to NOT antialias.  On GNUstep there is currently
174    no way to control this behavior. */
175 float ns_antialias_threshold;
177 /* Used to pick up AppleHighlightColor on OS X */
178 NSString *ns_selection_color;
180 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
181 NSString *ns_app_name = @"Emacs";  /* default changed later */
183 /* Display variables */
184 struct ns_display_info *x_display_list; /* Chain of existing displays */
185 Lisp_Object ns_display_name_list;
186 long context_menu_value = 0;
188 /* display update */
189 NSPoint last_mouse_motion_position;
190 static NSRect last_mouse_glyph;
191 static Time last_mouse_movement_time = 0;
192 static Lisp_Object last_mouse_motion_frame;
193 static EmacsScroller *last_mouse_scroll_bar = nil;
194 static struct frame *ns_updating_frame;
195 static NSView *focus_view = NULL;
196 static int ns_window_num = 0;
197 #ifdef NS_IMPL_GNUSTEP
198 static NSRect uRect;
199 #endif
200 static BOOL gsaved = NO;
201 static BOOL ns_fake_keydown = NO;
202 int ns_tmp_flags; /* FIXME */
203 struct nsfont_info *ns_tmp_font; /* FIXME */
204 static BOOL ns_menu_bar_is_hidden = NO;
205 /*static int debug_lock = 0; */
207 /* event loop */
208 static BOOL send_appdefined = YES;
209 #define NO_APPDEFINED_DATA (-8)
210 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
211 static NSTimer *timed_entry = 0;
212 static NSTimer *scroll_repeat_entry = nil;
213 static fd_set select_readfds, select_writefds;
214 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
215 static int select_nfds = 0, select_valid = 0;
216 static EMACS_TIME select_timeout = { 0, 0 };
217 static int selfds[2] = { -1, -1 };
218 static pthread_mutex_t select_mutex;
219 static int apploopnr = 0;
220 static NSAutoreleasePool *outerpool;
221 static struct input_event *emacs_event = NULL;
222 static struct input_event *q_event_ptr = NULL;
223 static int n_emacs_events_pending = 0;
224 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
225   *ns_pending_service_args;
226 static BOOL ns_do_open_file = NO;
228 static struct {
229   struct input_event *q;
230   int nr, cap;
231 } hold_event_q = {
232   NULL, 0, 0
235 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
236 #define NS_FUNCTION_KEY_MASK 0x800000
237 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
238 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
239 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
240 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
241 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
242 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
243 #define EV_MODIFIERS(e)                               \
244     ((([e modifierFlags] & NSHelpKeyMask) ?           \
245            hyper_modifier : 0)                        \
246      | (!EQ (ns_right_alternate_modifier, Qleft) && \
247         (([e modifierFlags] & NSRightAlternateKeyMask) \
248          == NSRightAlternateKeyMask) ? \
249            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
250      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
251            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
252      | (([e modifierFlags] & NSShiftKeyMask) ?     \
253            shift_modifier : 0)                        \
254      | (!EQ (ns_right_control_modifier, Qleft) && \
255         (([e modifierFlags] & NSRightControlKeyMask) \
256          == NSRightControlKeyMask) ? \
257            parse_solitary_modifier (ns_right_control_modifier) : 0) \
258      | (([e modifierFlags] & NSControlKeyMask) ?      \
259            parse_solitary_modifier (ns_control_modifier) : 0)     \
260      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
261            parse_solitary_modifier (ns_function_modifier) : 0)    \
262      | (!EQ (ns_right_command_modifier, Qleft) && \
263         (([e modifierFlags] & NSRightCommandKeyMask) \
264          == NSRightCommandKeyMask) ? \
265            parse_solitary_modifier (ns_right_command_modifier) : 0) \
266      | (([e modifierFlags] & NSCommandKeyMask) ?      \
267            parse_solitary_modifier (ns_command_modifier):0))
269 #define EV_UDMODIFIERS(e)                                      \
270     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
271      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
272      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
273      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
274      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
275      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
276      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
277      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
278      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
280 #define EV_BUTTON(e)                                                         \
281     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
282       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
283      [e buttonNumber] - 1)
285 /* Convert the time field to a timestamp in milliseconds. */
286 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
288 /* This is a piece of code which is common to all the event handling
289    methods.  Maybe it should even be a function.  */
290 #define EV_TRAILER(e)                                                   \
291     {                                                                   \
292       XSETFRAME (emacs_event->frame_or_window, emacsframe);             \
293       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
294       if (q_event_ptr)                                                  \
295         {                                                               \
296           n_emacs_events_pending++;                                     \
297           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
298         }                                                               \
299       else                                                              \
300         hold_event (emacs_event);                                       \
301       EVENT_INIT (*emacs_event);                                        \
302       ns_send_appdefined (-1);                                          \
303     }
305 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
307 /* TODO: get rid of need for these forward declarations */
308 static void ns_condemn_scroll_bars (struct frame *f);
309 static void ns_judge_scroll_bars (struct frame *f);
310 void x_set_frame_alpha (struct frame *f);
313 /* ==========================================================================
315     Utilities
317    ========================================================================== */
319 static void
320 hold_event (struct input_event *event)
322   if (hold_event_q.nr == hold_event_q.cap)
323     {
324       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
325       else hold_event_q.cap *= 2;
326       hold_event_q.q = (struct input_event *)
327         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof (*hold_event_q.q));
328     }
330   hold_event_q.q[hold_event_q.nr++] = *event;
331   /* Make sure ns_read_socket is called, i.e. we have input.  */
332   raise (SIGIO);
333   send_appdefined = YES;
336 static Lisp_Object
337 append2 (Lisp_Object list, Lisp_Object item)
338 /* --------------------------------------------------------------------------
339    Utility to append to a list
340    -------------------------------------------------------------------------- */
342   Lisp_Object array[2];
343   array[0] = list;
344   array[1] = Fcons (item, Qnil);
345   return Fnconc (2, &array[0]);
349 const char *
350 ns_etc_directory (void)
351 /* If running as a self-contained app bundle, return as a string the
352    filename of the etc directory, if present; else nil.  */
354   NSBundle *bundle = [NSBundle mainBundle];
355   NSString *resourceDir = [bundle resourcePath];
356   NSString *resourcePath;
357   NSFileManager *fileManager = [NSFileManager defaultManager];
358   BOOL isDir;
360   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
361   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
362     {
363       if (isDir) return [resourcePath UTF8String];
364     }
365   return NULL;
369 const char *
370 ns_exec_path (void)
371 /* If running as a self-contained app bundle, return as a path string
372    the filenames of the libexec and bin directories, ie libexec:bin.
373    Otherwise, return nil.
374    Normally, Emacs does not add its own bin/ directory to the PATH.
375    However, a self-contained NS build has a different layout, with
376    bin/ and libexec/ subdirectories in the directory that contains
377    Emacs.app itself.
378    We put libexec first, because init_callproc_1 uses the first
379    element to initialize exec-directory.  An alternative would be
380    for init_callproc to check for invocation-directory/libexec.
383   NSBundle *bundle = [NSBundle mainBundle];
384   NSString *resourceDir = [bundle resourcePath];
385   NSString *binDir = [bundle bundlePath];
386   NSString *resourcePath, *resourcePaths;
387   NSRange range;
388   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
389   NSFileManager *fileManager = [NSFileManager defaultManager];
390   NSArray *paths;
391   NSEnumerator *pathEnum;
392   BOOL isDir;
394   range = [resourceDir rangeOfString: @"Contents"];
395   if (range.location != NSNotFound)
396     {
397       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
398 #ifdef NS_IMPL_COCOA
399       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
400 #endif
401     }
403   paths = [binDir stringsByAppendingPaths:
404                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
405   pathEnum = [paths objectEnumerator];
406   resourcePaths = @"";
408   while ((resourcePath = [pathEnum nextObject]))
409     {
410       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
411         if (isDir)
412           {
413             if ([resourcePaths length] > 0)
414               resourcePaths
415                 = [resourcePaths stringByAppendingString: pathSeparator];
416             resourcePaths
417               = [resourcePaths stringByAppendingString: resourcePath];
418           }
419     }
420   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
422   return NULL;
426 const char *
427 ns_load_path (void)
428 /* If running as a self-contained app bundle, return as a path string
429    the filenames of the site-lisp, lisp and leim directories.
430    Ie, site-lisp:lisp:leim.  Otherwise, return nil.  */
432   NSBundle *bundle = [NSBundle mainBundle];
433   NSString *resourceDir = [bundle resourcePath];
434   NSString *resourcePath, *resourcePaths;
435   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
436   NSFileManager *fileManager = [NSFileManager defaultManager];
437   BOOL isDir;
438   NSArray *paths = [resourceDir stringsByAppendingPaths:
439                               [NSArray arrayWithObjects:
440                                          @"site-lisp", @"lisp", @"leim", nil]];
441   NSEnumerator *pathEnum = [paths objectEnumerator];
442   resourcePaths = @"";
444   /* Hack to skip site-lisp.  */
445   if (no_site_lisp) resourcePath = [pathEnum nextObject];
447   while ((resourcePath = [pathEnum nextObject]))
448     {
449       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
450         if (isDir)
451           {
452             if ([resourcePaths length] > 0)
453               resourcePaths
454                 = [resourcePaths stringByAppendingString: pathSeparator];
455             resourcePaths
456               = [resourcePaths stringByAppendingString: resourcePath];
457           }
458     }
459   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
461   return NULL;
464 static void
465 ns_timeout (int usecs)
466 /* --------------------------------------------------------------------------
467      Blocking timer utility used by ns_ring_bell
468    -------------------------------------------------------------------------- */
470   EMACS_TIME wakeup = add_emacs_time (current_emacs_time (),
471                                       make_emacs_time (0, usecs * 1000));
473   /* Keep waiting until past the time wakeup.  */
474   while (1)
475     {
476       EMACS_TIME timeout, now = current_emacs_time ();
477       if (EMACS_TIME_LE (wakeup, now))
478         break;
479       timeout = sub_emacs_time (wakeup, now);
481       /* Try to wait that long--but we might wake up sooner.  */
482       pselect (0, NULL, NULL, NULL, &timeout, NULL);
483     }
487 void
488 ns_release_object (void *obj)
489 /* --------------------------------------------------------------------------
490     Release an object (callable from C)
491    -------------------------------------------------------------------------- */
493     [(id)obj release];
497 void
498 ns_retain_object (void *obj)
499 /* --------------------------------------------------------------------------
500     Retain an object (callable from C)
501    -------------------------------------------------------------------------- */
503     [(id)obj retain];
507 void *
508 ns_alloc_autorelease_pool (void)
509 /* --------------------------------------------------------------------------
510      Allocate a pool for temporary objects (callable from C)
511    -------------------------------------------------------------------------- */
513   return [[NSAutoreleasePool alloc] init];
517 void
518 ns_release_autorelease_pool (void *pool)
519 /* --------------------------------------------------------------------------
520      Free a pool and temporary objects it refers to (callable from C)
521    -------------------------------------------------------------------------- */
523   ns_release_object (pool);
528 /* ==========================================================================
530     Focus (clipping) and screen update
532    ========================================================================== */
535 // Window constraining
536 // -------------------
538 // To ensure that the windows are not placed under the menu bar, they
539 // are typically moved by the call-back constrainFrameRect. However,
540 // by overriding it, it's possible to inhibit this, leaving the window
541 // in it's original position.
543 // It's possible to hide the menu bar. However, technically, it's only
544 // possible to hide it when the application is active. To ensure that
545 // this work properly, the menu bar and window constraining are
546 // deferred until the application becomes active.
548 // Even though it's not possible to manually move a window above the
549 // top of the screen, it is allowed if it's done programmatically,
550 // when the menu is hidden. This allows the editable area to cover the
551 // full screen height.
553 // Test cases
554 // ----------
556 // Use the following extra files:
558 //    init.el:
559 //       ;; Hide menu and place frame slightly above the top of the screen.
560 //       (setq ns-auto-hide-menu-bar t)
561 //       (set-frame-position (selected-frame) 0 -20)
563 // Test 1:
565 //    emacs -Q -l init.el
567 //    Result: No menu bar, and the title bar should be above the screen.
569 // Test 2:
571 //    emacs -Q
573 //    Result: Menu bar visible, frame placed immediately below the menu.
576 static void
577 ns_constrain_all_frames (void)
579   Lisp_Object tail, frame;
581   FOR_EACH_FRAME (tail, frame)
582     {
583       struct frame *f = XFRAME (frame);
584       if (FRAME_NS_P (f))
585         {
586           NSView *view = FRAME_NS_VIEW (f);
587           /* This no-op will trigger the default window placing
588            * constraint system. */
589           f->output_data.ns->dont_constrain = 0;
590           [[view window] setFrameOrigin:[[view window] frame].origin];
591         }
592     }
596 /* True, if the menu bar should be hidden.  */
598 static BOOL
599 ns_menu_bar_should_be_hidden (void)
601   return !NILP (ns_auto_hide_menu_bar)
602     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
606 /* Show or hide the menu bar, based on user setting.  */
608 static void
609 ns_update_auto_hide_menu_bar (void)
611 #ifdef NS_IMPL_COCOA
612 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
613   block_input ();
615   NSTRACE (ns_update_auto_hide_menu_bar);
617   if (NSApp != nil
618       && [NSApp isActive]
619       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
620     {
621       // Note, "setPresentationOptions" triggers an error unless the
622       // application is active.
623       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
625       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
626         {
627           NSApplicationPresentationOptions options
628             = NSApplicationPresentationAutoHideDock;
630           if (menu_bar_should_be_hidden)
631             options |= NSApplicationPresentationAutoHideMenuBar;
633           [NSApp setPresentationOptions: options];
635           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
637           if (!ns_menu_bar_is_hidden)
638             {
639               ns_constrain_all_frames ();
640             }
641         }
642     }
644   unblock_input ();
645 #endif
646 #endif
650 static void
651 ns_update_begin (struct frame *f)
652 /* --------------------------------------------------------------------------
653    Prepare for a grouped sequence of drawing calls
654    external (RIF) call; whole frame, called before update_window_begin
655    -------------------------------------------------------------------------- */
657   NSView *view = FRAME_NS_VIEW (f);
658   NSRect r = [view frame];
659   NSBezierPath *bp;
660   NSTRACE (ns_update_begin);
662   ns_update_auto_hide_menu_bar ();
664   ns_updating_frame = f;
665   [view lockFocus];
667   /* drawRect may have been called for say the minibuffer, and then clip path
668      is for the minibuffer.  But the display engine may draw more because
669      we have set the frame as garbaged.  So reset clip path to the whole
670      view.  */
671   bp = [[NSBezierPath bezierPathWithRect: r] retain];
672   [bp setClip];
673   [bp release];
675 #ifdef NS_IMPL_GNUSTEP
676   uRect = NSMakeRect (0, 0, 0, 0);
677 #endif
681 static void
682 ns_update_window_begin (struct window *w)
683 /* --------------------------------------------------------------------------
684    Prepare for a grouped sequence of drawing calls
685    external (RIF) call; for one window, called after update_begin
686    -------------------------------------------------------------------------- */
688   struct frame *f = XFRAME (WINDOW_FRAME (w));
689  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
690   NSTRACE (ns_update_window_begin);
691   updated_window = w;
692   set_output_cursor (&w->cursor);
694   block_input ();
696   if (f == hlinfo->mouse_face_mouse_frame)
697     {
698       /* Don't do highlighting for mouse motion during the update.  */
699       hlinfo->mouse_face_defer = 1;
701         /* If the frame needs to be redrawn,
702            simply forget about any prior mouse highlighting.  */
703       if (FRAME_GARBAGED_P (f))
704         hlinfo->mouse_face_window = Qnil;
706       /* (further code for mouse faces ifdef'd out in other terms elided) */
707     }
709   unblock_input ();
713 static void
714 ns_update_window_end (struct window *w, int cursor_on_p,
715                       int mouse_face_overwritten_p)
716 /* --------------------------------------------------------------------------
717    Finished a grouped sequence of drawing calls
718    external (RIF) call; for one window called before update_end
719    -------------------------------------------------------------------------- */
721   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
723   /* note: this fn is nearly identical in all terms */
724   if (!w->pseudo_window_p)
725     {
726       block_input ();
728       if (cursor_on_p)
729         display_and_set_cursor (w, 1,
730                                 output_cursor.hpos, output_cursor.vpos,
731                                 output_cursor.x, output_cursor.y);
733       if (draw_window_fringes (w, 1))
734         x_draw_vertical_border (w);
736       unblock_input ();
737     }
739   /* If a row with mouse-face was overwritten, arrange for
740      frame_up_to_date to redisplay the mouse highlight.  */
741   if (mouse_face_overwritten_p)
742     {
743       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
744       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
745       hlinfo->mouse_face_window = Qnil;
746     }
748   updated_window = NULL;
749   NSTRACE (update_window_end);
753 static void
754 ns_update_end (struct frame *f)
755 /* --------------------------------------------------------------------------
756    Finished a grouped sequence of drawing calls
757    external (RIF) call; for whole frame, called after update_window_end
758    -------------------------------------------------------------------------- */
760   NSView *view = FRAME_NS_VIEW (f);
762 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
763     MOUSE_HL_INFO (f)->mouse_face_defer = 0;
765     block_input ();
767 #ifdef NS_IMPL_GNUSTEP
768   /* trigger flush only in the rectangle we tracked as being drawn */
769   [view unlockFocusNeedsFlush: NO];
770 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
771   [view lockFocusInRect: uRect];
772 #endif
774   [view unlockFocus];
775   [[view window] flushWindow];
777   unblock_input ();
778   ns_updating_frame = NULL;
779   NSTRACE (ns_update_end);
783 static void
784 ns_flush (struct frame *f)
785 /* --------------------------------------------------------------------------
786    external (RIF) call
787    NS impl is no-op since currently we flush in ns_update_end and elsewhere
788    -------------------------------------------------------------------------- */
790     NSTRACE (ns_flush);
794 static void
795 ns_focus (struct frame *f, NSRect *r, int n)
796 /* --------------------------------------------------------------------------
797    Internal: Focus on given frame.  During small local updates this is used to
798      draw, however during large updates, ns_update_begin and ns_update_end are
799      called to wrap the whole thing, in which case these calls are stubbed out.
800      Except, on GNUstep, we accumulate the rectangle being drawn into, because
801      the back end won't do this automatically, and will just end up flushing
802      the entire window.
803    -------------------------------------------------------------------------- */
805 //  NSTRACE (ns_focus);
806 #ifdef NS_IMPL_GNUSTEP
807   NSRect u;
808     if (n == 2)
809       u = NSUnionRect (r[0], r[1]);
810     else if (r)
811       u = *r;
812 #endif
813 /* static int c =0;
814    fprintf (stderr, "focus: %d", c++);
815    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
816    fprintf (stderr, "\n"); */
818   if (f != ns_updating_frame)
819     {
820       NSView *view = FRAME_NS_VIEW (f);
821       if (view != focus_view)
822         {
823           if (focus_view != NULL)
824             {
825               [focus_view unlockFocus];
826               [[focus_view window] flushWindow];
827 /*debug_lock--; */
828             }
830           if (view)
831 #ifdef NS_IMPL_GNUSTEP
832             r ? [view lockFocusInRect: u] : [view lockFocus];
833 #else
834             [view lockFocus];
835 #endif
836           focus_view = view;
837 /*if (view) debug_lock++; */
838         }
839 #ifdef NS_IMPL_GNUSTEP
840       else
841         {
842           /* more than one rect being drawn into */
843           if (view && r)
844             {
845               [view unlockFocus]; /* add prev rect to redraw list */
846               [view lockFocusInRect: u]; /* focus for draw in new rect */
847             }
848         }
849 #endif
850     }
851 #ifdef NS_IMPL_GNUSTEP
852   else
853     {
854       /* in batch mode, but in GNUstep must still track rectangles explicitly */
855       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
856     }
857 #endif
859   /* clipping */
860   if (r)
861     {
862       [[NSGraphicsContext currentContext] saveGraphicsState];
863       if (n == 2)
864         NSRectClipList (r, 2);
865       else
866         NSRectClip (*r);
867       gsaved = YES;
868     }
872 static void
873 ns_unfocus (struct frame *f)
874 /* --------------------------------------------------------------------------
875      Internal: Remove focus on given frame
876    -------------------------------------------------------------------------- */
878 //  NSTRACE (ns_unfocus);
880   if (gsaved)
881     {
882       [[NSGraphicsContext currentContext] restoreGraphicsState];
883       gsaved = NO;
884     }
886   if (f != ns_updating_frame)
887     {
888       if (focus_view != NULL)
889         {
890           [focus_view unlockFocus];
891           [[focus_view window] flushWindow];
892           focus_view = NULL;
893 /*debug_lock--; */
894         }
895     }
899 static void
900 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
901 /* --------------------------------------------------------------------------
902      Internal (but parallels other terms): Focus drawing on given row
903    -------------------------------------------------------------------------- */
905   struct frame *f = XFRAME (WINDOW_FRAME (w));
906   NSRect clip_rect;
907   int window_x, window_y, window_width;
909   window_box (w, area, &window_x, &window_y, &window_width, 0);
911   clip_rect.origin.x = window_x;
912   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
913   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
914   clip_rect.size.width = window_width;
915   clip_rect.size.height = row->visible_height;
917   ns_focus (f, &clip_rect, 1);
921 static void
922 ns_ring_bell (struct frame *f)
923 /* --------------------------------------------------------------------------
924      "Beep" routine
925    -------------------------------------------------------------------------- */
927   NSTRACE (ns_ring_bell);
928   if (visible_bell)
929     {
930       NSAutoreleasePool *pool;
931       struct frame *frame = SELECTED_FRAME ();
932       NSView *view;
934       block_input ();
935       pool = [[NSAutoreleasePool alloc] init];
937       view = FRAME_NS_VIEW (frame);
938       if (view != nil)
939         {
940           NSRect r, surr;
941           NSPoint dim = NSMakePoint (128, 128);
943           r = [view bounds];
944           r.origin.x += (r.size.width - dim.x) / 2;
945           r.origin.y += (r.size.height - dim.y) / 2;
946           r.size.width = dim.x;
947           r.size.height = dim.y;
948           surr = NSInsetRect (r, -2, -2);
949           ns_focus (frame, &surr, 1);
950           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
951           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
952                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
953           NSRectFill (r);
954           [[view window] flushWindow];
955           ns_timeout (150000);
956           [[view window] restoreCachedImage];
957           [[view window] flushWindow];
958           ns_unfocus (frame);
959         }
960       [pool release];
961       unblock_input ();
962     }
963   else
964     {
965       NSBeep ();
966     }
970 static void
971 ns_reset_terminal_modes (struct terminal *terminal)
972 /*  Externally called as hook */
974   NSTRACE (ns_reset_terminal_modes);
978 static void
979 ns_set_terminal_modes (struct terminal *terminal)
980 /*  Externally called as hook */
982   NSTRACE (ns_set_terminal_modes);
987 /* ==========================================================================
989     Frame / window manager related functions
991    ========================================================================== */
994 static void
995 ns_raise_frame (struct frame *f)
996 /* --------------------------------------------------------------------------
997      Bring window to foreground and make it active
998    -------------------------------------------------------------------------- */
1000   NSView *view = FRAME_NS_VIEW (f);
1001   check_ns ();
1002   block_input ();
1003   if (FRAME_VISIBLE_P (f))
1004     [[view window] makeKeyAndOrderFront: NSApp];
1005   unblock_input ();
1009 static void
1010 ns_lower_frame (struct frame *f)
1011 /* --------------------------------------------------------------------------
1012      Send window to back
1013    -------------------------------------------------------------------------- */
1015   NSView *view = FRAME_NS_VIEW (f);
1016   check_ns ();
1017   block_input ();
1018   [[view window] orderBack: NSApp];
1019   unblock_input ();
1023 static void
1024 ns_frame_raise_lower (struct frame *f, int raise)
1025 /* --------------------------------------------------------------------------
1026      External (hook)
1027    -------------------------------------------------------------------------- */
1029   NSTRACE (ns_frame_raise_lower);
1031   if (raise)
1032     ns_raise_frame (f);
1033   else
1034     ns_lower_frame (f);
1038 static void
1039 ns_frame_rehighlight (struct frame *frame)
1040 /* --------------------------------------------------------------------------
1041      External (hook): called on things like window switching within frame
1042    -------------------------------------------------------------------------- */
1044   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1045   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1047   NSTRACE (ns_frame_rehighlight);
1048   if (dpyinfo->x_focus_frame)
1049     {
1050       dpyinfo->x_highlight_frame
1051         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1052            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1053            : dpyinfo->x_focus_frame);
1054       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1055         {
1056           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1057           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1058         }
1059     }
1060   else
1061       dpyinfo->x_highlight_frame = 0;
1063   if (dpyinfo->x_highlight_frame &&
1064          dpyinfo->x_highlight_frame != old_highlight)
1065     {
1066       if (old_highlight)
1067         {
1068           x_update_cursor (old_highlight, 1);
1069           x_set_frame_alpha (old_highlight);
1070         }
1071       if (dpyinfo->x_highlight_frame)
1072         {
1073           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1074           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1075         }
1076     }
1080 void
1081 x_make_frame_visible (struct frame *f)
1082 /* --------------------------------------------------------------------------
1083      External: Show the window (X11 semantics)
1084    -------------------------------------------------------------------------- */
1086   NSTRACE (x_make_frame_visible);
1087   /* XXX: at some points in past this was not needed, as the only place that
1088      called this (frame.c:Fraise_frame ()) also called raise_lower;
1089      if this ends up the case again, comment this out again. */
1090   if (!FRAME_VISIBLE_P (f))
1091     {
1092       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1094       SET_FRAME_VISIBLE (f, 1);
1095       ns_raise_frame (f);
1097 #ifdef NEW_STYLE_FS
1098       /* Making a new frame from a fullscreen frame will make the new frame
1099          fullscreen also.  So skip handleFS as this will print an error.  */
1100       if (f->want_fullscreen == FULLSCREEN_BOTH
1101           && ([[view window] styleMask] & NSFullScreenWindowMask) != 0)
1102         return;
1103 #endif
1104       if (f->want_fullscreen != FULLSCREEN_NONE)
1105         {
1106           block_input ();
1107           [view handleFS];
1108           unblock_input ();
1109         }
1110     }
1114 void
1115 x_make_frame_invisible (struct frame *f)
1116 /* --------------------------------------------------------------------------
1117      External: Hide the window (X11 semantics)
1118    -------------------------------------------------------------------------- */
1120   NSView * view = FRAME_NS_VIEW (f);
1121   NSTRACE (x_make_frame_invisible);
1122   check_ns ();
1123   [[view window] orderOut: NSApp];
1124   SET_FRAME_VISIBLE (f, 0);
1125   SET_FRAME_ICONIFIED (f, 0);
1129 void
1130 x_iconify_frame (struct frame *f)
1131 /* --------------------------------------------------------------------------
1132      External: Iconify window
1133    -------------------------------------------------------------------------- */
1135   NSView * view = FRAME_NS_VIEW (f);
1136   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1137   NSTRACE (x_iconify_frame);
1138   check_ns ();
1140   if (dpyinfo->x_highlight_frame == f)
1141     dpyinfo->x_highlight_frame = 0;
1143   if ([[view window] windowNumber] <= 0)
1144     {
1145       /* the window is still deferred.  Make it very small, bring it
1146          on screen and order it out. */
1147       NSRect s = { { 100, 100}, {0, 0} };
1148       NSRect t;
1149       t = [[view window] frame];
1150       [[view window] setFrame: s display: NO];
1151       [[view window] orderBack: NSApp];
1152       [[view window] orderOut: NSApp];
1153       [[view window] setFrame: t display: NO];
1154     }
1155   [[view window] miniaturize: NSApp];
1158 /* Free X resources of frame F.  */
1160 void
1161 x_free_frame_resources (struct frame *f)
1163   NSView *view = FRAME_NS_VIEW (f);
1164   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1165   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1166   NSTRACE (x_free_frame_resources);
1167   check_ns ();
1169   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1171   block_input ();
1173   free_frame_menubar (f);
1175   if (FRAME_FACE_CACHE (f))
1176     free_frame_faces (f);
1178   if (f == dpyinfo->x_focus_frame)
1179     dpyinfo->x_focus_frame = 0;
1180   if (f == dpyinfo->x_highlight_frame)
1181     dpyinfo->x_highlight_frame = 0;
1182   if (f == hlinfo->mouse_face_mouse_frame)
1183     {
1184       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1185       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1186       hlinfo->mouse_face_window = Qnil;
1187       hlinfo->mouse_face_mouse_frame = 0;
1188     }
1190   if (f->output_data.ns->miniimage != nil)
1191     [f->output_data.ns->miniimage release];
1193   [[view window] close];
1194   [view release];
1196   xfree (f->output_data.ns);
1198   unblock_input ();
1201 void
1202 x_destroy_window (struct frame *f)
1203 /* --------------------------------------------------------------------------
1204      External: Delete the window
1205    -------------------------------------------------------------------------- */
1207   NSTRACE (x_destroy_window);
1208   check_ns ();
1209   x_free_frame_resources (f);
1210   ns_window_num--;
1214 void
1215 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1216 /* --------------------------------------------------------------------------
1217      External: Position the window
1218    -------------------------------------------------------------------------- */
1220   NSView *view = FRAME_NS_VIEW (f);
1221   NSArray *screens = [NSScreen screens];
1222   NSScreen *fscreen = [screens objectAtIndex: 0];
1223   NSScreen *screen = [[view window] screen];
1225   NSTRACE (x_set_offset);
1227   block_input ();
1229   f->left_pos = xoff;
1230   f->top_pos = yoff;
1232   if (view != nil && screen && fscreen)
1233     {
1234       f->left_pos = f->size_hint_flags & XNegative
1235         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1236         : f->left_pos;
1237       /* We use visibleFrame here to take menu bar into account.
1238          Ideally we should also adjust left/top with visibleFrame.origin.  */
1240       f->top_pos = f->size_hint_flags & YNegative
1241         ? ([screen visibleFrame].size.height + f->top_pos
1242            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1243            - FRAME_TOOLBAR_HEIGHT (f))
1244         : f->top_pos;
1245 #ifdef NS_IMPL_GNUSTEP
1246       if (f->left_pos < 100)
1247         f->left_pos = 100;  /* don't overlap menu */
1248 #endif
1249       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1250          menu bar.  */
1251       f->output_data.ns->dont_constrain = 0;
1252       [[view window] setFrameTopLeftPoint:
1253                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1254                                     SCREENMAXBOUND ([fscreen frame].size.height
1255                                                     - NS_TOP_POS (f)))];
1256       f->size_hint_flags &= ~(XNegative|YNegative);
1257     }
1259   unblock_input ();
1263 void
1264 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1265 /* --------------------------------------------------------------------------
1266      Adjust window pixel size based on given character grid size
1267      Impl is a bit more complex than other terms, need to do some
1268      internal clipping.
1269    -------------------------------------------------------------------------- */
1271   EmacsView *view = FRAME_NS_VIEW (f);
1272   NSWindow *window = [view window];
1273   NSRect wr = [window frame];
1274   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1275   int pixelwidth, pixelheight;
1277   NSTRACE (x_set_window_size);
1279   if (view == nil)
1280     return;
1282 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1284   block_input ();
1286   check_frame_size (f, &rows, &cols);
1288   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1289   compute_fringe_widths (f, 0);
1291   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1292   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1294   /* If we have a toolbar, take its height into account. */
1295   if (tb)
1296     /* NOTE: previously this would generate wrong result if toolbar not
1297              yet displayed and fixing toolbar_height=32 helped, but
1298              now (200903) seems no longer needed */
1299     FRAME_TOOLBAR_HEIGHT (f) =
1300       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1301         - FRAME_NS_TITLEBAR_HEIGHT (f);
1302   else
1303     FRAME_TOOLBAR_HEIGHT (f) = 0;
1305   wr.size.width = pixelwidth + f->border_width;
1306   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f)
1307                   + FRAME_TOOLBAR_HEIGHT (f);
1309   /* Do not try to constrain to this screen.  We may have multiple
1310      screens, and want Emacs to span those.  Constraining to screen
1311      prevents that, and that is not nice to the user.  */
1312  if (f->output_data.ns->zooming)
1313    f->output_data.ns->zooming = 0;
1314  else
1315    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1317   [view setRows: rows andColumns: cols];
1318   [window setFrame: wr display: YES];
1320 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1322   /* This is a trick to compensate for Emacs' managing the scrollbar area
1323      as a fixed number of standard character columns.  Instead of leaving
1324      blank space for the extra, we chopped it off above.  Now for
1325      left-hand scrollbars, we shift all rendering to the left by the
1326      difference between the real width and Emacs' imagined one.  For
1327      right-hand bars, don't worry about it since the extra is never used.
1328      (Obviously doesn't work for vertically split windows tho..) */
1329   {
1330     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1331       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1332                      - NS_SCROLL_BAR_WIDTH (f), 0)
1333       : NSMakePoint (0, 0);
1334     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1335     [view setBoundsOrigin: origin];
1336   }
1338   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1339   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1340   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1341 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1343   mark_window_cursors_off (XWINDOW (f->root_window));
1344   cancel_mouse_face (f);
1346   unblock_input ();
1350 static void
1351 ns_fullscreen_hook (FRAME_PTR f)
1353   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1355   if (!FRAME_VISIBLE_P (f))
1356     return;
1358 #ifndef NEW_STYLE_FS
1359   if (f->want_fullscreen == FULLSCREEN_BOTH)
1360     {
1361       /* Old style fs don't initiate correctly if created from
1362          init/default-frame alist, so use a timer (not nice...).
1363       */
1364       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1365                                      selector: @selector (handleFS)
1366                                      userInfo: nil repeats: NO];
1367       return;
1368     }
1369 #endif
1371   block_input ();
1372   [view handleFS];
1373   unblock_input ();
1376 /* ==========================================================================
1378     Color management
1380    ========================================================================== */
1383 NSColor *
1384 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1386   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1387   if (idx < 1 || idx >= color_table->avail)
1388     return nil;
1389   return color_table->colors[idx];
1393 unsigned long
1394 ns_index_color (NSColor *color, struct frame *f)
1396   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1397   ptrdiff_t idx;
1398   ptrdiff_t i;
1400   if (!color_table->colors)
1401     {
1402       color_table->size = NS_COLOR_CAPACITY;
1403       color_table->avail = 1; /* skip idx=0 as marker */
1404       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1405       color_table->colors[0] = nil;
1406       color_table->empty_indices = [[NSMutableSet alloc] init];
1407     }
1409   /* do we already have this color ? */
1410   for (i = 1; i < color_table->avail; i++)
1411     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1412       return i;
1414   if ([color_table->empty_indices count] > 0)
1415     {
1416       NSNumber *index = [color_table->empty_indices anyObject];
1417       [color_table->empty_indices removeObject: index];
1418       idx = [index unsignedLongValue];
1419     }
1420   else
1421     {
1422       if (color_table->avail == color_table->size)
1423         color_table->colors =
1424           xpalloc (color_table->colors, &color_table->size, 1,
1425                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1426       idx = color_table->avail++;
1427     }
1429   color_table->colors[idx] = color;
1430   [color retain];
1431 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1432   return idx;
1436 void
1437 ns_free_indexed_color (unsigned long idx, struct frame *f)
1439   struct ns_color_table *color_table;
1440   NSColor *color;
1441   NSNumber *index;
1443   if (!f)
1444     return;
1446   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1448   if (idx <= 0 || idx >= color_table->size) {
1449     message1 ("ns_free_indexed_color: Color index out of range.\n");
1450     return;
1451   }
1453   index = [NSNumber numberWithUnsignedInt: idx];
1454   if ([color_table->empty_indices containsObject: index]) {
1455     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1456     return;
1457   }
1459   color = color_table->colors[idx];
1460   [color release];
1461   color_table->colors[idx] = nil;
1462   [color_table->empty_indices addObject: index];
1463 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1467 static int
1468 ns_get_color (const char *name, NSColor **col)
1469 /* --------------------------------------------------------------------------
1470      Parse a color name
1471    -------------------------------------------------------------------------- */
1472 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1473    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1474    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1476   NSColor *new = nil;
1477   static char hex[20];
1478   int scaling;
1479   float r = -1.0, g, b;
1480   NSString *nsname = [NSString stringWithUTF8String: name];
1482 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1483   block_input ();
1485   if ([nsname isEqualToString: @"ns_selection_color"])
1486     {
1487       nsname = ns_selection_color;
1488       name = [ns_selection_color UTF8String];
1489     }
1491   /* First, check for some sort of numeric specification. */
1492   hex[0] = '\0';
1494   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1495     {
1496       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1497       [scanner scanFloat: &r];
1498       [scanner scanFloat: &g];
1499       [scanner scanFloat: &b];
1500     }
1501   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1502     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1503   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1504     {
1505       int len = (strlen(name) - 1);
1506       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1507       int i;
1508       scaling = strlen(name+start) / 3;
1509       for (i = 0; i < 3; i++)
1510         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1511                  name + start + i * scaling);
1512       hex[3 * (scaling + 1) - 1] = '\0';
1513     }
1515   if (hex[0])
1516     {
1517       int rr, gg, bb;
1518       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1519       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1520         {
1521           r = rr / fscale;
1522           g = gg / fscale;
1523           b = bb / fscale;
1524         }
1525     }
1527   if (r >= 0.0)
1528     {
1529       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1530       unblock_input ();
1531       return 0;
1532     }
1534   /* Otherwise, color is expected to be from a list */
1535   {
1536     NSEnumerator *lenum, *cenum;
1537     NSString *name;
1538     NSColorList *clist;
1540 #ifdef NS_IMPL_GNUSTEP
1541     /* XXX: who is wrong, the requestor or the implementation? */
1542     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1543         == NSOrderedSame)
1544       nsname = @"highlightColor";
1545 #endif
1547     lenum = [[NSColorList availableColorLists] objectEnumerator];
1548     while ( (clist = [lenum nextObject]) && new == nil)
1549       {
1550         cenum = [[clist allKeys] objectEnumerator];
1551         while ( (name = [cenum nextObject]) && new == nil )
1552           {
1553             if ([name compare: nsname
1554                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1555               new = [clist colorWithKey: name];
1556           }
1557       }
1558   }
1560   if (new)
1561     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1562   unblock_input ();
1563   return new ? 0 : 1;
1568 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1569 /* --------------------------------------------------------------------------
1570      Convert a Lisp string object to a NS color
1571    -------------------------------------------------------------------------- */
1573   NSTRACE (ns_lisp_to_color);
1574   if (STRINGP (color))
1575     return ns_get_color (SSDATA (color), col);
1576   else if (SYMBOLP (color))
1577     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1578   return 1;
1582 Lisp_Object
1583 ns_color_to_lisp (NSColor *col)
1584 /* --------------------------------------------------------------------------
1585      Convert a color to a lisp string with the RGB equivalent
1586    -------------------------------------------------------------------------- */
1588   CGFloat red, green, blue, alpha, gray;
1589   char buf[1024];
1590   const char *str;
1591   NSTRACE (ns_color_to_lisp);
1593   block_input ();
1594   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1596       if ((str =[[col colorNameComponent] UTF8String]))
1597         {
1598           unblock_input ();
1599           return build_string ((char *)str);
1600         }
1602     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1603         getRed: &red green: &green blue: &blue alpha: &alpha];
1604   if (red ==green && red ==blue)
1605     {
1606       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1607             getWhite: &gray alpha: &alpha];
1608       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1609                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1610       unblock_input ();
1611       return build_string (buf);
1612     }
1614   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1615             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1617   unblock_input ();
1618   return build_string (buf);
1622 void
1623 ns_query_color(void *col, XColor *color_def, int setPixel)
1624 /* --------------------------------------------------------------------------
1625          Get ARGB values out of NSColor col and put them into color_def.
1626          If setPixel, set the pixel to a concatenated version.
1627          and set color_def pixel to the resulting index.
1628    -------------------------------------------------------------------------- */
1630   CGFloat r, g, b, a;
1632   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1633   color_def->red   = r * 65535;
1634   color_def->green = g * 65535;
1635   color_def->blue  = b * 65535;
1637   if (setPixel == YES)
1638     color_def->pixel
1639       = ARGB_TO_ULONG((int)(a*255),
1640                       (int)(r*255), (int)(g*255), (int)(b*255));
1644 bool
1645 ns_defined_color (struct frame *f,
1646                   const char *name,
1647                   XColor *color_def,
1648                   bool alloc,
1649                   bool makeIndex)
1650 /* --------------------------------------------------------------------------
1651          Return true if named color found, and set color_def rgb accordingly.
1652          If makeIndex and alloc are nonzero put the color in the color_table,
1653          and set color_def pixel to the resulting index.
1654          If makeIndex is zero, set color_def pixel to ARGB.
1655          Return false if not found
1656    -------------------------------------------------------------------------- */
1658   NSColor *col;
1659   NSTRACE (ns_defined_color);
1661   block_input ();
1662   if (ns_get_color (name, &col) != 0) /* Color not found  */
1663     {
1664       unblock_input ();
1665       return 0;
1666     }
1667   if (makeIndex && alloc)
1668     color_def->pixel = ns_index_color (col, f);
1669   ns_query_color (col, color_def, !makeIndex);
1670   unblock_input ();
1671   return 1;
1675 unsigned long
1676 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1677 /* --------------------------------------------------------------------------
1678     return an autoreleased RGB color
1679    -------------------------------------------------------------------------- */
1681 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1682   if (r < 0.0) r = 0.0;
1683   else if (r > 1.0) r = 1.0;
1684   if (g < 0.0) g = 0.0;
1685   else if (g > 1.0) g = 1.0;
1686   if (b < 0.0) b = 0.0;
1687   else if (b > 1.0) b = 1.0;
1688   if (a < 0.0) a = 0.0;
1689   else if (a > 1.0) a = 1.0;
1690   return (unsigned long) ns_index_color(
1691     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1695 void
1696 x_set_frame_alpha (struct frame *f)
1697 /* --------------------------------------------------------------------------
1698      change the entire-frame transparency
1699    -------------------------------------------------------------------------- */
1701   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1702   EmacsView *view = FRAME_NS_VIEW (f);
1703   double alpha = 1.0;
1704   double alpha_min = 1.0;
1706   if (dpyinfo->x_highlight_frame == f)
1707     alpha = f->alpha[0];
1708   else
1709     alpha = f->alpha[1];
1711   if (FLOATP (Vframe_alpha_lower_limit))
1712     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1713   else if (INTEGERP (Vframe_alpha_lower_limit))
1714     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1716   if (alpha < 0.0)
1717     return;
1718   else if (1.0 < alpha)
1719     alpha = 1.0;
1720   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1721     alpha = alpha_min;
1723 #ifdef NS_IMPL_COCOA
1724   [[view window] setAlphaValue: alpha];
1725 #endif
1729 /* ==========================================================================
1731     Mouse handling
1733    ========================================================================== */
1736 void
1737 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1738 /* --------------------------------------------------------------------------
1739      Programmatically reposition mouse pointer in pixel coordinates
1740    -------------------------------------------------------------------------- */
1742   NSTRACE (x_set_mouse_pixel_position);
1743   ns_raise_frame (f);
1744 #if 0
1745   /* FIXME: this does not work, and what about GNUstep? */
1746 #ifdef NS_IMPL_COCOA
1747   [FRAME_NS_VIEW (f) lockFocus];
1748   PSsetmouse ((float)pix_x, (float)pix_y);
1749   [FRAME_NS_VIEW (f) unlockFocus];
1750 #endif
1751 #endif
1755 void
1756 x_set_mouse_position (struct frame *f, int h, int v)
1757 /* --------------------------------------------------------------------------
1758      Programmatically reposition mouse pointer in character coordinates
1759    -------------------------------------------------------------------------- */
1761   int pix_x, pix_y;
1763   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1764   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1766   if (pix_x < 0) pix_x = 0;
1767   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1769   if (pix_y < 0) pix_y = 0;
1770   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1772   x_set_mouse_pixel_position (f, pix_x, pix_y);
1776 static int
1777 note_mouse_movement (struct frame *frame, float x, float y)
1778 /*   ------------------------------------------------------------------------
1779      Called by EmacsView on mouseMovement events.  Passes on
1780      to emacs mainstream code if we moved off of a rect of interest
1781      known as last_mouse_glyph.
1782      ------------------------------------------------------------------------ */
1784 //  NSTRACE (note_mouse_movement);
1786   XSETFRAME (last_mouse_motion_frame, frame);
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 < last_mouse_glyph.origin.x ||
1793       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1794       y < last_mouse_glyph.origin.y ||
1795       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1796     {
1797       ns_update_begin(frame);
1798       frame->mouse_moved = 1;
1799       note_mouse_highlight (frame, x, y);
1800       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1801       ns_update_end(frame);
1802       return 1;
1803     }
1805   return 0;
1809 static void
1810 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1811                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1812                    Time *time)
1813 /* --------------------------------------------------------------------------
1814     External (hook): inform emacs about mouse position and hit parts.
1815     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1816     x & y should be position in the scrollbar (the whole bar, not the handle)
1817     and length of scrollbar respectively
1818    -------------------------------------------------------------------------- */
1820   id view;
1821   NSPoint position;
1822   Lisp_Object frame, tail;
1823   struct frame *f;
1824   struct ns_display_info *dpyinfo;
1826   NSTRACE (ns_mouse_position);
1828   if (*fp == NULL)
1829     {
1830       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1831       return;
1832     }
1834   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1836   block_input ();
1838   if (last_mouse_scroll_bar != nil && insist == 0)
1839     {
1840       /* TODO: we do not use this path at the moment because drag events will
1841            go directly to the EmacsScroller.  Leaving code in for now. */
1842       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1843                                               x: x y: y];
1844       if (time) *time = last_mouse_movement_time;
1845       last_mouse_scroll_bar = nil;
1846     }
1847   else
1848     {
1849       /* Clear the mouse-moved flag for every frame on this display.  */
1850       FOR_EACH_FRAME (tail, frame)
1851         if (FRAME_NS_P (XFRAME (frame))
1852             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1853           XFRAME (frame)->mouse_moved = 0;
1855       last_mouse_scroll_bar = nil;
1856       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1857         f = last_mouse_frame;
1858       else
1859         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1860                                     : SELECTED_FRAME ();
1862       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
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, &last_mouse_glyph);
1869 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1871           if (bar_window) *bar_window = Qnil;
1872           if (part) *part = 0; /*scroll_bar_handle; */
1874           if (x) XSETINT (*x, lrint (position.x));
1875           if (y) XSETINT (*y, lrint (position.y));
1876           if (time) *time = last_mouse_movement_time;
1877           *fp = f;
1878         }
1879     }
1881   unblock_input ();
1885 static void
1886 ns_frame_up_to_date (struct frame *f)
1887 /* --------------------------------------------------------------------------
1888     External (hook): Fix up mouse highlighting right after a full update.
1889     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1890    -------------------------------------------------------------------------- */
1892   NSTRACE (ns_frame_up_to_date);
1894   if (FRAME_NS_P (f))
1895     {
1896       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1897       if (f == hlinfo->mouse_face_mouse_frame)
1898         {
1899           block_input ();
1900           ns_update_begin(f);
1901           if (hlinfo->mouse_face_mouse_frame)
1902             note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1903                                   hlinfo->mouse_face_mouse_x,
1904                                   hlinfo->mouse_face_mouse_y);
1905           ns_update_end(f);
1906           unblock_input ();
1907         }
1908     }
1912 static void
1913 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1914 /* --------------------------------------------------------------------------
1915     External (RIF): set frame mouse pointer type.
1916    -------------------------------------------------------------------------- */
1918   NSTRACE (ns_define_frame_cursor);
1919   if (FRAME_POINTER_TYPE (f) != cursor)
1920     {
1921       EmacsView *view = FRAME_NS_VIEW (f);
1922       FRAME_POINTER_TYPE (f) = cursor;
1923       [[view window] invalidateCursorRectsForView: view];
1924       /* Redisplay assumes this function also draws the changed frame
1925          cursor, but this function doesn't, so do it explicitly.  */
1926       x_update_cursor (f, 1);
1927     }
1932 /* ==========================================================================
1934     Keyboard handling
1936    ========================================================================== */
1939 static unsigned
1940 ns_convert_key (unsigned code)
1941 /* --------------------------------------------------------------------------
1942     Internal call used by NSView-keyDown.
1943    -------------------------------------------------------------------------- */
1945   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1946                                 / sizeof (convert_ns_to_X_keysym[0]));
1947   unsigned keysym;
1948   /* An array would be faster, but less easy to read. */
1949   for (keysym = 0; keysym < last_keysym; keysym += 2)
1950     if (code == convert_ns_to_X_keysym[keysym])
1951       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1952   return 0;
1953 /* if decide to use keyCode and Carbon table, use this line:
1954      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1958 char *
1959 x_get_keysym_name (int keysym)
1960 /* --------------------------------------------------------------------------
1961     Called by keyboard.c.  Not sure if the return val is important, except
1962     that it be unique.
1963    -------------------------------------------------------------------------- */
1965   static char value[16];
1966   NSTRACE (x_get_keysym_name);
1967   sprintf (value, "%d", keysym);
1968   return value;
1973 /* ==========================================================================
1975     Block drawing operations
1977    ========================================================================== */
1980 static void
1981 ns_redraw_scroll_bars (struct frame *f)
1983   int i;
1984   id view;
1985   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1986   NSTRACE (ns_redraw_scroll_bars);
1987   for (i =[subviews count]-1; i >= 0; i--)
1988     {
1989       view = [subviews objectAtIndex: i];
1990       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1991       [view display];
1992     }
1996 void
1997 ns_clear_frame (struct frame *f)
1998 /* --------------------------------------------------------------------------
1999       External (hook): Erase the entire frame
2000    -------------------------------------------------------------------------- */
2002   NSView *view = FRAME_NS_VIEW (f);
2003   NSRect r;
2005   NSTRACE (ns_clear_frame);
2007  /* comes on initial frame because we have
2008     after-make-frame-functions = select-frame */
2009  if (!FRAME_DEFAULT_FACE (f))
2010    return;
2012   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2014   output_cursor.hpos = output_cursor.vpos = 0;
2015   output_cursor.x = -1;
2017   r = [view bounds];
2019   block_input ();
2020   ns_focus (f, &r, 1);
2021   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2022   NSRectFill (r);
2023   ns_unfocus (f);
2025   /* as of 2006/11 or so this is now needed */
2026   ns_redraw_scroll_bars (f);
2027   unblock_input ();
2031 static void
2032 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2033 /* --------------------------------------------------------------------------
2034     External (RIF):  Clear section of frame
2035    -------------------------------------------------------------------------- */
2037   NSRect r = NSMakeRect (x, y, width, height);
2038   NSView *view = FRAME_NS_VIEW (f);
2039   struct face *face = FRAME_DEFAULT_FACE (f);
2041   if (!view || !face)
2042     return;
2044   NSTRACE (ns_clear_frame_area);
2046   r = NSIntersectionRect (r, [view frame]);
2047   ns_focus (f, &r, 1);
2048   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2050   NSRectFill (r);
2052   ns_unfocus (f);
2053   return;
2057 static void
2058 ns_scroll_run (struct window *w, struct run *run)
2059 /* --------------------------------------------------------------------------
2060     External (RIF):  Insert or delete n lines at line vpos
2061    -------------------------------------------------------------------------- */
2063   struct frame *f = XFRAME (w->frame);
2064   int x, y, width, height, from_y, to_y, bottom_y;
2066   NSTRACE (ns_scroll_run);
2068   /* begin copy from other terms */
2069   /* Get frame-relative bounding box of the text display area of W,
2070      without mode lines.  Include in this box the left and right
2071      fringe of W.  */
2072   window_box (w, -1, &x, &y, &width, &height);
2074   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2075   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2076   bottom_y = y + height;
2078   if (to_y < from_y)
2079     {
2080       /* Scrolling up.  Make sure we don't copy part of the mode
2081          line at the bottom.  */
2082       if (from_y + run->height > bottom_y)
2083         height = bottom_y - from_y;
2084       else
2085         height = run->height;
2086     }
2087   else
2088     {
2089       /* Scrolling down.  Make sure we don't copy over the mode line.
2090          at the bottom.  */
2091       if (to_y + run->height > bottom_y)
2092         height = bottom_y - to_y;
2093       else
2094         height = run->height;
2095     }
2096   /* end copy from other terms */
2098   if (height == 0)
2099       return;
2101   block_input ();
2103   updated_window = w;
2104   x_clear_cursor (w);
2106   {
2107     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2108     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2109     NSPoint dstOrigin = NSMakePoint (x, to_y);
2111     ns_focus (f, &dstRect, 1);
2112     NSCopyBits (0, srcRect , dstOrigin);
2113     ns_unfocus (f);
2114   }
2116   unblock_input ();
2120 static void
2121 ns_after_update_window_line (struct glyph_row *desired_row)
2122 /* --------------------------------------------------------------------------
2123     External (RIF): preparatory to fringe update after text was updated
2124    -------------------------------------------------------------------------- */
2126   struct window *w = updated_window;
2127   struct frame *f;
2128   int width, height;
2130   NSTRACE (ns_after_update_window_line);
2132   /* begin copy from other terms */
2133   eassert (w);
2135   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2136     desired_row->redraw_fringe_bitmaps_p = 1;
2138   /* When a window has disappeared, make sure that no rest of
2139      full-width rows stays visible in the internal border.  */
2140   if (windows_or_buffers_changed
2141       && desired_row->full_width_p
2142       && (f = XFRAME (w->frame),
2143           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2144           width != 0)
2145       && (height = desired_row->visible_height,
2146           height > 0))
2147     {
2148       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2150       block_input ();
2151       ns_clear_frame_area (f, 0, y, width, height);
2152       ns_clear_frame_area (f,
2153                            FRAME_PIXEL_WIDTH (f) - width,
2154                            y, width, height);
2155       unblock_input ();
2156     }
2160 static void
2161 ns_shift_glyphs_for_insert (struct frame *f,
2162                            int x, int y, int width, int height,
2163                            int shift_by)
2164 /* --------------------------------------------------------------------------
2165     External (RIF): copy an area horizontally, don't worry about clearing src
2166    -------------------------------------------------------------------------- */
2168   NSRect srcRect = NSMakeRect (x, y, width, height);
2169   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2170   NSPoint dstOrigin = dstRect.origin;
2172   NSTRACE (ns_shift_glyphs_for_insert);
2174   ns_focus (f, &dstRect, 1);
2175   NSCopyBits (0, srcRect, dstOrigin);
2176   ns_unfocus (f);
2181 /* ==========================================================================
2183     Character encoding and metrics
2185    ========================================================================== */
2188 static void
2189 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2190 /* --------------------------------------------------------------------------
2191      External (RIF); compute left/right overhang of whole string and set in s
2192    -------------------------------------------------------------------------- */
2194   struct font *font = s->font;
2196   if (s->char2b)
2197     {
2198       struct font_metrics metrics;
2199       unsigned int codes[2];
2200       codes[0] = *(s->char2b);
2201       codes[1] = *(s->char2b + s->nchars - 1);
2203       font->driver->text_extents (font, codes, 2, &metrics);
2204       s->left_overhang = -metrics.lbearing;
2205       s->right_overhang
2206         = metrics.rbearing > metrics.width
2207         ? metrics.rbearing - metrics.width : 0;
2208     }
2209   else
2210     {
2211       s->left_overhang = 0;
2212       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2213         FONT_HEIGHT (font) * 0.2 : 0;
2214     }
2219 /* ==========================================================================
2221     Fringe and cursor drawing
2223    ========================================================================== */
2226 extern int max_used_fringe_bitmap;
2227 static void
2228 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2229                       struct draw_fringe_bitmap_params *p)
2230 /* --------------------------------------------------------------------------
2231     External (RIF); fringe-related
2232    -------------------------------------------------------------------------- */
2234   struct frame *f = XFRAME (WINDOW_FRAME (w));
2235   struct face *face = p->face;
2236   int rowY;
2237   static EmacsImage **bimgs = NULL;
2238   static int nBimgs = 0;
2240   /* grow bimgs if needed */
2241   if (nBimgs < max_used_fringe_bitmap)
2242     {
2243       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2244       memset (bimgs + nBimgs, 0,
2245               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2246       nBimgs = max_used_fringe_bitmap;
2247     }
2249   /* Must clip because of partially visible lines.  */
2250   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2251   ns_clip_to_row (w, row, -1, YES);
2253   if (!p->overlay_p)
2254     {
2255       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2257       /* If the fringe is adjacent to the left (right) scroll bar of a
2258          leftmost (rightmost, respectively) window, then extend its
2259          background to the gap between the fringe and the bar.  */
2260       if ((WINDOW_LEFTMOST_P (w)
2261            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2262           || (WINDOW_RIGHTMOST_P (w)
2263               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2264         {
2265           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2267           if (sb_width > 0)
2268             {
2269               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2270               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2271                                     * FRAME_COLUMN_WIDTH (f));
2273               if (bx < 0)
2274                 {
2275                   /* Bitmap fills the fringe.  */
2276                   if (bar_area_x + bar_area_width == p->x)
2277                     bx = bar_area_x + sb_width;
2278                   else if (p->x + p->wd == bar_area_x)
2279                     bx = bar_area_x;
2280                   if (bx >= 0)
2281                     {
2282                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2284                       nx = bar_area_width - sb_width;
2285                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2286                                                             row->y));
2287                       ny = row->visible_height;
2288                     }
2289                 }
2290               else
2291                 {
2292                   if (bar_area_x + bar_area_width == bx)
2293                     {
2294                       bx = bar_area_x + sb_width;
2295                       nx += bar_area_width - sb_width;
2296                     }
2297                   else if (bx + nx == bar_area_x)
2298                     nx += bar_area_width - sb_width;
2299                 }
2300             }
2301         }
2303       if (bx >= 0 && nx > 0)
2304         {
2305           NSRect r = NSMakeRect (bx, by, nx, ny);
2306           NSRectClip (r);
2307           [ns_lookup_indexed_color (face->background, f) set];
2308           NSRectFill (r);
2309         }
2310     }
2312   if (p->which)
2313     {
2314       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2315       EmacsImage *img = bimgs[p->which - 1];
2317       if (!img)
2318         {
2319           unsigned short *bits = p->bits + p->dh;
2320           int len = p->h;
2321           int i;
2322           unsigned char *cbits = xmalloc (len);
2324           for (i = 0; i < len; i++)
2325             cbits[i] = ~(bits[i] & 0xff);
2326           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2327                                            flip: NO];
2328           bimgs[p->which - 1] = img;
2329           xfree (cbits);
2330         }
2332       NSRectClip (r);
2333       /* Since we composite the bitmap instead of just blitting it, we need
2334          to erase the whole background. */
2335       [ns_lookup_indexed_color(face->background, f) set];
2336       NSRectFill (r);
2337       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2338 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2339       [img drawInRect: r
2340               fromRect: NSZeroRect
2341              operation: NSCompositeSourceOver
2342               fraction: 1.0
2343            respectFlipped: YES
2344                 hints: nil];
2345 #else
2346       {
2347         NSPoint pt = r.origin;
2348         pt.y += p->h;
2349         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2350       }
2351 #endif
2352     }
2353   ns_unfocus (f);
2357 static void
2358 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2359                        int x, int y, int cursor_type, int cursor_width,
2360                        int on_p, int active_p)
2361 /* --------------------------------------------------------------------------
2362      External call (RIF): draw cursor.
2363      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2364    -------------------------------------------------------------------------- */
2366   NSRect r, s;
2367   int fx, fy, h, cursor_height;
2368   struct frame *f = WINDOW_XFRAME (w);
2369   struct glyph *phys_cursor_glyph;
2370   int overspill;
2371   struct glyph *cursor_glyph;
2372   struct face *face;
2373   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2375   /* If cursor is out of bounds, don't draw garbage.  This can happen
2376      in mini-buffer windows when switching between echo area glyphs
2377      and mini-buffer.  */
2379   NSTRACE (dumpcursor);
2381   if (!on_p)
2382     return;
2384   w->phys_cursor_type = cursor_type;
2385   w->phys_cursor_on_p = on_p;
2387   if (cursor_type == NO_CURSOR)
2388     {
2389       w->phys_cursor_width = 0;
2390       return;
2391     }
2393   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2394     {
2395       if (glyph_row->exact_window_width_line_p
2396           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2397         {
2398           glyph_row->cursor_in_fringe_p = 1;
2399           draw_fringe_bitmap (w, glyph_row, 0);
2400         }
2401       return;
2402     }
2404   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2405      (other terminals do it the other way round).  We must set
2406      w->phys_cursor_width to the cursor width.  For bar cursors, that
2407      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2408   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2410   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2411      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2412   if (cursor_type == BAR_CURSOR)
2413     {
2414       if (cursor_width < 1)
2415         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2416       w->phys_cursor_width = cursor_width;
2417     }
2418   /* If we have an HBAR, "cursor_width" MAY specify height. */
2419   else if (cursor_type == HBAR_CURSOR)
2420     {
2421       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2422       fy += h - cursor_height;
2423       h = cursor_height;
2424     }
2426   r.origin.x = fx, r.origin.y = fy;
2427   r.size.height = h;
2428   r.size.width = w->phys_cursor_width;
2430   /* TODO: only needed in rare cases with last-resort font in HELLO..
2431      should we do this more efficiently? */
2432   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2435   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2436   if (face && NS_FACE_BACKGROUND (face)
2437       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2438     {
2439       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2440       hollow_color = FRAME_CURSOR_COLOR (f);
2441     }
2442   else
2443     [FRAME_CURSOR_COLOR (f) set];
2445 #ifdef NS_IMPL_COCOA
2446   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2447            atomic.  Cleaner ways of doing this should be investigated.
2448            One way would be to set a global variable DRAWING_CURSOR
2449            when making the call to draw_phys..(), don't focus in that
2450            case, then move the ns_unfocus() here after that call. */
2451   NSDisableScreenUpdates ();
2452 #endif
2454   switch (cursor_type)
2455     {
2456     case NO_CURSOR:
2457       break;
2458     case FILLED_BOX_CURSOR:
2459       NSRectFill (r);
2460       break;
2461     case HOLLOW_BOX_CURSOR:
2462       NSRectFill (r);
2463       [hollow_color set];
2464       NSRectFill (NSInsetRect (r, 1, 1));
2465       [FRAME_CURSOR_COLOR (f) set];
2466       break;
2467     case HBAR_CURSOR:
2468       NSRectFill (r);
2469       break;
2470     case BAR_CURSOR:
2471       s = r;
2472       /* If the character under cursor is R2L, draw the bar cursor
2473          on the right of its glyph, rather than on the left.  */
2474       cursor_glyph = get_phys_cursor_glyph (w);
2475       if ((cursor_glyph->resolved_level & 1) != 0)
2476         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2478       NSRectFill (s);
2479       break;
2480     }
2481   ns_unfocus (f);
2483   /* draw the character under the cursor */
2484   if (cursor_type != NO_CURSOR)
2485     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2487 #ifdef NS_IMPL_COCOA
2488   NSEnableScreenUpdates ();
2489 #endif
2494 static void
2495 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2496 /* --------------------------------------------------------------------------
2497      External (RIF): Draw a vertical line.
2498    -------------------------------------------------------------------------- */
2500   struct frame *f = XFRAME (WINDOW_FRAME (w));
2501   struct face *face;
2502   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2504   NSTRACE (ns_draw_vertical_window_border);
2506   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2507   if (face)
2508       [ns_lookup_indexed_color(face->foreground, f) set];
2510   ns_focus (f, &r, 1);
2511   NSRectFill(r);
2512   ns_unfocus (f);
2516 void
2517 show_hourglass (struct atimer *timer)
2519   if (hourglass_shown_p)
2520     return;
2522   block_input ();
2524   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2526   hourglass_shown_p = 1;
2527   unblock_input ();
2531 void
2532 hide_hourglass (void)
2534   if (!hourglass_shown_p)
2535     return;
2537   block_input ();
2539   /* TODO: remove NSProgressIndicator from all frames */
2541   hourglass_shown_p = 0;
2542   unblock_input ();
2547 /* ==========================================================================
2549     Glyph drawing operations
2551    ========================================================================== */
2553 static int
2554 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2555 /* --------------------------------------------------------------------------
2556     Wrapper utility to account for internal border width on full-width lines,
2557     and allow top full-width rows to hit the frame top.  nr should be pointer
2558     to two successive NSRects.  Number of rects actually used is returned.
2559    -------------------------------------------------------------------------- */
2561   int n = get_glyph_string_clip_rects (s, nr, 2);
2562   return n;
2565 /* --------------------------------------------------------------------
2566    Draw a wavy line under glyph string s. The wave fills wave_height
2567    pixels from y.
2569                     x          wave_length = 2
2570                                  --
2571                 y    *   *   *   *   *
2572                      |* * * * * * * * *
2573     wave_height = 3  | *   *   *   *
2574   --------------------------------------------------------------------- */
2576 static void
2577 ns_draw_underwave (struct glyph_string *s, CGFloat width, CGFloat x)
2579   int wave_height = 3, wave_length = 2;
2580   int y, dx, dy, odd, xmax;
2581   NSPoint a, b;
2582   NSRect waveClip;
2584   dx = wave_length;
2585   dy = wave_height - 1;
2586   y =  s->ybase - wave_height + 3;
2587   xmax = x + width;
2589   /* Find and set clipping rectangle */
2590   waveClip = NSMakeRect (x, y, width, wave_height);
2591   [[NSGraphicsContext currentContext] saveGraphicsState];
2592   NSRectClip (waveClip);
2594   /* Draw the waves */
2595   a.x = x - ((int)(x) % dx) + 0.5;
2596   b.x = a.x + dx;
2597   odd = (int)(a.x/dx) % 2;
2598   a.y = b.y = y + 0.5;
2600   if (odd)
2601     a.y += dy;
2602   else
2603     b.y += dy;
2605   while (a.x <= xmax)
2606     {
2607       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2608       a.x = b.x, a.y = b.y;
2609       b.x += dx, b.y = y + 0.5 + odd*dy;
2610       odd = !odd;
2611     }
2613   /* Restore previous clipping rectangle(s) */
2614   [[NSGraphicsContext currentContext] restoreGraphicsState];
2619 void
2620 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2621                          NSColor *defaultCol, CGFloat width, CGFloat x)
2622 /* --------------------------------------------------------------------------
2623    Draw underline, overline, and strike-through on glyph string s.
2624    -------------------------------------------------------------------------- */
2626   if (s->for_overlaps)
2627     return;
2629   /* Do underline. */
2630   if (face->underline_p)
2631     {
2632       if (s->face->underline_type == FACE_UNDER_WAVE)
2633         {
2634           if (face->underline_defaulted_p)
2635             [defaultCol set];
2636           else
2637             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2639           ns_draw_underwave (s, width, x);
2640         }
2641       else if (s->face->underline_type == FACE_UNDER_LINE)
2642         {
2644           NSRect r;
2645           unsigned long thickness, position;
2647           /* If the prev was underlined, match its appearance. */
2648           if (s->prev && s->prev->face->underline_p
2649               && s->prev->face->underline_type == FACE_UNDER_LINE
2650               && s->prev->underline_thickness > 0)
2651             {
2652               thickness = s->prev->underline_thickness;
2653               position = s->prev->underline_position;
2654             }
2655           else
2656             {
2657               struct font *font;
2658               unsigned long descent;
2660               font=s->font;
2661               descent = s->y + s->height - s->ybase;
2663               /* Use underline thickness of font, defaulting to 1. */
2664               thickness = (font && font->underline_thickness > 0)
2665                 ? font->underline_thickness : 1;
2667               /* Determine the offset of underlining from the baseline. */
2668               if (x_underline_at_descent_line)
2669                 position = descent - thickness;
2670               else if (x_use_underline_position_properties
2671                        && font && font->underline_position >= 0)
2672                 position = font->underline_position;
2673               else if (font)
2674                 position = lround (font->descent / 2);
2675               else
2676                 position = underline_minimum_offset;
2678               position = max (position, underline_minimum_offset);
2680               /* Ensure underlining is not cropped. */
2681               if (descent <= position)
2682                 {
2683                   position = descent - 1;
2684                   thickness = 1;
2685                 }
2686               else if (descent < position + thickness)
2687                 thickness = 1;
2688             }
2690           s->underline_thickness = thickness;
2691           s->underline_position = position;
2693           r = NSMakeRect (x, s->ybase + position, width, thickness);
2695           if (face->underline_defaulted_p)
2696             [defaultCol set];
2697           else
2698             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2699           NSRectFill (r);
2700         }
2701     }
2702   /* Do overline. We follow other terms in using a thickness of 1
2703      and ignoring overline_margin. */
2704   if (face->overline_p)
2705     {
2706       NSRect r;
2707       r = NSMakeRect (x, s->y, width, 1);
2709       if (face->overline_color_defaulted_p)
2710         [defaultCol set];
2711       else
2712         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2713       NSRectFill (r);
2714     }
2716   /* Do strike-through.  We follow other terms for thickness and
2717      vertical position.*/
2718   if (face->strike_through_p)
2719     {
2720       NSRect r;
2721       unsigned long dy;
2723       dy = lrint ((s->height - 1) / 2);
2724       r = NSMakeRect (x, s->y + dy, width, 1);
2726       if (face->strike_through_color_defaulted_p)
2727         [defaultCol set];
2728       else
2729         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2730       NSRectFill (r);
2731     }
2734 static void
2735 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2736 /* --------------------------------------------------------------------------
2737     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2738     Note we can't just use an NSDrawRect command, because of the possibility
2739     of some sides not being drawn, and because the rect will be filled.
2740    -------------------------------------------------------------------------- */
2742   NSRect s = r;
2743   [col set];
2745   /* top, bottom */
2746   s.size.height = thickness;
2747   NSRectFill (s);
2748   s.origin.y += r.size.height - thickness;
2749   NSRectFill (s);
2751   s.size.height = r.size.height;
2752   s.origin.y = r.origin.y;
2754   /* left, right (optional) */
2755   s.size.width = thickness;
2756   if (left_p)
2757     NSRectFill (s);
2758   if (right_p)
2759     {
2760       s.origin.x += r.size.width - thickness;
2761       NSRectFill (s);
2762     }
2766 static void
2767 ns_draw_relief (NSRect r, int thickness, char raised_p,
2768                char top_p, char bottom_p, char left_p, char right_p,
2769                struct glyph_string *s)
2770 /* --------------------------------------------------------------------------
2771     Draw a relief rect inside r, optionally leaving some sides open.
2772     Note we can't just use an NSDrawBezel command, because of the possibility
2773     of some sides not being drawn, and because the rect will be filled.
2774    -------------------------------------------------------------------------- */
2776   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2777   NSColor *newBaseCol = nil;
2778   NSRect sr = r;
2780   NSTRACE (ns_draw_relief);
2782   /* set up colors */
2784   if (s->face->use_box_color_for_shadows_p)
2785     {
2786       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2787     }
2788 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2789            && s->img->pixmap
2790            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2791        {
2792          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2793        } */
2794   else
2795     {
2796       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2797     }
2799   if (newBaseCol == nil)
2800     newBaseCol = [NSColor grayColor];
2802   if (newBaseCol != baseCol)  /* TODO: better check */
2803     {
2804       [baseCol release];
2805       baseCol = [newBaseCol retain];
2806       [lightCol release];
2807       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2808       [darkCol release];
2809       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2810     }
2812   [(raised_p ? lightCol : darkCol) set];
2814   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2816   /* top */
2817   sr.size.height = thickness;
2818   if (top_p) NSRectFill (sr);
2820   /* left */
2821   sr.size.height = r.size.height;
2822   sr.size.width = thickness;
2823   if (left_p) NSRectFill (sr);
2825   [(raised_p ? darkCol : lightCol) set];
2827   /* bottom */
2828   sr.size.width = r.size.width;
2829   sr.size.height = thickness;
2830   sr.origin.y += r.size.height - thickness;
2831   if (bottom_p) NSRectFill (sr);
2833   /* right */
2834   sr.size.height = r.size.height;
2835   sr.origin.y = r.origin.y;
2836   sr.size.width = thickness;
2837   sr.origin.x += r.size.width - thickness;
2838   if (right_p) NSRectFill (sr);
2842 static void
2843 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2844 /* --------------------------------------------------------------------------
2845       Function modeled after x_draw_glyph_string_box ().
2846       Sets up parameters for drawing.
2847    -------------------------------------------------------------------------- */
2849   int right_x, last_x;
2850   char left_p, right_p;
2851   struct glyph *last_glyph;
2852   NSRect r;
2853   int thickness;
2854   struct face *face;
2856   if (s->hl == DRAW_MOUSE_FACE)
2857     {
2858       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2859       if (!face)
2860         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2861     }
2862   else
2863     face = s->face;
2865   thickness = face->box_line_width;
2867   NSTRACE (ns_dumpglyphs_box_or_relief);
2869   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2870             ? WINDOW_RIGHT_EDGE_X (s->w)
2871             : window_box_right (s->w, s->area));
2872   last_glyph = (s->cmp || s->img
2873                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2875   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2876               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2878   left_p = (s->first_glyph->left_box_line_p
2879             || (s->hl == DRAW_MOUSE_FACE
2880                 && (s->prev == NULL || s->prev->hl != s->hl)));
2881   right_p = (last_glyph->right_box_line_p
2882              || (s->hl == DRAW_MOUSE_FACE
2883                  && (s->next == NULL || s->next->hl != s->hl)));
2885   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2887   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2888   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2889     {
2890       ns_draw_box (r, abs (thickness),
2891                    ns_lookup_indexed_color (face->box_color, s->f),
2892                   left_p, right_p);
2893     }
2894   else
2895     {
2896       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2897                      1, 1, left_p, right_p, s);
2898     }
2902 static void
2903 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2904 /* --------------------------------------------------------------------------
2905       Modeled after x_draw_glyph_string_background, which draws BG in
2906       certain cases.  Others are left to the text rendering routine.
2907    -------------------------------------------------------------------------- */
2909   NSTRACE (ns_maybe_dumpglyphs_background);
2911   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2912     {
2913       int box_line_width = max (s->face->box_line_width, 0);
2914       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2915           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2916         {
2917           struct face *face;
2918           if (s->hl == DRAW_MOUSE_FACE)
2919             {
2920               face = FACE_FROM_ID (s->f,
2921                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2922               if (!face)
2923                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2924             }
2925           else
2926             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2927           if (!face->stipple)
2928             [(NS_FACE_BACKGROUND (face) != 0
2929               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2930               : FRAME_BACKGROUND_COLOR (s->f)) set];
2931           else
2932             {
2933               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2934               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2935             }
2937           if (s->hl != DRAW_CURSOR)
2938             {
2939               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2940                                     s->background_width,
2941                                     s->height-2*box_line_width);
2942               NSRectFill (r);
2943             }
2945           s->background_filled_p = 1;
2946         }
2947     }
2951 static void
2952 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2953 /* --------------------------------------------------------------------------
2954       Renders an image and associated borders.
2955    -------------------------------------------------------------------------- */
2957   EmacsImage *img = s->img->pixmap;
2958   int box_line_vwidth = max (s->face->box_line_width, 0);
2959   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2960   int bg_x, bg_y, bg_height;
2961   int th;
2962   char raised_p;
2963   NSRect br;
2964   struct face *face;
2965   NSColor *tdCol;
2967   NSTRACE (ns_dumpglyphs_image);
2969   if (s->face->box != FACE_NO_BOX
2970       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2971     x += abs (s->face->box_line_width);
2973   bg_x = x;
2974   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2975   bg_height = s->height;
2976   /* other terms have this, but was causing problems w/tabbar mode */
2977   /* - 2 * box_line_vwidth; */
2979   if (s->slice.x == 0) x += s->img->hmargin;
2980   if (s->slice.y == 0) y += s->img->vmargin;
2982   /* Draw BG: if we need larger area than image itself cleared, do that,
2983      otherwise, since we composite the image under NS (instead of mucking
2984      with its background color), we must clear just the image area. */
2985   if (s->hl == DRAW_MOUSE_FACE)
2986     {
2987       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2988       if (!face)
2989        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2990     }
2991   else
2992     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2994   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2996   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2997       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2998     {
2999       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3000       s->background_filled_p = 1;
3001     }
3002   else
3003     {
3004       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3005     }
3007   NSRectFill (br);
3009   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3010   if (img != nil)
3011     {
3012 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
3013       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3014       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3015                               s->slice.width, s->slice.height);
3016       [img drawInRect: dr
3017              fromRect: ir
3018              operation: NSCompositeSourceOver
3019               fraction: 1.0
3020            respectFlipped: YES
3021                 hints: nil];
3022 #else
3023       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3024                   operation: NSCompositeSourceOver];
3025 #endif
3026     }
3028   if (s->hl == DRAW_CURSOR)
3029     {
3030     [FRAME_CURSOR_COLOR (s->f) set];
3031     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3032       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3033     else
3034       /* Currently on NS img->mask is always 0. Since
3035          get_window_cursor_type specifies a hollow box cursor when on
3036          a non-masked image we never reach this clause. But we put it
3037          in in anticipation of better support for image masks on
3038          NS. */
3039       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3040     }
3041   else
3042     {
3043       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3044     }
3046   /* Draw underline, overline, strike-through. */
3047   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3049   /* Draw relief, if requested */
3050   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3051     {
3052       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3053         {
3054           th = tool_bar_button_relief >= 0 ?
3055             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3056           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3057         }
3058       else
3059         {
3060           th = abs (s->img->relief);
3061           raised_p = (s->img->relief > 0);
3062         }
3064       r.origin.x = x - th;
3065       r.origin.y = y - th;
3066       r.size.width = s->slice.width + 2*th-1;
3067       r.size.height = s->slice.height + 2*th-1;
3068       ns_draw_relief (r, th, raised_p,
3069                       s->slice.y == 0,
3070                       s->slice.y + s->slice.height == s->img->height,
3071                       s->slice.x == 0,
3072                       s->slice.x + s->slice.width == s->img->width, s);
3073     }
3075   /* If there is no mask, the background won't be seen,
3076      so draw a rectangle on the image for the cursor.
3077      Do this for all images, getting transparency right is not reliable.  */
3078   if (s->hl == DRAW_CURSOR)
3079     {
3080       int thickness = abs (s->img->relief);
3081       if (thickness == 0) thickness = 1;
3082       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3083     }
3087 static void
3088 ns_dumpglyphs_stretch (struct glyph_string *s)
3090   NSRect r[2];
3091   int n, i;
3092   struct face *face;
3093   NSColor *fgCol, *bgCol;
3095   if (!s->background_filled_p)
3096     {
3097       n = ns_get_glyph_string_clip_rect (s, r);
3098       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3100       ns_focus (s->f, r, n);
3102       if (s->hl == DRAW_MOUSE_FACE)
3103        {
3104          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3105          if (!face)
3106            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3107        }
3108       else
3109        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3111       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3112       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3114       for (i = 0; i < n; ++i)
3115         {
3116           if (!s->row->full_width_p)
3117             {
3118               int overrun, leftoverrun;
3120               /* truncate to avoid overwriting fringe and/or scrollbar */
3121               overrun = max (0, (s->x + s->background_width)
3122                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3123                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3124               r[i].size.width -= overrun;
3126               /* truncate to avoid overwriting to left of the window box */
3127               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3128                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3130               if (leftoverrun > 0)
3131                 {
3132                   r[i].origin.x += leftoverrun;
3133                   r[i].size.width -= leftoverrun;
3134                 }
3136               /* XXX: Try to work between problem where a stretch glyph on
3137                  a partially-visible bottom row will clear part of the
3138                  modeline, and another where list-buffers headers and similar
3139                  rows erroneously have visible_height set to 0.  Not sure
3140                  where this is coming from as other terms seem not to show. */
3141               r[i].size.height = min (s->height, s->row->visible_height);
3142             }
3144           [bgCol set];
3146           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3147              overwriting cursor (usually when cursor on a tab) */
3148           if (s->hl == DRAW_CURSOR)
3149             {
3150               CGFloat x, width;
3152               x = r[i].origin.x;
3153               width = s->w->phys_cursor_width;
3154               r[i].size.width -= width;
3155               r[i].origin.x += width;
3157               NSRectFill (r[i]);
3159               /* Draw overlining, etc. on the cursor. */
3160               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3161                 ns_draw_text_decoration (s, face, bgCol, width, x);
3162               else
3163                 ns_draw_text_decoration (s, face, fgCol, width, x);
3164             }
3165           else
3166             {
3167               NSRectFill (r[i]);
3168             }
3170           /* Draw overlining, etc. on the stretch glyph (or the part
3171              of the stretch glyph after the cursor). */
3172           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3173                                    r[i].origin.x);
3174         }
3175       ns_unfocus (s->f);
3176       s->background_filled_p = 1;
3177     }
3181 static void
3182 ns_draw_glyph_string (struct glyph_string *s)
3183 /* --------------------------------------------------------------------------
3184       External (RIF): Main draw-text call.
3185    -------------------------------------------------------------------------- */
3187   /* TODO (optimize): focus for box and contents draw */
3188   NSRect r[2];
3189   int n;
3190   char box_drawn_p = 0;
3192   NSTRACE (ns_draw_glyph_string);
3194   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3195     {
3196       int width;
3197       struct glyph_string *next;
3199       for (width = 0, next = s->next;
3200            next && width < s->right_overhang;
3201            width += next->width, next = next->next)
3202         if (next->first_glyph->type != IMAGE_GLYPH)
3203           {
3204             if (next->first_glyph->type != STRETCH_GLYPH)
3205               {
3206                 n = ns_get_glyph_string_clip_rect (s->next, r);
3207                 ns_focus (s->f, r, n);
3208                 ns_maybe_dumpglyphs_background (s->next, 1);
3209                 ns_unfocus (s->f);
3210               }
3211             else
3212               {
3213                 ns_dumpglyphs_stretch (s->next);
3214               }
3215             next->num_clips = 0;
3216           }
3217     }
3219   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3220         && (s->first_glyph->type == CHAR_GLYPH
3221             || s->first_glyph->type == COMPOSITE_GLYPH))
3222     {
3223       n = ns_get_glyph_string_clip_rect (s, r);
3224       ns_focus (s->f, r, n);
3225       ns_maybe_dumpglyphs_background (s, 1);
3226       ns_dumpglyphs_box_or_relief (s);
3227       ns_unfocus (s->f);
3228       box_drawn_p = 1;
3229     }
3231   switch (s->first_glyph->type)
3232     {
3234     case IMAGE_GLYPH:
3235       n = ns_get_glyph_string_clip_rect (s, r);
3236       ns_focus (s->f, r, n);
3237       ns_dumpglyphs_image (s, r[0]);
3238       ns_unfocus (s->f);
3239       break;
3241     case STRETCH_GLYPH:
3242       ns_dumpglyphs_stretch (s);
3243       break;
3245     case CHAR_GLYPH:
3246     case COMPOSITE_GLYPH:
3247       n = ns_get_glyph_string_clip_rect (s, r);
3248       ns_focus (s->f, r, n);
3250       if (s->for_overlaps || (s->cmp_from > 0
3251                               && ! s->first_glyph->u.cmp.automatic))
3252         s->background_filled_p = 1;
3253       else
3254         ns_maybe_dumpglyphs_background
3255           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3257       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3258                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3259                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3260                       NS_DUMPGLYPH_NORMAL));
3261       ns_tmp_font = (struct nsfont_info *)s->face->font;
3262       if (ns_tmp_font == NULL)
3263           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3265       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3266         {
3267           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3268           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3269           NS_FACE_FOREGROUND (s->face) = tmp;
3270         }
3272       ns_tmp_font->font.driver->draw
3273         (s, 0, s->nchars, s->x, s->y,
3274          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3275          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3277       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3278         {
3279           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3280           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3281           NS_FACE_FOREGROUND (s->face) = tmp;
3282         }
3284       ns_unfocus (s->f);
3285       break;
3287     case GLYPHLESS_GLYPH:
3288       n = ns_get_glyph_string_clip_rect (s, r);
3289       ns_focus (s->f, r, n);
3291       if (s->for_overlaps || (s->cmp_from > 0
3292                               && ! s->first_glyph->u.cmp.automatic))
3293         s->background_filled_p = 1;
3294       else
3295         ns_maybe_dumpglyphs_background
3296           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3297       /* ... */
3298       /* Not yet implemented.  */
3299       /* ... */
3300       ns_unfocus (s->f);
3301       break;
3303     default:
3304       emacs_abort ();
3305     }
3307   /* Draw box if not done already. */
3308   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3309     {
3310       n = ns_get_glyph_string_clip_rect (s, r);
3311       ns_focus (s->f, r, n);
3312       ns_dumpglyphs_box_or_relief (s);
3313       ns_unfocus (s->f);
3314     }
3316   s->num_clips = 0;
3321 /* ==========================================================================
3323     Event loop
3325    ========================================================================== */
3328 static void
3329 ns_send_appdefined (int value)
3330 /* --------------------------------------------------------------------------
3331     Internal: post an appdefined event which EmacsApp-sendEvent will
3332               recognize and take as a command to halt the event loop.
3333    -------------------------------------------------------------------------- */
3335   /*NSTRACE (ns_send_appdefined); */
3337   /* Only post this event if we haven't already posted one.  This will end
3338        the [NXApp run] main loop after having processed all events queued at
3339        this moment.  */
3340   if (send_appdefined)
3341     {
3342       NSEvent *nxev;
3344       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3345       send_appdefined = NO;
3347       /* Don't need wakeup timer any more */
3348       if (timed_entry)
3349         {
3350           [timed_entry invalidate];
3351           [timed_entry release];
3352           timed_entry = nil;
3353         }
3355       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3356                                 location: NSMakePoint (0, 0)
3357                            modifierFlags: 0
3358                                timestamp: 0
3359                             windowNumber: [[NSApp mainWindow] windowNumber]
3360                                  context: [NSApp context]
3361                                  subtype: 0
3362                                    data1: value
3363                                    data2: 0];
3365       /* Post an application defined event on the event queue.  When this is
3366          received the [NXApp run] will return, thus having processed all
3367          events which are currently queued.  */
3368       [NSApp postEvent: nxev atStart: NO];
3369     }
3372 static int
3373 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3374 /* --------------------------------------------------------------------------
3375      External (hook): Post an event to ourself and keep reading events until
3376      we read it back again.  In effect process all events which were waiting.
3377      From 21+ we have to manage the event buffer ourselves.
3378    -------------------------------------------------------------------------- */
3380   struct input_event ev;
3381   int nevents;
3383 /* NSTRACE (ns_read_socket); */
3385   if ([NSApp modalWindow] != nil)
3386     return -1;
3388   if (hold_event_q.nr > 0)
3389     {
3390       int i;
3391       for (i = 0; i < hold_event_q.nr; ++i)
3392         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3393       hold_event_q.nr = 0;
3394       return i;
3395     }
3397   block_input ();
3398   n_emacs_events_pending = 0;
3399   EVENT_INIT (ev);
3400   emacs_event = &ev;
3401   q_event_ptr = hold_quit;
3403   /* we manage autorelease pools by allocate/reallocate each time around
3404      the loop; strict nesting is occasionally violated but seems not to
3405      matter.. earlier methods using full nesting caused major memory leaks */
3406   [outerpool release];
3407   outerpool = [[NSAutoreleasePool alloc] init];
3409   /* If have pending open-file requests, attend to the next one of those. */
3410   if (ns_pending_files && [ns_pending_files count] != 0
3411       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3412     {
3413       [ns_pending_files removeObjectAtIndex: 0];
3414     }
3415   /* Deal with pending service requests. */
3416   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3417     && [(EmacsApp *)
3418          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3419                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3420     {
3421       [ns_pending_service_names removeObjectAtIndex: 0];
3422       [ns_pending_service_args removeObjectAtIndex: 0];
3423     }
3424   else
3425     {
3426       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3427          to ourself, otherwise [NXApp run] will never exit.  */
3428       send_appdefined = YES;
3429       ns_send_appdefined (-1);
3431       if (++apploopnr != 1)
3432         {
3433           emacs_abort ();
3434         }
3435       [NSApp run];
3436       --apploopnr;
3437     }
3439   nevents = n_emacs_events_pending;
3440   n_emacs_events_pending = 0;
3441   emacs_event = q_event_ptr = NULL;
3442   unblock_input ();
3444   return nevents;
3449 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3450            fd_set *exceptfds, EMACS_TIME *timeout, sigset_t *sigmask)
3451 /* --------------------------------------------------------------------------
3452      Replacement for select, checking for events
3453    -------------------------------------------------------------------------- */
3455   int result;
3456   int t, k, nr = 0;
3457   struct input_event event;
3458   char c;
3460 /*  NSTRACE (ns_select); */
3462   if (hold_event_q.nr > 0)
3463     {
3464       /* We already have events pending. */
3465       raise (SIGIO);
3466       errno = EINTR;
3467       return -1;
3468     }
3470   for (k = 0; k < nfds+1; k++)
3471     {
3472       if (readfds && FD_ISSET(k, readfds)) ++nr;
3473       if (writefds && FD_ISSET(k, writefds)) ++nr;
3474     }
3476   if (NSApp == nil
3477       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3478     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3480   [outerpool release];
3481   outerpool = [[NSAutoreleasePool alloc] init];
3484   send_appdefined = YES;
3485   if (nr > 0)
3486     {
3487       pthread_mutex_lock (&select_mutex);
3488       select_nfds = nfds;
3489       select_valid = 0;
3490       if (readfds)
3491         {
3492           select_readfds = *readfds;
3493           select_valid += SELECT_HAVE_READ;
3494         }
3495       if (writefds)
3496         {
3497           select_writefds = *writefds;
3498           select_valid += SELECT_HAVE_WRITE;
3499         }
3501       if (timeout)
3502         {
3503           select_timeout = *timeout;
3504           select_valid += SELECT_HAVE_TMO;
3505         }
3507       pthread_mutex_unlock (&select_mutex);
3509       /* Inform fd_handler that select should be called */
3510       c = 'g';
3511       emacs_write (selfds[1], &c, 1);
3512     }
3513   else if (nr == 0 && timeout)
3514     {
3515       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3516       double time = EMACS_TIME_TO_DOUBLE (*timeout);
3517       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3518                                                       target: NSApp
3519                                                     selector:
3520                                   @selector (timeout_handler:)
3521                                                     userInfo: 0
3522                                                      repeats: NO]
3523                       retain];
3524     }
3525   else /* No timeout and no file descriptors, can this happen?  */
3526     {
3527       /* Send appdefined so we exit from the loop */
3528       ns_send_appdefined (-1);
3529     }
3531   EVENT_INIT (event);
3532   block_input ();
3533   emacs_event = &event;
3534   if (++apploopnr != 1)
3535     {
3536       emacs_abort ();
3537     }
3538   [NSApp run];
3539   --apploopnr;
3540   emacs_event = NULL;
3541   if (nr > 0 && readfds)
3542     {
3543       c = 's';
3544       emacs_write (selfds[1], &c, 1);
3545     }
3546   unblock_input ();
3548   t = last_appdefined_event_data;
3550   if (t != NO_APPDEFINED_DATA)
3551     {
3552       last_appdefined_event_data = NO_APPDEFINED_DATA;
3554       if (t == -2)
3555         {
3556           /* The NX_APPDEFINED event we received was a timeout. */
3557           result = 0;
3558         }
3559       else if (t == -1)
3560         {
3561           /* The NX_APPDEFINED event we received was the result of
3562              at least one real input event arriving.  */
3563           errno = EINTR;
3564           result = -1;
3565         }
3566       else
3567         {
3568           /* Received back from select () in fd_handler; copy the results */
3569           pthread_mutex_lock (&select_mutex);
3570           if (readfds) *readfds = select_readfds;
3571           if (writefds) *writefds = select_writefds;
3572           if (timeout) *timeout = select_timeout;
3573           pthread_mutex_unlock (&select_mutex);
3574           result = t;
3575         }
3576     }
3578   return result;
3583 /* ==========================================================================
3585     Scrollbar handling
3587    ========================================================================== */
3590 static void
3591 ns_set_vertical_scroll_bar (struct window *window,
3592                            int portion, int whole, int position)
3593 /* --------------------------------------------------------------------------
3594       External (hook): Update or add scrollbar
3595    -------------------------------------------------------------------------- */
3597   Lisp_Object win;
3598   NSRect r, v;
3599   struct frame *f = XFRAME (WINDOW_FRAME (window));
3600   EmacsView *view = FRAME_NS_VIEW (f);
3601   int window_y, window_height;
3602   int top, left, height, width, sb_width, sb_left;
3603   EmacsScroller *bar;
3604   BOOL fringe_extended_p;
3606   /* optimization; display engine sends WAY too many of these.. */
3607   if (!NILP (window->vertical_scroll_bar))
3608     {
3609       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3610       if ([bar checkSamePosition: position portion: portion whole: whole])
3611         {
3612           if (view->scrollbarsNeedingUpdate == 0)
3613             {
3614               if (!windows_or_buffers_changed)
3615                   return;
3616             }
3617           else
3618             view->scrollbarsNeedingUpdate--;
3619         }
3620     }
3622   NSTRACE (ns_set_vertical_scroll_bar);
3624   /* Get dimensions.  */
3625   window_box (window, -1, 0, &window_y, 0, &window_height);
3626   top = window_y;
3627   height = window_height;
3628   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3629   left = WINDOW_SCROLL_BAR_AREA_X (window);
3631   /* allow for displaying a skinnier scrollbar than char area allotted */
3632   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3633     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3634   sb_left = left;
3636   r = NSMakeRect (sb_left, top, sb_width, height);
3637   /* the parent view is flipped, so we need to flip y value */
3638   v = [view frame];
3639   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3641   if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (window))
3642     fringe_extended_p = (WINDOW_LEFTMOST_P (window)
3643                          && WINDOW_LEFT_FRINGE_WIDTH (window)
3644                          && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (window)
3645                              || WINDOW_LEFT_MARGIN_COLS (window) == 0));
3646   else
3647     fringe_extended_p = (WINDOW_RIGHTMOST_P (window)
3648                          && WINDOW_RIGHT_FRINGE_WIDTH (window)
3649                          && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (window)
3650                              || WINDOW_RIGHT_MARGIN_COLS (window) == 0));
3652   XSETWINDOW (win, window);
3653   block_input ();
3655   /* we want at least 5 lines to display a scrollbar */
3656   if (WINDOW_TOTAL_LINES (window) < 5)
3657     {
3658       if (!NILP (window->vertical_scroll_bar))
3659         {
3660           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3661           [bar removeFromSuperview];
3662           wset_vertical_scroll_bar (window, Qnil);
3663         }
3664       ns_clear_frame_area (f, sb_left, top, width, height);
3665       unblock_input ();
3666       return;
3667     }
3669   if (NILP (window->vertical_scroll_bar))
3670     {
3671       if (width > 0 && height > 0)
3672         {
3673           if (fringe_extended_p)
3674             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3675           else
3676             ns_clear_frame_area (f, left, top, width, height);
3677         }
3679       bar = [[EmacsScroller alloc] initFrame: r window: win];
3680       wset_vertical_scroll_bar (window, make_save_pointer (bar));
3681     }
3682   else
3683     {
3684       NSRect oldRect;
3685       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3686       oldRect = [bar frame];
3687       r.size.width = oldRect.size.width;
3688       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3689         {
3690           if (oldRect.origin.x != r.origin.x)
3691               ns_clear_frame_area (f, sb_left, top, width, height);
3692           [bar setFrame: r];
3693         }
3694     }
3696   [bar setPosition: position portion: portion whole: whole];
3697   unblock_input ();
3701 static void
3702 ns_condemn_scroll_bars (struct frame *f)
3703 /* --------------------------------------------------------------------------
3704      External (hook): arrange for all frame's scrollbars to be removed
3705      at next call to judge_scroll_bars, except for those redeemed.
3706    -------------------------------------------------------------------------- */
3708   int i;
3709   id view;
3710   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3712   NSTRACE (ns_condemn_scroll_bars);
3714   for (i =[subviews count]-1; i >= 0; i--)
3715     {
3716       view = [subviews objectAtIndex: i];
3717       if ([view isKindOfClass: [EmacsScroller class]])
3718         [view condemn];
3719     }
3723 static void
3724 ns_redeem_scroll_bar (struct window *window)
3725 /* --------------------------------------------------------------------------
3726      External (hook): arrange to spare this window's scrollbar
3727      at next call to judge_scroll_bars.
3728    -------------------------------------------------------------------------- */
3730   id bar;
3731   NSTRACE (ns_redeem_scroll_bar);
3732   if (!NILP (window->vertical_scroll_bar))
3733     {
3734       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3735       [bar reprieve];
3736     }
3740 static void
3741 ns_judge_scroll_bars (struct frame *f)
3742 /* --------------------------------------------------------------------------
3743      External (hook): destroy all scrollbars on frame that weren't
3744      redeemed after call to condemn_scroll_bars.
3745    -------------------------------------------------------------------------- */
3747   int i;
3748   id view;
3749   EmacsView *eview = FRAME_NS_VIEW (f);
3750   NSArray *subviews = [[eview superview] subviews];
3751   BOOL removed = NO;
3753   NSTRACE (ns_judge_scroll_bars);
3754   for (i = [subviews count]-1; i >= 0; --i)
3755     {
3756       view = [subviews objectAtIndex: i];
3757       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3758       [view judge];
3759       removed = YES;
3760     }
3762   if (removed)
3763     [eview updateFrameSize: NO];
3767 void
3768 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3770   /* XXX irrelevant under NS */
3775 /* ==========================================================================
3777     Initialization
3779    ========================================================================== */
3782 x_display_pixel_height (struct ns_display_info *dpyinfo)
3784   NSScreen *screen = [NSScreen mainScreen];
3785   return [screen frame].size.height;
3789 x_display_pixel_width (struct ns_display_info *dpyinfo)
3791   NSScreen *screen = [NSScreen mainScreen];
3792   return [screen frame].size.width;
3796 static Lisp_Object ns_string_to_lispmod (const char *s)
3797 /* --------------------------------------------------------------------------
3798      Convert modifier name to lisp symbol
3799    -------------------------------------------------------------------------- */
3801   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3802     return Qmeta;
3803   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3804     return Qsuper;
3805   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3806     return Qcontrol;
3807   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3808     return Qalt;
3809   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3810     return Qhyper;
3811   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3812     return Qnone;
3813   else
3814     return Qnil;
3818 static void
3819 ns_default (const char *parameter, Lisp_Object *result,
3820            Lisp_Object yesval, Lisp_Object noval,
3821            BOOL is_float, BOOL is_modstring)
3822 /* --------------------------------------------------------------------------
3823       Check a parameter value in user's preferences
3824    -------------------------------------------------------------------------- */
3826   const char *value = ns_get_defaults_value (parameter);
3828   if (value)
3829     {
3830       double f;
3831       char *pos;
3832       if (c_strcasecmp (value, "YES") == 0)
3833         *result = yesval;
3834       else if (c_strcasecmp (value, "NO") == 0)
3835         *result = noval;
3836       else if (is_float && (f = strtod (value, &pos), pos != value))
3837         *result = make_float (f);
3838       else if (is_modstring && value)
3839         *result = ns_string_to_lispmod (value);
3840       else fprintf (stderr,
3841                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3842     }
3846 static void
3847 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3848 /* --------------------------------------------------------------------------
3849       Initialize global info and storage for display.
3850    -------------------------------------------------------------------------- */
3852     NSScreen *screen = [NSScreen mainScreen];
3853     NSWindowDepth depth = [screen depth];
3854     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3856     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3857     dpyinfo->resy = 72.27;
3858     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3859                                                   NSColorSpaceFromDepth (depth)]
3860                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3861                                                  NSColorSpaceFromDepth (depth)];
3862     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3863     dpyinfo->image_cache = make_image_cache ();
3864     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
3865     dpyinfo->color_table->colors = NULL;
3866     dpyinfo->root_window = 42; /* a placeholder.. */
3868     hlinfo->mouse_face_mouse_frame = NULL;
3869     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3870     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3871     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3872     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3873     hlinfo->mouse_face_hidden = 0;
3875     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3876     hlinfo->mouse_face_defer = 0;
3878     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3880     dpyinfo->n_fonts = 0;
3881     dpyinfo->smallest_font_height = 1;
3882     dpyinfo->smallest_char_width = 1;
3886 /* This and next define (many of the) public functions in this file. */
3887 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3888          with using despite presence in the "system dependent" redisplay
3889          interface.  In addition, many of the ns_ methods have code that is
3890          shared with all terms, indicating need for further refactoring. */
3891 extern frame_parm_handler ns_frame_parm_handlers[];
3892 static struct redisplay_interface ns_redisplay_interface =
3894   ns_frame_parm_handlers,
3895   x_produce_glyphs,
3896   x_write_glyphs,
3897   x_insert_glyphs,
3898   x_clear_end_of_line,
3899   ns_scroll_run,
3900   ns_after_update_window_line,
3901   ns_update_window_begin,
3902   ns_update_window_end,
3903   x_cursor_to,
3904   ns_flush,
3905   0, /* flush_display_optional */
3906   x_clear_window_mouse_face,
3907   x_get_glyph_overhangs,
3908   x_fix_overlapping_area,
3909   ns_draw_fringe_bitmap,
3910   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3911   0, /* destroy_fringe_bitmap */
3912   ns_compute_glyph_string_overhangs,
3913   ns_draw_glyph_string, /* interface to nsfont.m */
3914   ns_define_frame_cursor,
3915   ns_clear_frame_area,
3916   ns_draw_window_cursor,
3917   ns_draw_vertical_window_border,
3918   ns_shift_glyphs_for_insert
3922 static void
3923 ns_delete_display (struct ns_display_info *dpyinfo)
3925   /* TODO... */
3929 /* This function is called when the last frame on a display is deleted. */
3930 static void
3931 ns_delete_terminal (struct terminal *terminal)
3933   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3935   /* Protect against recursive calls.  delete_frame in
3936      delete_terminal calls us back when it deletes our last frame.  */
3937   if (!terminal->name)
3938     return;
3940   block_input ();
3942   x_destroy_all_bitmaps (dpyinfo);
3943   ns_delete_display (dpyinfo);
3944   unblock_input ();
3948 static struct terminal *
3949 ns_create_terminal (struct ns_display_info *dpyinfo)
3950 /* --------------------------------------------------------------------------
3951       Set up use of NS before we make the first connection.
3952    -------------------------------------------------------------------------- */
3954   struct terminal *terminal;
3956   NSTRACE (ns_create_terminal);
3958   terminal = create_terminal ();
3960   terminal->type = output_ns;
3961   terminal->display_info.ns = dpyinfo;
3962   dpyinfo->terminal = terminal;
3964   terminal->rif = &ns_redisplay_interface;
3966   terminal->clear_frame_hook = ns_clear_frame;
3967   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3968   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3969   terminal->ring_bell_hook = ns_ring_bell;
3970   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3971   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3972   terminal->update_begin_hook = ns_update_begin;
3973   terminal->update_end_hook = ns_update_end;
3974   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
3975   terminal->read_socket_hook = ns_read_socket;
3976   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3977   terminal->mouse_position_hook = ns_mouse_position;
3978   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3979   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3981   terminal->fullscreen_hook = ns_fullscreen_hook;
3983   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3984   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3985   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3986   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3988   terminal->delete_frame_hook = x_destroy_window;
3989   terminal->delete_terminal_hook = ns_delete_terminal;
3991   terminal->scroll_region_ok = 1;
3992   terminal->char_ins_del_ok = 1;
3993   terminal->line_ins_del_ok = 1;
3994   terminal->fast_clear_end_of_line = 1;
3995   terminal->memory_below_frame = 0;
3997   return terminal;
4001 struct ns_display_info *
4002 ns_term_init (Lisp_Object display_name)
4003 /* --------------------------------------------------------------------------
4004      Start the Application and get things rolling.
4005    -------------------------------------------------------------------------- */
4007   struct terminal *terminal;
4008   struct ns_display_info *dpyinfo;
4009   static int ns_initialized = 0;
4010   Lisp_Object tmp;
4012   if (ns_initialized) return x_display_list;
4013   ns_initialized = 1;
4015   NSTRACE (ns_term_init);
4017   [outerpool release];
4018   outerpool = [[NSAutoreleasePool alloc] init];
4020   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4021   /*GSDebugAllocationActive (YES); */
4022   block_input ();
4024   baud_rate = 38400;
4025   Fset_input_interrupt_mode (Qnil);
4027   if (selfds[0] == -1)
4028     {
4029       if (pipe (selfds) == -1)
4030         {
4031           fprintf (stderr, "Failed to create pipe: %s\n",
4032                    emacs_strerror (errno));
4033           emacs_abort ();
4034         }
4036       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4037       FD_ZERO (&select_readfds);
4038       FD_ZERO (&select_writefds);
4039       pthread_mutex_init (&select_mutex, NULL);
4040     }
4042   ns_pending_files = [[NSMutableArray alloc] init];
4043   ns_pending_service_names = [[NSMutableArray alloc] init];
4044   ns_pending_service_args = [[NSMutableArray alloc] init];
4046 /* Start app and create the main menu, window, view.
4047      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4048      The view will then ask the NSApp to stop and return to Emacs. */
4049   [EmacsApp sharedApplication];
4050   if (NSApp == nil)
4051     return NULL;
4052   [NSApp setDelegate: NSApp];
4054   /* Start the select thread.  */
4055   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4056                            toTarget:NSApp
4057                          withObject:nil];
4059   /* debugging: log all notifications */
4060   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4061                                          selector: @selector (logNotification:)
4062                                              name: nil object: nil]; */
4064   dpyinfo = xzalloc (sizeof *dpyinfo);
4066   ns_initialize_display_info (dpyinfo);
4067   terminal = ns_create_terminal (dpyinfo);
4069   terminal->kboard = xmalloc (sizeof *terminal->kboard);
4070   init_kboard (terminal->kboard);
4071   kset_window_system (terminal->kboard, Qns);
4072   terminal->kboard->next_kboard = all_kboards;
4073   all_kboards = terminal->kboard;
4074   /* Don't let the initial kboard remain current longer than necessary.
4075      That would cause problems if a file loaded on startup tries to
4076      prompt in the mini-buffer.  */
4077   if (current_kboard == initial_kboard)
4078     current_kboard = terminal->kboard;
4079   terminal->kboard->reference_count++;
4081   dpyinfo->next = x_display_list;
4082   x_display_list = dpyinfo;
4084   /* Put it on ns_display_name_list */
4085   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4086                                 ns_display_name_list);
4087   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4089   terminal->name = xstrdup (SSDATA (display_name));
4091   unblock_input ();
4093   if (!inhibit_x_resources)
4094     {
4095       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4096                  Qt, Qnil, NO, NO);
4097       tmp = Qnil;
4098       /* this is a standard variable */
4099       ns_default ("AppleAntiAliasingThreshold", &tmp,
4100                  make_float (10.0), make_float (6.0), YES, NO);
4101       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4102     }
4104   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4105                          stringForKey: @"AppleHighlightColor"];
4106   if (ns_selection_color == nil)
4107     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4109   {
4110     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4112     if ( cl == nil )
4113       {
4114         Lisp_Object color_file, color_map, color;
4115         unsigned long c;
4116         char *name;
4118         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4119                          Fsymbol_value (intern ("data-directory")));
4121         color_map = Fx_load_color_file (color_file);
4122         if (NILP (color_map))
4123           fatal ("Could not read %s.\n", SDATA (color_file));
4125         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4126         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4127           {
4128             color = XCAR (color_map);
4129             name = SSDATA (XCAR (color));
4130             c = XINT (XCDR (color));
4131             [cl setColor:
4132                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4133                                             green: GREEN_FROM_ULONG (c) / 255.0
4134                                              blue: BLUE_FROM_ULONG (c) / 255.0
4135                                             alpha: 1.0]
4136                   forKey: [NSString stringWithUTF8String: name]];
4137           }
4138         [cl writeToFile: nil];
4139       }
4140   }
4142   {
4143 #ifdef NS_IMPL_GNUSTEP
4144     Vwindow_system_version = build_string (gnustep_base_version);
4145 #else
4146     /*PSnextrelease (128, c); */
4147     char c[DBL_BUFSIZE_BOUND];
4148     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4149     Vwindow_system_version = make_unibyte_string (c, len);
4150 #endif
4151   }
4153   delete_keyboard_wait_descriptor (0);
4155   ns_app_name = [[NSProcessInfo processInfo] processName];
4157 /* Set up OS X app menu */
4158 #ifdef NS_IMPL_COCOA
4159   {
4160     NSMenu *appMenu;
4161     NSMenuItem *item;
4162     /* set up the application menu */
4163     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4164     [svcsMenu setAutoenablesItems: NO];
4165     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4166     [appMenu setAutoenablesItems: NO];
4167     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4168     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4170     [appMenu insertItemWithTitle: @"About Emacs"
4171                           action: @selector (orderFrontStandardAboutPanel:)
4172                    keyEquivalent: @""
4173                          atIndex: 0];
4174     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4175     [appMenu insertItemWithTitle: @"Preferences..."
4176                           action: @selector (showPreferencesWindow:)
4177                    keyEquivalent: @","
4178                          atIndex: 2];
4179     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4180     item = [appMenu insertItemWithTitle: @"Services"
4181                                  action: @selector (menuDown:)
4182                           keyEquivalent: @""
4183                                 atIndex: 4];
4184     [appMenu setSubmenu: svcsMenu forItem: item];
4185     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4186     [appMenu insertItemWithTitle: @"Hide Emacs"
4187                           action: @selector (hide:)
4188                    keyEquivalent: @"h"
4189                          atIndex: 6];
4190     item =  [appMenu insertItemWithTitle: @"Hide Others"
4191                           action: @selector (hideOtherApplications:)
4192                    keyEquivalent: @"h"
4193                          atIndex: 7];
4194     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4195     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4196     [appMenu insertItemWithTitle: @"Quit Emacs"
4197                           action: @selector (terminate:)
4198                    keyEquivalent: @"q"
4199                          atIndex: 9];
4201     item = [mainMenu insertItemWithTitle: ns_app_name
4202                                   action: @selector (menuDown:)
4203                            keyEquivalent: @""
4204                                  atIndex: 0];
4205     [mainMenu setSubmenu: appMenu forItem: item];
4206     [dockMenu insertItemWithTitle: @"New Frame"
4207                            action: @selector (newFrame:)
4208                     keyEquivalent: @""
4209                           atIndex: 0];
4211     [NSApp setMainMenu: mainMenu];
4212     [NSApp setAppleMenu: appMenu];
4213     [NSApp setServicesMenu: svcsMenu];
4214     /* Needed at least on Cocoa, to get dock menu to show windows */
4215     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4217     [[NSNotificationCenter defaultCenter]
4218       addObserver: mainMenu
4219          selector: @selector (trackingNotification:)
4220              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4221     [[NSNotificationCenter defaultCenter]
4222       addObserver: mainMenu
4223          selector: @selector (trackingNotification:)
4224              name: NSMenuDidEndTrackingNotification object: mainMenu];
4225   }
4226 #endif /* MAC OS X menu setup */
4228   /* Register our external input/output types, used for determining
4229      applicable services and also drag/drop eligibility. */
4230   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4231   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4232                       retain];
4233   ns_drag_types = [[NSArray arrayWithObjects:
4234                             NSStringPboardType,
4235                             NSTabularTextPboardType,
4236                             NSFilenamesPboardType,
4237                             NSURLPboardType,
4238                             NSColorPboardType,
4239                             NSFontPboardType, nil] retain];
4241 #ifndef NEW_STYLE_FS
4242   /* If fullscreen is in init/default-frame-alist, focus isn't set
4243      right for fullscreen windows, so set this.  */
4244   [NSApp activateIgnoringOtherApps:YES];
4245 #endif
4247   [NSApp run];
4248   ns_do_open_file = YES;
4249   return dpyinfo;
4253 void
4254 ns_term_shutdown (int sig)
4256   [[NSUserDefaults standardUserDefaults] synchronize];
4258   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4259   if (STRINGP (Vauto_save_list_file_name))
4260     unlink (SSDATA (Vauto_save_list_file_name));
4262   if (sig == 0 || sig == SIGTERM)
4263     {
4264       [NSApp terminate: NSApp];
4265     }
4266   else // force a stack trace to happen
4267     {
4268       emacs_abort ();
4269     }
4273 /* ==========================================================================
4275     EmacsApp implementation
4277    ========================================================================== */
4280 @implementation EmacsApp
4282 - (void)logNotification: (NSNotification *)notification
4284   const char *name = [[notification name] UTF8String];
4285   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4286       && !strstr (name, "WindowNumber"))
4287     NSLog (@"notification: '%@'", [notification name]);
4291 - (void)sendEvent: (NSEvent *)theEvent
4292 /* --------------------------------------------------------------------------
4293      Called when NSApp is running for each event received.  Used to stop
4294      the loop when we choose, since there's no way to just run one iteration.
4295    -------------------------------------------------------------------------- */
4297   int type = [theEvent type];
4298   NSWindow *window = [theEvent window];
4299 /*  NSTRACE (sendEvent); */
4300 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4302 #ifdef NS_IMPL_COCOA
4303   if (type == NSApplicationDefined
4304       && [theEvent data2] == NSAPP_DATA2_RUNASSCRIPT)
4305     {
4306       ns_run_ascript ();
4307       [self stop: self];
4308       return;
4309     }
4310 #endif
4312   if (type == NSCursorUpdate && window == nil)
4313     {
4314       fprintf (stderr, "Dropping external cursor update event.\n");
4315       return;
4316     }
4318   if (type == NSApplicationDefined)
4319     {
4320       /* Events posted by ns_send_appdefined interrupt the run loop here.
4321          But, if a modal window is up, an appdefined can still come through,
4322          (e.g., from a makeKeyWindow event) but stopping self also stops the
4323          modal loop. Just defer it until later. */
4324       if ([NSApp modalWindow] == nil)
4325         {
4326           last_appdefined_event_data = [theEvent data1];
4327           [self stop: self];
4328         }
4329       else
4330         {
4331           send_appdefined = YES;
4332         }
4333     }
4335   [super sendEvent: theEvent];
4339 - (void)showPreferencesWindow: (id)sender
4341   struct frame *emacsframe = SELECTED_FRAME ();
4342   NSEvent *theEvent = [NSApp currentEvent];
4344   if (!emacs_event)
4345     return;
4346   emacs_event->kind = NS_NONKEY_EVENT;
4347   emacs_event->code = KEY_NS_SHOW_PREFS;
4348   emacs_event->modifiers = 0;
4349   EV_TRAILER (theEvent);
4353 - (void)newFrame: (id)sender
4355   struct frame *emacsframe = SELECTED_FRAME ();
4356   NSEvent *theEvent = [NSApp currentEvent];
4358   if (!emacs_event)
4359     return;
4360   emacs_event->kind = NS_NONKEY_EVENT;
4361   emacs_event->code = KEY_NS_NEW_FRAME;
4362   emacs_event->modifiers = 0;
4363   EV_TRAILER (theEvent);
4367 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4368 - (BOOL) openFile: (NSString *)fileName
4370   struct frame *emacsframe = SELECTED_FRAME ();
4371   NSEvent *theEvent = [NSApp currentEvent];
4373   if (!emacs_event)
4374     return NO;
4376   emacs_event->kind = NS_NONKEY_EVENT;
4377   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4378   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4379   ns_input_line = Qnil; /* can be start or cons start,end */
4380   emacs_event->modifiers =0;
4381   EV_TRAILER (theEvent);
4383   return YES;
4387 /* **************************************************************************
4389       EmacsApp delegate implementation
4391    ************************************************************************** */
4393 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4394 /* --------------------------------------------------------------------------
4395      When application is loaded, terminate event loop in ns_term_init
4396    -------------------------------------------------------------------------- */
4398   NSTRACE (applicationDidFinishLaunching);
4399   [NSApp setServicesProvider: NSApp];
4400   ns_send_appdefined (-2);
4404 /* Termination sequences:
4405     C-x C-c:
4406     Cmd-Q:
4407     MenuBar | File | Exit:
4408     Select Quit from App menubar:
4409         -terminate
4410         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4411         ns_term_shutdown()
4413     Select Quit from Dock menu:
4414     Logout attempt:
4415         -appShouldTerminate
4416           Cancel -> Nothing else
4417           Accept ->
4419           -terminate
4420           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4421           ns_term_shutdown()
4425 - (void) terminate: (id)sender
4427   struct frame *emacsframe = SELECTED_FRAME ();
4429   if (!emacs_event)
4430     return;
4432   emacs_event->kind = NS_NONKEY_EVENT;
4433   emacs_event->code = KEY_NS_POWER_OFF;
4434   emacs_event->arg = Qt; /* mark as non-key event */
4435   EV_TRAILER ((id)nil);
4439 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4441   int ret;
4443   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4444     return NSTerminateNow;
4446     ret = NSRunAlertPanel(ns_app_name,
4447                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4448                           @"Save Buffers and Exit", @"Cancel", nil);
4450     if (ret == NSAlertDefaultReturn)
4451         return NSTerminateNow;
4452     else if (ret == NSAlertAlternateReturn)
4453         return NSTerminateCancel;
4454     return NSTerminateNow;  /* just in case */
4457 static int
4458 not_in_argv (NSString *arg)
4460   int k;
4461   const char *a = [arg UTF8String];
4462   for (k = 1; k < initial_argc; ++k)
4463     if (strcmp (a, initial_argv[k]) == 0) return 0;
4464   return 1;
4467 /*   Notification from the Workspace to open a file */
4468 - (BOOL)application: sender openFile: (NSString *)file
4470   if (ns_do_open_file || not_in_argv (file))
4471     [ns_pending_files addObject: file];
4472   return YES;
4476 /*   Open a file as a temporary file */
4477 - (BOOL)application: sender openTempFile: (NSString *)file
4479   if (ns_do_open_file || not_in_argv (file))
4480     [ns_pending_files addObject: file];
4481   return YES;
4485 /*   Notification from the Workspace to open a file noninteractively (?) */
4486 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4488   if (ns_do_open_file || not_in_argv (file))
4489     [ns_pending_files addObject: file];
4490   return YES;
4493 /*   Notification from the Workspace to open multiple files */
4494 - (void)application: sender openFiles: (NSArray *)fileList
4496   NSEnumerator *files = [fileList objectEnumerator];
4497   NSString *file;
4498   /* Don't open files from the command line unconditionally,
4499      Cocoa parses the command line wrong, --option value tries to open value
4500      if --option is the last option.  */
4501   while ((file = [files nextObject]) != nil)
4502     if (ns_do_open_file || not_in_argv (file))
4503       [ns_pending_files addObject: file];
4505   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4510 /* Handle dock menu requests.  */
4511 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4513   return dockMenu;
4517 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4518 - (void)applicationWillBecomeActive: (NSNotification *)notification
4520   //ns_app_active=YES;
4522 - (void)applicationDidBecomeActive: (NSNotification *)notification
4524   NSTRACE (applicationDidBecomeActive);
4526   //ns_app_active=YES;
4528   ns_update_auto_hide_menu_bar ();
4529   // No constraining takes place when the application is not active.
4530   ns_constrain_all_frames ();
4532 - (void)applicationDidResignActive: (NSNotification *)notification
4534   //ns_app_active=NO;
4535   ns_send_appdefined (-1);
4540 /* ==========================================================================
4542     EmacsApp aux handlers for managing event loop
4544    ========================================================================== */
4547 - (void)timeout_handler: (NSTimer *)timedEntry
4548 /* --------------------------------------------------------------------------
4549      The timeout specified to ns_select has passed.
4550    -------------------------------------------------------------------------- */
4552   /*NSTRACE (timeout_handler); */
4553   ns_send_appdefined (-2);
4556 - (void)fd_handler:(id)unused
4557 /* --------------------------------------------------------------------------
4558      Check data waiting on file descriptors and terminate if so
4559    -------------------------------------------------------------------------- */
4561   int result;
4562   int waiting = 1, nfds;
4563   char c;
4565   SELECT_TYPE readfds, writefds, *wfds;
4566   EMACS_TIME timeout, *tmo;
4567   NSAutoreleasePool *pool = nil;
4569   /* NSTRACE (fd_handler); */
4571   for (;;)
4572     {
4573       [pool release];
4574       pool = [[NSAutoreleasePool alloc] init];
4576       if (waiting)
4577         {
4578           SELECT_TYPE fds;
4579           FD_ZERO (&fds);
4580           FD_SET (selfds[0], &fds);
4581           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4582           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4583             waiting = 0;
4584         }
4585       else
4586         {
4587           pthread_mutex_lock (&select_mutex);
4588           nfds = select_nfds;
4590           if (select_valid & SELECT_HAVE_READ)
4591             readfds = select_readfds;
4592           else
4593             FD_ZERO (&readfds);
4595           if (select_valid & SELECT_HAVE_WRITE)
4596             {
4597               writefds = select_writefds;
4598               wfds = &writefds;
4599             }
4600           else
4601             wfds = NULL;
4602           if (select_valid & SELECT_HAVE_TMO)
4603             {
4604               timeout = select_timeout;
4605               tmo = &timeout;
4606             }
4607           else
4608             tmo = NULL;
4610           pthread_mutex_unlock (&select_mutex);
4612           FD_SET (selfds[0], &readfds);
4613           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4615           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4617           if (result == 0)
4618             ns_send_appdefined (-2);
4619           else if (result > 0)
4620             {
4621               if (FD_ISSET (selfds[0], &readfds))
4622                 {
4623                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4624                     waiting = 1;
4625                 }
4626               else
4627                 {
4628                   pthread_mutex_lock (&select_mutex);
4629                   if (select_valid & SELECT_HAVE_READ)
4630                     select_readfds = readfds;
4631                   if (select_valid & SELECT_HAVE_WRITE)
4632                     select_writefds = writefds;
4633                   if (select_valid & SELECT_HAVE_TMO)
4634                     select_timeout = timeout;
4635                   pthread_mutex_unlock (&select_mutex);
4637                   ns_send_appdefined (result);
4638                 }
4639             }
4640           waiting = 1;
4641         }
4642     }
4647 /* ==========================================================================
4649     Service provision
4651    ========================================================================== */
4653 /* called from system: queue for next pass through event loop */
4654 - (void)requestService: (NSPasteboard *)pboard
4655               userData: (NSString *)userData
4656                  error: (NSString **)error
4658   [ns_pending_service_names addObject: userData];
4659   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4660       SSDATA (ns_string_from_pasteboard (pboard))]];
4664 /* called from ns_read_socket to clear queue */
4665 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4667   struct frame *emacsframe = SELECTED_FRAME ();
4668   NSEvent *theEvent = [NSApp currentEvent];
4670   if (!emacs_event)
4671     return NO;
4673   emacs_event->kind = NS_NONKEY_EVENT;
4674   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4675   ns_input_spi_name = build_string ([name UTF8String]);
4676   ns_input_spi_arg = build_string ([arg UTF8String]);
4677   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4678   EV_TRAILER (theEvent);
4680   return YES;
4684 @end  /* EmacsApp */
4688 /* ==========================================================================
4690     EmacsView implementation
4692    ========================================================================== */
4695 @implementation EmacsView
4697 /* needed to inform when window closed from LISP */
4698 - (void) setWindowClosing: (BOOL)closing
4700   windowClosing = closing;
4704 - (void)dealloc
4706   NSTRACE (EmacsView_dealloc);
4707   [toolbar release];
4708   if (fs_state == FULLSCREEN_BOTH)
4709     [nonfs_window release];
4710   [super dealloc];
4714 /* called on font panel selection */
4715 - (void)changeFont: (id)sender
4717   NSEvent *e =[[self window] currentEvent];
4718   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4719   id newFont;
4720   float size;
4722   NSTRACE (changeFont);
4723   if (!emacs_event)
4724     return;
4726   if ((newFont = [sender convertFont:
4727                            ((struct nsfont_info *)face->font)->nsfont]))
4728     {
4729       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4731       emacs_event->kind = NS_NONKEY_EVENT;
4732       emacs_event->modifiers = 0;
4733       emacs_event->code = KEY_NS_CHANGE_FONT;
4735       size = [newFont pointSize];
4736       ns_input_fontsize = make_number (lrint (size));
4737       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4738       EV_TRAILER (e);
4739     }
4743 - (BOOL)acceptsFirstResponder
4745   NSTRACE (acceptsFirstResponder);
4746   return YES;
4750 - (void)resetCursorRects
4752   NSRect visible = [self visibleRect];
4753   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4754   NSTRACE (resetCursorRects);
4756   if (currentCursor == nil)
4757     currentCursor = [NSCursor arrowCursor];
4759   if (!NSIsEmptyRect (visible))
4760     [self addCursorRect: visible cursor: currentCursor];
4761   [currentCursor setOnMouseEntered: YES];
4766 /*****************************************************************************/
4767 /* Keyboard handling. */
4768 #define NS_KEYLOG 0
4770 - (void)keyDown: (NSEvent *)theEvent
4772   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4773   int code;
4774   unsigned fnKeysym = 0;
4775   static NSMutableArray *nsEvArray;
4776 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4777   static BOOL firstTime = YES;
4778 #endif
4779   int left_is_none;
4780   unsigned int flags = [theEvent modifierFlags];
4782   NSTRACE (keyDown);
4784   /* Rhapsody and OS X give up and down events for the arrow keys */
4785   if (ns_fake_keydown == YES)
4786     ns_fake_keydown = NO;
4787   else if ([theEvent type] != NSKeyDown)
4788     return;
4790   if (!emacs_event)
4791     return;
4793  if (![[self window] isKeyWindow]
4794      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4795      /* we must avoid an infinite loop here. */
4796      && (EmacsView *)[[theEvent window] delegate] != self)
4797    {
4798      /* XXX: There is an occasional condition in which, when Emacs display
4799          updates a different frame from the current one, and temporarily
4800          selects it, then processes some interrupt-driven input
4801          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4802          for some reason that window has its first responder set to the NSView
4803          most recently updated (I guess), which is not the correct one. */
4804      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4805      return;
4806    }
4808   if (nsEvArray == nil)
4809     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4811   [NSCursor setHiddenUntilMouseMoves: YES];
4813   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4814     {
4815       clear_mouse_face (hlinfo);
4816       hlinfo->mouse_face_hidden = 1;
4817     }
4819   if (!processingCompose)
4820     {
4821       /* When using screen sharing, no left or right information is sent,
4822          so use Left key in those cases.  */
4823       int is_left_key, is_right_key;
4825       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4826         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4828       /* (Carbon way: [theEvent keyCode]) */
4830       /* is it a "function key"? */
4831       fnKeysym = (code < 0x00ff && (flags&NSNumericPadKeyMask))
4832         ? ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask)
4833         : ns_convert_key (code);
4835       if (fnKeysym)
4836         {
4837           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4838              because Emacs treats Delete and KP-Delete same (in simple.el). */
4839           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4840             code = 0xFF08; /* backspace */
4841           else
4842             code = fnKeysym;
4843         }
4845       /* are there modifiers? */
4846       emacs_event->modifiers = 0;
4848       if (flags & NSHelpKeyMask)
4849           emacs_event->modifiers |= hyper_modifier;
4851       if (flags & NSShiftKeyMask)
4852         emacs_event->modifiers |= shift_modifier;
4854       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
4855       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
4856         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
4858       if (is_right_key)
4859         emacs_event->modifiers |= parse_solitary_modifier
4860           (EQ (ns_right_command_modifier, Qleft)
4861            ? ns_command_modifier
4862            : ns_right_command_modifier);
4864       if (is_left_key)
4865         {
4866           emacs_event->modifiers |= parse_solitary_modifier
4867             (ns_command_modifier);
4869           /* if super (default), take input manager's word so things like
4870              dvorak / qwerty layout work */
4871           if (EQ (ns_command_modifier, Qsuper)
4872               && !fnKeysym
4873               && [[theEvent characters] length] != 0)
4874             {
4875               /* XXX: the code we get will be unshifted, so if we have
4876                  a shift modifier, must convert ourselves */
4877               if (!(flags & NSShiftKeyMask))
4878                 code = [[theEvent characters] characterAtIndex: 0];
4879 #if 0
4880               /* this is ugly and also requires linking w/Carbon framework
4881                  (for LMGetKbdType) so for now leave this rare (?) case
4882                  undealt with.. in future look into CGEvent methods */
4883               else
4884                 {
4885                   long smv = GetScriptManagerVariable (smKeyScript);
4886                   Handle uchrHandle = GetResource
4887                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4888                   UInt32 dummy = 0;
4889                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4890                                  [[theEvent characters] characterAtIndex: 0],
4891                                  kUCKeyActionDisplay,
4892                                  (flags & ~NSCommandKeyMask) >> 8,
4893                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4894                                  &dummy, 1, &dummy, &code);
4895                   code &= 0xFF;
4896                 }
4897 #endif
4898             }
4899         }
4901       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
4902       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
4903         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
4905       if (is_right_key)
4906           emacs_event->modifiers |= parse_solitary_modifier
4907               (EQ (ns_right_control_modifier, Qleft)
4908                ? ns_control_modifier
4909                : ns_right_control_modifier);
4911       if (is_left_key)
4912         emacs_event->modifiers |= parse_solitary_modifier
4913           (ns_control_modifier);
4915       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4916           emacs_event->modifiers |=
4917             parse_solitary_modifier (ns_function_modifier);
4919       left_is_none = NILP (ns_alternate_modifier)
4920         || EQ (ns_alternate_modifier, Qnone);
4922       is_right_key = (flags & NSRightAlternateKeyMask)
4923         == NSRightAlternateKeyMask;
4924       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
4925         || (! is_right_key
4926             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
4928       if (is_right_key)
4929         {
4930           if ((NILP (ns_right_alternate_modifier)
4931                || EQ (ns_right_alternate_modifier, Qnone)
4932                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4933               && !fnKeysym)
4934             {   /* accept pre-interp alt comb */
4935               if ([[theEvent characters] length] > 0)
4936                 code = [[theEvent characters] characterAtIndex: 0];
4937               /*HACK: clear lone shift modifier to stop next if from firing */
4938               if (emacs_event->modifiers == shift_modifier)
4939                 emacs_event->modifiers = 0;
4940             }
4941           else
4942             emacs_event->modifiers |= parse_solitary_modifier
4943               (EQ (ns_right_alternate_modifier, Qleft)
4944                ? ns_alternate_modifier
4945                : ns_right_alternate_modifier);
4946         }
4948       if (is_left_key) /* default = meta */
4949         {
4950           if (left_is_none && !fnKeysym)
4951             {   /* accept pre-interp alt comb */
4952               if ([[theEvent characters] length] > 0)
4953                 code = [[theEvent characters] characterAtIndex: 0];
4954               /*HACK: clear lone shift modifier to stop next if from firing */
4955               if (emacs_event->modifiers == shift_modifier)
4956                 emacs_event->modifiers = 0;
4957             }
4958           else
4959               emacs_event->modifiers |=
4960                 parse_solitary_modifier (ns_alternate_modifier);
4961         }
4963   if (NS_KEYLOG)
4964     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4965              code, fnKeysym, flags, emacs_event->modifiers);
4967       /* if it was a function key or had modifiers, pass it directly to emacs */
4968       if (fnKeysym || (emacs_event->modifiers
4969                        && (emacs_event->modifiers != shift_modifier)
4970                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4971 /*[[theEvent characters] length] */
4972         {
4973           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4974           if (code < 0x20)
4975             code |= (1<<28)|(3<<16);
4976           else if (code == 0x7f)
4977             code |= (1<<28)|(3<<16);
4978           else if (!fnKeysym)
4979             emacs_event->kind = code > 0xFF
4980               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4982           emacs_event->code = code;
4983           EV_TRAILER (theEvent);
4984           processingCompose = NO;
4985           return;
4986         }
4987     }
4990 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4991   /* if we get here we should send the key for input manager processing */
4992   if (firstTime && [[NSInputManager currentInputManager]
4993                      wantsToDelayTextChangeNotifications] == NO)
4994     fprintf (stderr,
4995           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4996   firstTime = NO;
4997 #endif
4998   if (NS_KEYLOG && !processingCompose)
4999     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5001   processingCompose = YES;
5002   [nsEvArray addObject: theEvent];
5003   [self interpretKeyEvents: nsEvArray];
5004   [nsEvArray removeObject: theEvent];
5008 #ifdef NS_IMPL_COCOA
5009 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5010    decided not to send key-down for.
5011    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5012    This only applies on Tiger and earlier.
5013    If it matches one of these, send it on to keyDown. */
5014 -(void)keyUp: (NSEvent *)theEvent
5016   int flags = [theEvent modifierFlags];
5017   int code = [theEvent keyCode];
5018   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5019       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5020     {
5021       if (NS_KEYLOG)
5022         fprintf (stderr, "keyUp: passed test");
5023       ns_fake_keydown = YES;
5024       [self keyDown: theEvent];
5025     }
5027 #endif
5030 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5033 /* <NSTextInput>: called when done composing;
5034    NOTE: also called when we delete over working text, followed immed.
5035          by doCommandBySelector: deleteBackward: */
5036 - (void)insertText: (id)aString
5038   int code;
5039   int len = [(NSString *)aString length];
5040   int i;
5042   if (NS_KEYLOG)
5043     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5044   processingCompose = NO;
5046   if (!emacs_event)
5047     return;
5049   /* first, clear any working text */
5050   if (workingText != nil)
5051     [self deleteWorkingText];
5053   /* now insert the string as keystrokes */
5054   for (i =0; i<len; i++)
5055     {
5056       code = [aString characterAtIndex: i];
5057       /* TODO: still need this? */
5058       if (code == 0x2DC)
5059         code = '~'; /* 0x7E */
5060       if (code != 32) /* Space */
5061         emacs_event->modifiers = 0;
5062       emacs_event->kind
5063         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5064       emacs_event->code = code;
5065       EV_TRAILER ((id)nil);
5066     }
5070 /* <NSTextInput>: inserts display of composing characters */
5071 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5073   NSString *str = [aString respondsToSelector: @selector (string)] ?
5074     [aString string] : aString;
5075   if (NS_KEYLOG)
5076     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
5077            selRange.length, selRange.location);
5079   if (workingText != nil)
5080     [self deleteWorkingText];
5081   if ([str length] == 0)
5082     return;
5084   if (!emacs_event)
5085     return;
5087   processingCompose = YES;
5088   workingText = [str copy];
5089   ns_working_text = build_string ([workingText UTF8String]);
5091   emacs_event->kind = NS_TEXT_EVENT;
5092   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5093   EV_TRAILER ((id)nil);
5097 /* delete display of composing characters [not in <NSTextInput>] */
5098 - (void)deleteWorkingText
5100   if (workingText == nil)
5101     return;
5102   if (NS_KEYLOG)
5103     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
5104   [workingText release];
5105   workingText = nil;
5106   processingCompose = NO;
5108   if (!emacs_event)
5109     return;
5111   emacs_event->kind = NS_TEXT_EVENT;
5112   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5113   EV_TRAILER ((id)nil);
5117 - (BOOL)hasMarkedText
5119   return workingText != nil;
5123 - (NSRange)markedRange
5125   NSRange rng = workingText != nil
5126     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5127   if (NS_KEYLOG)
5128     NSLog (@"markedRange request");
5129   return rng;
5133 - (void)unmarkText
5135   if (NS_KEYLOG)
5136     NSLog (@"unmark (accept) text");
5137   [self deleteWorkingText];
5138   processingCompose = NO;
5142 /* used to position char selection windows, etc. */
5143 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5145   NSRect rect;
5146   NSPoint pt;
5147   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5148   if (NS_KEYLOG)
5149     NSLog (@"firstRectForCharRange request");
5151   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5152   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5153   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5154   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5155                                        +FRAME_LINE_HEIGHT (emacsframe));
5157   pt = [self convertPoint: pt toView: nil];
5158   pt = [[self window] convertBaseToScreen: pt];
5159   rect.origin = pt;
5160   return rect;
5164 - (NSInteger)conversationIdentifier
5166   return (NSInteger)self;
5170 - (void)doCommandBySelector: (SEL)aSelector
5172   if (NS_KEYLOG)
5173     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5175   processingCompose = NO;
5176   if (aSelector == @selector (deleteBackward:))
5177     {
5178       /* happens when user backspaces over an ongoing composition:
5179          throw a 'delete' into the event queue */
5180       if (!emacs_event)
5181         return;
5182       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5183       emacs_event->code = 0xFF08;
5184       EV_TRAILER ((id)nil);
5185     }
5188 - (NSArray *)validAttributesForMarkedText
5190   static NSArray *arr = nil;
5191   if (arr == nil) arr = [NSArray new];
5192  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5193   return arr;
5196 - (NSRange)selectedRange
5198   if (NS_KEYLOG)
5199     NSLog (@"selectedRange request");
5200   return NSMakeRange (NSNotFound, 0);
5203 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5205   if (NS_KEYLOG)
5206     NSLog (@"characterIndexForPoint request");
5207   return 0;
5210 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5212   static NSAttributedString *str = nil;
5213   if (str == nil) str = [NSAttributedString new];
5214   if (NS_KEYLOG)
5215     NSLog (@"attributedSubstringFromRange request");
5216   return str;
5219 /* End <NSTextInput> impl. */
5220 /*****************************************************************************/
5223 /* This is what happens when the user presses a mouse button.  */
5224 - (void)mouseDown: (NSEvent *)theEvent
5226   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5228   NSTRACE (mouseDown);
5230   [self deleteWorkingText];
5232   if (!emacs_event)
5233     return;
5235   last_mouse_frame = emacsframe;
5236   /* appears to be needed to prevent spurious movement events generated on
5237      button clicks */
5238   last_mouse_frame->mouse_moved = 0;
5240   if ([theEvent type] == NSScrollWheel)
5241     {
5242       float delta = [theEvent deltaY];
5243       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5244       if (delta == 0)
5245         return;
5246       emacs_event->kind = WHEEL_EVENT;
5247       emacs_event->code = 0;
5248       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5249         ((delta > 0) ? up_modifier : down_modifier);
5250     }
5251   else
5252     {
5253       emacs_event->kind = MOUSE_CLICK_EVENT;
5254       emacs_event->code = EV_BUTTON (theEvent);
5255       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5256                              | EV_UDMODIFIERS (theEvent);
5257     }
5258   XSETINT (emacs_event->x, lrint (p.x));
5259   XSETINT (emacs_event->y, lrint (p.y));
5260   EV_TRAILER (theEvent);
5264 - (void)rightMouseDown: (NSEvent *)theEvent
5266   NSTRACE (rightMouseDown);
5267   [self mouseDown: theEvent];
5271 - (void)otherMouseDown: (NSEvent *)theEvent
5273   NSTRACE (otherMouseDown);
5274   [self mouseDown: theEvent];
5278 - (void)mouseUp: (NSEvent *)theEvent
5280   NSTRACE (mouseUp);
5281   [self mouseDown: theEvent];
5285 - (void)rightMouseUp: (NSEvent *)theEvent
5287   NSTRACE (rightMouseUp);
5288   [self mouseDown: theEvent];
5292 - (void)otherMouseUp: (NSEvent *)theEvent
5294   NSTRACE (otherMouseUp);
5295   [self mouseDown: theEvent];
5299 - (void) scrollWheel: (NSEvent *)theEvent
5301   NSTRACE (scrollWheel);
5302   [self mouseDown: theEvent];
5306 /* Tell emacs the mouse has moved. */
5307 - (void)mouseMoved: (NSEvent *)e
5309   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5310   Lisp_Object frame;
5312 //  NSTRACE (mouseMoved);
5314   last_mouse_movement_time = EV_TIMESTAMP (e);
5315   last_mouse_motion_position
5316     = [self convertPoint: [e locationInWindow] fromView: nil];
5318   /* update any mouse face */
5319   if (hlinfo->mouse_face_hidden)
5320     {
5321       hlinfo->mouse_face_hidden = 0;
5322       clear_mouse_face (hlinfo);
5323     }
5325   /* tooltip handling */
5326   previous_help_echo_string = help_echo_string;
5327   help_echo_string = Qnil;
5329   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5330                             last_mouse_motion_position.y))
5331     help_echo_string = previous_help_echo_string;
5333   XSETFRAME (frame, emacsframe);
5334   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5335     {
5336       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5337          (note_mouse_highlight), which is called through the
5338          note_mouse_movement () call above */
5339       gen_help_event (help_echo_string, frame, help_echo_window,
5340                       help_echo_object, help_echo_pos);
5341     }
5342   else
5343     {
5344       help_echo_string = Qnil;
5345       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5346     }
5348   if (emacsframe->mouse_moved && send_appdefined)
5349     ns_send_appdefined (-1);
5353 - (void)mouseDragged: (NSEvent *)e
5355   NSTRACE (mouseDragged);
5356   [self mouseMoved: e];
5360 - (void)rightMouseDragged: (NSEvent *)e
5362   NSTRACE (rightMouseDragged);
5363   [self mouseMoved: e];
5367 - (void)otherMouseDragged: (NSEvent *)e
5369   NSTRACE (otherMouseDragged);
5370   [self mouseMoved: e];
5374 - (BOOL)windowShouldClose: (id)sender
5376   NSEvent *e =[[self window] currentEvent];
5378   NSTRACE (windowShouldClose);
5379   windowClosing = YES;
5380   if (!emacs_event)
5381     return NO;
5382   emacs_event->kind = DELETE_WINDOW_EVENT;
5383   emacs_event->modifiers = 0;
5384   emacs_event->code = 0;
5385   EV_TRAILER (e);
5386   /* Don't close this window, let this be done from lisp code.  */
5387   return NO;
5390 - (void) updateFrameSize: (BOOL) delay;
5392   NSWindow *window = [self window];
5393   NSRect wr = [window frame];
5394 #ifdef NS_IMPL_GNUSTEP
5395   int extra = 3;
5396 #else
5397   int extra = 0;
5398 #endif
5400   int oldc = cols, oldr = rows;
5401   int oldw = FRAME_PIXEL_WIDTH (emacsframe),
5402     oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5403   int neww, newh;
5405   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, wr.size.width + extra);
5407   if (cols < MINWIDTH)
5408     cols = MINWIDTH;
5410   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES
5411     (emacsframe, wr.size.height
5412      - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + extra
5413      - FRAME_TOOLBAR_HEIGHT (emacsframe));
5415   if (rows < MINHEIGHT)
5416     rows = MINHEIGHT;
5418   neww = (int)wr.size.width - emacsframe->border_width;
5419   newh = ((int)wr.size.height
5420           - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5421           - FRAME_TOOLBAR_HEIGHT (emacsframe));
5423   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5424     {
5425       NSView *view = FRAME_NS_VIEW (emacsframe);
5426       FRAME_PIXEL_WIDTH (emacsframe) = neww;
5427       FRAME_PIXEL_HEIGHT (emacsframe) = newh;
5428       change_frame_size (emacsframe, rows, cols, 0, delay, 0);
5429       SET_FRAME_GARBAGED (emacsframe);
5430       cancel_mouse_face (emacsframe);
5431       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5432       [self windowDidMove:nil];   // Update top/left.
5433     }
5436 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5437 /* normalize frame to gridded text size */
5439   NSTRACE (windowWillResize);
5440 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5442   if (fs_state == FULLSCREEN_MAXIMIZED
5443       && (maximized_width != (int)frameSize.width
5444           || maximized_height != (int)frameSize.height))
5445     [self setFSValue: FULLSCREEN_NONE];
5446   else if (fs_state == FULLSCREEN_WIDTH
5447            && maximized_width != (int)frameSize.width)
5448     [self setFSValue: FULLSCREEN_NONE];
5449   else if (fs_state == FULLSCREEN_HEIGHT
5450            && maximized_height != (int)frameSize.height)
5451     [self setFSValue: FULLSCREEN_NONE];
5452   if (fs_state == FULLSCREEN_NONE)
5453     maximized_width = maximized_height = -1;
5455   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5456 #ifdef NS_IMPL_GNUSTEP
5457                                         frameSize.width + 3);
5458 #else
5459                                         frameSize.width);
5460 #endif
5461   if (cols < MINWIDTH)
5462     cols = MINWIDTH;
5464   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
5465 #ifdef NS_IMPL_GNUSTEP
5466       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
5467         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5468 #else
5469       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5470         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5471 #endif
5472   if (rows < MINHEIGHT)
5473     rows = MINHEIGHT;
5474 #ifdef NS_IMPL_COCOA
5475   {
5476     /* this sets window title to have size in it; the wm does this under GS */
5477     NSRect r = [[self window] frame];
5478     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5479       {
5480         if (old_title != 0)
5481           {
5482             xfree (old_title);
5483             old_title = 0;
5484           }
5485       }
5486     else
5487       {
5488         char *size_title;
5489         NSWindow *window = [self window];
5490         if (old_title == 0)
5491           {
5492             const char *t = [[[self window] title] UTF8String];
5493             char *pos = strstr (t, "  â€”  ");
5494             if (pos)
5495               *pos = '\0';
5496             old_title = xstrdup (t);
5497           }
5498         size_title = xmalloc (strlen (old_title) + 40);
5499         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5500         [window setTitle: [NSString stringWithUTF8String: size_title]];
5501         [window display];
5502         xfree (size_title);
5503       }
5504   }
5505 #endif /* NS_IMPL_COCOA */
5506 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5508   return frameSize;
5512 - (void)windowDidResize: (NSNotification *)notification
5515 #if !defined (NEW_STYLE_FS) && ! defined (NS_IMPL_GNUSTEP)
5516   NSWindow *theWindow = [notification object];
5517   /* We can get notification on the non-FS window when in fullscreen mode.  */
5518   if ([self window] != theWindow) return;
5519 #endif
5521 #ifdef NS_IMPL_GNUSTEP
5522   NSWindow *theWindow = [notification object];
5524    /* In GNUstep, at least currently, it's possible to get a didResize
5525       without getting a willResize.. therefore we need to act as if we got
5526       the willResize now */
5527   NSSize sz = [theWindow frame].size;
5528   sz = [self windowWillResize: theWindow toSize: sz];
5529 #endif /* NS_IMPL_GNUSTEP */
5531   NSTRACE (windowDidResize);
5532 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5534 #ifdef NS_IMPL_COCOA
5535   if (old_title != 0)
5536     {
5537       xfree (old_title);
5538       old_title = 0;
5539     }
5540 #endif /* NS_IMPL_COCOA */
5542   if (cols > 0 && rows > 0)
5543     {
5544       [self updateFrameSize: YES];
5545     }
5547   ns_send_appdefined (-1);
5551 - (void)windowDidBecomeKey: (NSNotification *)notification
5552 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5554   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5555   struct frame *old_focus = dpyinfo->x_focus_frame;
5557   NSTRACE (windowDidBecomeKey);
5559   if (emacsframe != old_focus)
5560     dpyinfo->x_focus_frame = emacsframe;
5562   ns_frame_rehighlight (emacsframe);
5564   if (emacs_event)
5565     {
5566       emacs_event->kind = FOCUS_IN_EVENT;
5567       EV_TRAILER ((id)nil);
5568     }
5572 - (void)windowDidResignKey: (NSNotification *)notification
5573 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5575   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5576   NSTRACE (windowDidResignKey);
5578   if (dpyinfo->x_focus_frame == emacsframe)
5579     dpyinfo->x_focus_frame = 0;
5581   ns_frame_rehighlight (emacsframe);
5583   /* FIXME: for some reason needed on second and subsequent clicks away
5584             from sole-frame Emacs to get hollow box to show */
5585   if (!windowClosing && [[self window] isVisible] == YES)
5586     {
5587       x_update_cursor (emacsframe, 1);
5588       x_set_frame_alpha (emacsframe);
5589     }
5591   if (emacs_event)
5592     {
5593       [self deleteWorkingText];
5594       emacs_event->kind = FOCUS_IN_EVENT;
5595       EV_TRAILER ((id)nil);
5596     }
5600 - (void)windowWillMiniaturize: sender
5602   NSTRACE (windowWillMiniaturize);
5606 - (BOOL)isFlipped
5608   return YES;
5612 - (BOOL)isOpaque
5614   return NO;
5618 - initFrameFromEmacs: (struct frame *)f
5620   NSRect r, wr;
5621   Lisp_Object tem;
5622   NSWindow *win;
5623   NSButton *toggleButton;
5624   NSSize sz;
5625   NSColor *col;
5626   NSString *name;
5628   NSTRACE (initFrameFromEmacs);
5630   windowClosing = NO;
5631   processingCompose = NO;
5632   scrollbarsNeedingUpdate = 0;
5633   fs_state = FULLSCREEN_NONE;
5634   fs_before_fs = next_maximized = -1;
5635   maximized_width = maximized_height = -1;
5636   nonfs_window = nil;
5638 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5640   ns_userRect = NSMakeRect (0, 0, 0, 0);
5641   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5642                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5643   [self initWithFrame: r];
5644   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5646   FRAME_NS_VIEW (f) = self;
5647   emacsframe = f;
5648   old_title = 0;
5650   win = [[EmacsWindow alloc]
5651             initWithContentRect: r
5652                       styleMask: (NSResizableWindowMask |
5653 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5654                                   NSTitledWindowMask |
5655 #endif
5656                                   NSMiniaturizableWindowMask |
5657                                   NSClosableWindowMask)
5658                         backing: NSBackingStoreBuffered
5659                           defer: YES];
5661 #ifdef NEW_STYLE_FS
5662     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
5663 #endif
5665   wr = [win frame];
5666   bwidth = f->border_width = wr.size.width - r.size.width;
5667   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5669   [win setAcceptsMouseMovedEvents: YES];
5670   [win setDelegate: self];
5671   [win useOptimizedDrawing: YES];
5673   sz.width = FRAME_COLUMN_WIDTH (f);
5674   sz.height = FRAME_LINE_HEIGHT (f);
5675   [win setResizeIncrements: sz];
5677   [[win contentView] addSubview: self];
5679   if (ns_drag_types)
5680     [self registerForDraggedTypes: ns_drag_types];
5682   tem = f->name;
5683   name = [NSString stringWithUTF8String:
5684                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5685   [win setTitle: name];
5687   /* toolbar support */
5688   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5689                          [NSString stringWithFormat: @"Emacs Frame %d",
5690                                    ns_window_num]];
5691   [win setToolbar: toolbar];
5692   [toolbar setVisible: NO];
5693 #ifdef NS_IMPL_COCOA
5694   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5695   [toggleButton setTarget: self];
5696   [toggleButton setAction: @selector (toggleToolbar: )];
5697 #endif
5698   FRAME_TOOLBAR_HEIGHT (f) = 0;
5700   tem = f->icon_name;
5701   if (!NILP (tem))
5702     [win setMiniwindowTitle:
5703            [NSString stringWithUTF8String: SSDATA (tem)]];
5705   {
5706     NSScreen *screen = [win screen];
5708     if (screen != 0)
5709       [win setFrameTopLeftPoint: NSMakePoint
5710            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5711             IN_BOUND (-SCREENMAX,
5712                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5713   }
5715   [win makeFirstResponder: self];
5717   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5718                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5719   [win setBackgroundColor: col];
5720   if ([col alphaComponent] != 1.0)
5721     [win setOpaque: NO];
5723   [self allocateGState];
5725   [NSApp registerServicesMenuSendTypes: ns_send_types
5726                            returnTypes: nil];
5728   ns_window_num++;
5729   return self;
5733 - (void)windowDidMove: sender
5735   NSWindow *win = [self window];
5736   NSRect r = [win frame];
5737   NSArray *screens = [NSScreen screens];
5738   NSScreen *screen = [screens objectAtIndex: 0];
5740   NSTRACE (windowDidMove);
5742   if (!emacsframe->output_data.ns)
5743     return;
5744   if (screen != nil)
5745     {
5746       emacsframe->left_pos = r.origin.x;
5747       emacsframe->top_pos =
5748         [screen frame].size.height - (r.origin.y + r.size.height);
5749     }
5753 /* Called AFTER method below, but before our windowWillResize call there leads
5754    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5755    location so set_window_size moves the frame. */
5756 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5758   emacsframe->output_data.ns->zooming = 1;
5759   return YES;
5763 /* Override to do something slightly nonstandard, but nice.  First click on
5764    zoom button will zoom vertically.  Second will zoom completely.  Third
5765    returns to original. */
5766 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5767                         defaultFrame:(NSRect)defaultFrame
5769   NSRect result = [sender frame];
5771   NSTRACE (windowWillUseStandardFrame);
5773   if (fs_before_fs != -1) /* Entering fullscreen */
5774       {
5775         result = defaultFrame;
5776       }
5777   else if (next_maximized == FULLSCREEN_HEIGHT
5778       || (next_maximized == -1
5779           && abs (defaultFrame.size.height - result.size.height)
5780           > FRAME_LINE_HEIGHT (emacsframe)))
5781     {
5782       /* first click */
5783       ns_userRect = result;
5784       maximized_height = result.size.height = defaultFrame.size.height;
5785       maximized_width = -1;
5786       result.origin.y = defaultFrame.origin.y;
5787       [self setFSValue: FULLSCREEN_HEIGHT];
5788     }
5789   else if (next_maximized == FULLSCREEN_WIDTH)
5790     {
5791       ns_userRect = result;
5792       maximized_width = result.size.width = defaultFrame.size.width;
5793       maximized_height = -1;
5794       result.origin.x = defaultFrame.origin.x;
5795       [self setFSValue: FULLSCREEN_WIDTH];
5796     }
5797   else if (next_maximized == FULLSCREEN_MAXIMIZED
5798            || (next_maximized == -1
5799                && abs (defaultFrame.size.width - result.size.width)
5800                > FRAME_COLUMN_WIDTH (emacsframe)))
5801     {
5802       result = defaultFrame;  /* second click */
5803       maximized_width = result.size.width;
5804       maximized_height = result.size.height;
5805       [self setFSValue: FULLSCREEN_MAXIMIZED];
5806     }
5807   else
5808     {
5809       /* restore */
5810       result = ns_userRect.size.height ? ns_userRect : result;
5811       ns_userRect = NSMakeRect (0, 0, 0, 0);
5812       [self setFSValue: FULLSCREEN_NONE];
5813       maximized_width = maximized_width = -1;
5814     }
5816   if (fs_before_fs == -1) next_maximized = -1;
5817   [self windowWillResize: sender toSize: result.size];
5818   return result;
5822 - (void)windowDidDeminiaturize: sender
5824   NSTRACE (windowDidDeminiaturize);
5825   if (!emacsframe->output_data.ns)
5826     return;
5828   SET_FRAME_ICONIFIED (emacsframe, 0);
5829   SET_FRAME_VISIBLE (emacsframe, 1);
5830   windows_or_buffers_changed++;
5832   if (emacs_event)
5833     {
5834       emacs_event->kind = DEICONIFY_EVENT;
5835       EV_TRAILER ((id)nil);
5836     }
5840 - (void)windowDidExpose: sender
5842   NSTRACE (windowDidExpose);
5843   if (!emacsframe->output_data.ns)
5844     return;
5846   SET_FRAME_VISIBLE (emacsframe, 1);
5847   SET_FRAME_GARBAGED (emacsframe);
5849   if (send_appdefined)
5850     ns_send_appdefined (-1);
5854 - (void)windowDidMiniaturize: sender
5856   NSTRACE (windowDidMiniaturize);
5857   if (!emacsframe->output_data.ns)
5858     return;
5860   SET_FRAME_ICONIFIED (emacsframe, 1);
5861   SET_FRAME_VISIBLE (emacsframe, 0);
5863   if (emacs_event)
5864     {
5865       emacs_event->kind = ICONIFY_EVENT;
5866       EV_TRAILER ((id)nil);
5867     }
5870 - (void)windowWillEnterFullScreen:(NSNotification *)notification
5872   fs_before_fs = fs_state;
5875 - (void)windowDidEnterFullScreen:(NSNotification *)notification
5877   [self setFSValue: FULLSCREEN_BOTH];
5878 #ifdef NEW_STYLE_FS
5879   // Fix bad background.
5880   if ([toolbar isVisible])
5881     {
5882       [toolbar setVisible:NO];
5883       [toolbar setVisible:YES];
5884     }
5885 #else
5886   [self windowDidBecomeKey:notification];
5887   [nonfs_window orderOut:self];
5888 #endif
5891 - (void)windowWillExitFullScreen:(NSNotification *)notification
5893   if (next_maximized != -1)
5894     fs_before_fs = next_maximized;
5897 - (void)windowDidExitFullScreen:(NSNotification *)notification
5899   [self setFSValue: fs_before_fs];
5900   fs_before_fs = -1;
5901   if (next_maximized != -1)
5902     [[self window] performZoom:self];
5905 - (void)toggleFullScreen: (id)sender
5907 #ifdef NEW_STYLE_FS
5908   [[self window] toggleFullScreen:sender];
5909 #else
5910   NSWindow *w = [self window], *fw;
5911   BOOL onFirstScreen = [[w screen]
5912                          isEqual:[[NSScreen screens] objectAtIndex:0]];
5913   struct frame *f = emacsframe;
5914   NSSize sz;
5915   NSRect r, wr = [w frame];
5916   NSColor *col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5917                                           (FRAME_DEFAULT_FACE (f)),
5918                                           f);
5920   sz.width = FRAME_COLUMN_WIDTH (f);
5921   sz.height = FRAME_LINE_HEIGHT (f);
5923   if (fs_state != FULLSCREEN_BOTH)
5924     {
5925       /* Hide dock and menubar if we are on the primary screen.  */
5926       if (onFirstScreen)
5927         {
5928 #if defined (NS_IMPL_COCOA) && \
5929   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
5930           NSApplicationPresentationOptions options
5931             = NSApplicationPresentationAutoHideDock
5932             | NSApplicationPresentationAutoHideMenuBar;
5934           [NSApp setPresentationOptions: options];
5935 #else
5936           [NSMenu setMenuBarVisible:NO];
5937 #endif
5938         }
5940       fw = [[EmacsFSWindow alloc]
5941                        initWithContentRect:[w contentRectForFrameRect:wr]
5942                                  styleMask:NSBorderlessWindowMask
5943                                    backing:NSBackingStoreBuffered
5944                                      defer:YES
5945                                     screen:[w screen]];
5947       [fw setContentView:[w contentView]];
5948       [fw setTitle:[w title]];
5949       [fw setDelegate:self];
5950       [fw setAcceptsMouseMovedEvents: YES];
5951       [fw useOptimizedDrawing: YES];
5952       [fw setResizeIncrements: sz];
5953       [fw setBackgroundColor: col];
5954       if ([col alphaComponent] != 1.0)
5955         [fw setOpaque: NO];
5957       f->border_width = 0;
5958       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
5959       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
5960       FRAME_TOOLBAR_HEIGHT (f) = 0;
5961       FRAME_EXTERNAL_TOOL_BAR (f) = 0;
5963       nonfs_window = w;
5965       [self windowWillEnterFullScreen:nil];
5966       [fw makeKeyAndOrderFront:NSApp];
5967       [fw makeFirstResponder:self];
5968       [w orderOut:self];
5969       r = [fw frameRectForContentRect:[[fw screen] frame]];
5970       [fw setFrame: r display:YES animate:YES];
5971       [self windowDidEnterFullScreen:nil];
5972       [fw display];
5973     }
5974   else
5975     {
5976       fw = w;
5977       w = nonfs_window;
5978       nonfs_window = nil;
5980       if (onFirstScreen)
5981         {
5982 #if defined (NS_IMPL_COCOA) && \
5983   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
5984           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
5985 #else
5986           [NSMenu setMenuBarVisible:YES];
5987 #endif
5988         }
5990       [w setContentView:[fw contentView]];
5991       [w setResizeIncrements: sz];
5992       [w setBackgroundColor: col];
5993       if ([col alphaComponent] != 1.0)
5994         [w setOpaque: NO];
5996       f->border_width = bwidth;
5997       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
5998       FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
5999       if (tobar_height)
6000         FRAME_EXTERNAL_TOOL_BAR (f) = 1;
6002       [self windowWillExitFullScreen:nil];
6003       [fw setFrame: [w frame] display:YES animate:YES];
6004       [fw close];
6005       [w makeKeyAndOrderFront:NSApp];
6006       [self windowDidExitFullScreen:nil];
6007     }
6008 #endif
6011 - (void)handleFS
6013   if (fs_state != emacsframe->want_fullscreen)
6014     {
6015       if (fs_state == FULLSCREEN_BOTH)
6016         {
6017           [self toggleFullScreen:self];
6018         }
6020       switch (emacsframe->want_fullscreen)
6021         {
6022         case FULLSCREEN_BOTH:
6023           [self toggleFullScreen:self];
6024           break;
6025         case FULLSCREEN_WIDTH:
6026           next_maximized = FULLSCREEN_WIDTH;
6027           if (fs_state != FULLSCREEN_BOTH)
6028             [[self window] performZoom:self];
6029           break;
6030         case FULLSCREEN_HEIGHT:
6031           next_maximized = FULLSCREEN_HEIGHT;
6032           if (fs_state != FULLSCREEN_BOTH)
6033             [[self window] performZoom:self];
6034           break;
6035         case FULLSCREEN_MAXIMIZED:
6036           next_maximized = FULLSCREEN_MAXIMIZED;
6037           if (fs_state != FULLSCREEN_BOTH)
6038             [[self window] performZoom:self];
6039           break;
6040         case FULLSCREEN_NONE:
6041           if (fs_state != FULLSCREEN_BOTH)
6042             {
6043               next_maximized = FULLSCREEN_NONE;
6044               [[self window] performZoom:self];
6045             }
6046           break;
6047         }
6049       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6050     }
6054 - (void) setFSValue: (int)value
6056   Lisp_Object lval = Qnil;
6057   switch (value)
6058     {
6059     case FULLSCREEN_BOTH:
6060       lval = Qfullboth;
6061       break;
6062     case FULLSCREEN_WIDTH:
6063       lval = Qfullwidth;
6064       break;
6065     case FULLSCREEN_HEIGHT:
6066       lval = Qfullheight;
6067       break;
6068     case FULLSCREEN_MAXIMIZED:
6069       lval = Qmaximized;
6070       break;
6071     }
6072   store_frame_param (emacsframe, Qfullscreen, lval);
6073   fs_state = value;
6076 - (void)mouseEntered: (NSEvent *)theEvent
6078   NSTRACE (mouseEntered);
6079   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6083 - (void)mouseExited: (NSEvent *)theEvent
6085   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6087   NSTRACE (mouseExited);
6089   if (!hlinfo)
6090     return;
6092   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6094   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6095     {
6096       clear_mouse_face (hlinfo);
6097       hlinfo->mouse_face_mouse_frame = 0;
6098     }
6102 - menuDown: sender
6104   NSTRACE (menuDown);
6105   if (context_menu_value == -1)
6106     context_menu_value = [sender tag];
6107   else
6108     {
6109       NSInteger tag = [sender tag];
6110       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6111                                     emacsframe->menu_bar_vector,
6112                                     (void *)tag);
6113     }
6115   ns_send_appdefined (-1);
6116   return self;
6120 - (EmacsToolbar *)toolbar
6122   return toolbar;
6126 /* this gets called on toolbar button click */
6127 - toolbarClicked: (id)item
6129   NSEvent *theEvent;
6130   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6132   NSTRACE (toolbarClicked);
6134   if (!emacs_event)
6135     return self;
6137   /* send first event (for some reason two needed) */
6138   theEvent = [[self window] currentEvent];
6139   emacs_event->kind = TOOL_BAR_EVENT;
6140   XSETFRAME (emacs_event->arg, emacsframe);
6141   EV_TRAILER (theEvent);
6143   emacs_event->kind = TOOL_BAR_EVENT;
6144 /*   XSETINT (emacs_event->code, 0); */
6145   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6146                            idx + TOOL_BAR_ITEM_KEY);
6147   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6148   EV_TRAILER (theEvent);
6149   return self;
6153 - toggleToolbar: (id)sender
6155   if (!emacs_event)
6156     return self;
6158   emacs_event->kind = NS_NONKEY_EVENT;
6159   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6160   EV_TRAILER ((id)nil);
6161   return self;
6165 - (void)drawRect: (NSRect)rect
6167   int x = NSMinX (rect), y = NSMinY (rect);
6168   int width = NSWidth (rect), height = NSHeight (rect);
6170   NSTRACE (drawRect);
6172   if (!emacsframe || !emacsframe->output_data.ns)
6173     return;
6175   ns_clear_frame_area (emacsframe, x, y, width, height);
6176   expose_frame (emacsframe, x, y, width, height);
6178   /*
6179     drawRect: may be called (at least in OS X 10.5) for invisible
6180     views as well for some reason.  Thus, do not infer visibility
6181     here.
6183     emacsframe->async_visible = 1;
6184     emacsframe->async_iconified = 0;
6185   */
6189 /* NSDraggingDestination protocol methods.  Actually this is not really a
6190    protocol, but a category of Object.  O well...  */
6192 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6194   NSTRACE (draggingEntered);
6195   return NSDragOperationGeneric;
6199 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6201   return YES;
6205 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6207   id pb;
6208   int x, y;
6209   NSString *type;
6210   NSEvent *theEvent = [[self window] currentEvent];
6211   NSPoint position;
6213   NSTRACE (performDragOperation);
6215   if (!emacs_event)
6216     return NO;
6218   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6219   x = lrint (position.x);  y = lrint (position.y);
6221   pb = [sender draggingPasteboard];
6222   type = [pb availableTypeFromArray: ns_drag_types];
6223   if (type == 0)
6224     {
6225       return NO;
6226     }
6227   else if ([type isEqualToString: NSFilenamesPboardType])
6228     {
6229       NSArray *files;
6230       NSEnumerator *fenum;
6231       NSString *file;
6233       if (!(files = [pb propertyListForType: type]))
6234         return NO;
6236       fenum = [files objectEnumerator];
6237       while ( (file = [fenum nextObject]) )
6238         {
6239           emacs_event->kind = NS_NONKEY_EVENT;
6240           emacs_event->code = KEY_NS_DRAG_FILE;
6241           XSETINT (emacs_event->x, x);
6242           XSETINT (emacs_event->y, y);
6243           ns_input_file = append2 (ns_input_file,
6244                                    build_string ([file UTF8String]));
6245           emacs_event->modifiers = EV_MODIFIERS (theEvent);
6246           EV_TRAILER (theEvent);
6247         }
6248       return YES;
6249     }
6250   else if ([type isEqualToString: NSURLPboardType])
6251     {
6252       NSString *file;
6253       NSURL *fileURL;
6255       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6256           [fileURL isFileURL] == NO)
6257         return NO;
6259       file = [fileURL path];
6260       emacs_event->kind = NS_NONKEY_EVENT;
6261       emacs_event->code = KEY_NS_DRAG_FILE;
6262       XSETINT (emacs_event->x, x);
6263       XSETINT (emacs_event->y, y);
6264       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6265       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6266       EV_TRAILER (theEvent);
6267       return YES;
6268     }
6269   else if ([type isEqualToString: NSStringPboardType]
6270            || [type isEqualToString: NSTabularTextPboardType])
6271     {
6272       NSString *data;
6274       if (! (data = [pb stringForType: type]))
6275         return NO;
6277       emacs_event->kind = NS_NONKEY_EVENT;
6278       emacs_event->code = KEY_NS_DRAG_TEXT;
6279       XSETINT (emacs_event->x, x);
6280       XSETINT (emacs_event->y, y);
6281       ns_input_text = build_string ([data UTF8String]);
6282       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6283       EV_TRAILER (theEvent);
6284       return YES;
6285     }
6286   else if ([type isEqualToString: NSColorPboardType])
6287     {
6288       NSColor *c = [NSColor colorFromPasteboard: pb];
6289       emacs_event->kind = NS_NONKEY_EVENT;
6290       emacs_event->code = KEY_NS_DRAG_COLOR;
6291       XSETINT (emacs_event->x, x);
6292       XSETINT (emacs_event->y, y);
6293       ns_input_color = ns_color_to_lisp (c);
6294       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6295       EV_TRAILER (theEvent);
6296       return YES;
6297     }
6298   else if ([type isEqualToString: NSFontPboardType])
6299     {
6300       /* impl based on GNUstep NSTextView.m */
6301       NSData *data = [pb dataForType: NSFontPboardType];
6302       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6303       NSFont *font = [dict objectForKey: NSFontAttributeName];
6304       char fontSize[10];
6306       if (font == nil)
6307         return NO;
6309       emacs_event->kind = NS_NONKEY_EVENT;
6310       emacs_event->code = KEY_NS_CHANGE_FONT;
6311       XSETINT (emacs_event->x, x);
6312       XSETINT (emacs_event->y, y);
6313       ns_input_font = build_string ([[font fontName] UTF8String]);
6314       snprintf (fontSize, 10, "%f", [font pointSize]);
6315       ns_input_fontsize = build_string (fontSize);
6316       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6317       EV_TRAILER (theEvent);
6318       return YES;
6319     }
6320   else
6321     {
6322       error ("Invalid data type in dragging pasteboard.");
6323       return NO;
6324     }
6328 - (id) validRequestorForSendType: (NSString *)typeSent
6329                       returnType: (NSString *)typeReturned
6331   NSTRACE (validRequestorForSendType);
6332   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6333       && typeReturned == nil)
6334     {
6335       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6336         return self;
6337     }
6339   return [super validRequestorForSendType: typeSent
6340                                returnType: typeReturned];
6344 /* The next two methods are part of NSServicesRequests informal protocol,
6345    supposedly called when a services menu item is chosen from this app.
6346    But this should not happen because we override the services menu with our
6347    own entries which call ns-perform-service.
6348    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6349    So let's at least stub them out until further investigation can be done. */
6351 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6353   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6354      be written into the buffer in place of the existing selection..
6355      ordinary service calls go through functions defined in ns-win.el */
6356   return NO;
6359 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6361   NSArray *typesDeclared;
6362   Lisp_Object val;
6364   /* We only support NSStringPboardType */
6365   if ([types containsObject:NSStringPboardType] == NO) {
6366     return NO;
6367   }
6369   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6370   if (CONSP (val) && SYMBOLP (XCAR (val)))
6371     {
6372       val = XCDR (val);
6373       if (CONSP (val) && NILP (XCDR (val)))
6374         val = XCAR (val);
6375     }
6376   if (! STRINGP (val))
6377     return NO;
6379   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6380   [pb declareTypes:typesDeclared owner:nil];
6381   ns_string_to_pasteboard (pb, val);
6382   return YES;
6386 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6387    (gives a miniaturized version of the window); currently we use the latter for
6388    frames whose active buffer doesn't correspond to any file
6389    (e.g., '*scratch*') */
6390 - setMiniwindowImage: (BOOL) setMini
6392   id image = [[self window] miniwindowImage];
6393   NSTRACE (setMiniwindowImage);
6395   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6396      about "AppleDockIconEnabled" notwithstanding, however the set message
6397      below has its effect nonetheless. */
6398   if (image != emacsframe->output_data.ns->miniimage)
6399     {
6400       if (image && [image isKindOfClass: [EmacsImage class]])
6401         [image release];
6402       [[self window] setMiniwindowImage:
6403                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6404     }
6406   return self;
6410 - (void) setRows: (int) r andColumns: (int) c
6412   rows = r;
6413   cols = c;
6416 @end  /* EmacsView */
6420 /* ==========================================================================
6422     EmacsWindow implementation
6424    ========================================================================== */
6426 @implementation EmacsWindow
6428 #ifdef NS_IMPL_COCOA
6429 - (id)accessibilityAttributeValue:(NSString *)attribute
6431   Lisp_Object str = Qnil;
6432   struct frame *f = SELECTED_FRAME ();
6433   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->buffer);
6435   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6436     return NSAccessibilityTextFieldRole;
6438   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6439       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6440     {
6441       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6442     }
6443   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6444     {
6445       if (! NILP (BVAR (curbuf, mark_active)))
6446           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6448       if (NILP (str))
6449         {
6450           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6451           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6452           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6454           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6455             str = make_uninit_multibyte_string (range, byte_range);
6456           else
6457             str = make_uninit_string (range);
6458           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6459              Is this a problem?  */
6460           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6461         }
6462     }
6465   if (! NILP (str))
6466     {
6467       if (CONSP (str) && SYMBOLP (XCAR (str)))
6468         {
6469           str = XCDR (str);
6470           if (CONSP (str) && NILP (XCDR (str)))
6471             str = XCAR (str);
6472         }
6473       if (STRINGP (str))
6474         {
6475           const char *utfStr = SSDATA (str);
6476           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6477           return nsStr;
6478         }
6479     }
6481   return [super accessibilityAttributeValue:attribute];
6483 #endif /* NS_IMPL_COCOA */
6485 /* If we have multiple monitors, one above the other, we don't want to
6486    restrict the height to just one monitor.  So we override this.  */
6487 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6489   /* When making the frame visible for the first time or if there is just
6490      one screen, we want to constrain.  Other times not.  */
6491   NSUInteger nr_screens = [[NSScreen screens] count];
6492   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6493   NSTRACE (constrainFrameRect);
6495   if (nr_screens == 1)
6496     {
6497       NSRect r = [super constrainFrameRect:frameRect toScreen:screen];
6498       return r;
6499     }
6501   if (f->output_data.ns->dont_constrain
6502       || ns_menu_bar_should_be_hidden ())
6503     return frameRect;
6505   f->output_data.ns->dont_constrain = 1;
6506   return [super constrainFrameRect:frameRect toScreen:screen];
6509 @end /* EmacsWindow */
6512 @implementation EmacsFSWindow
6514 - (BOOL)canBecomeKeyWindow
6516   return YES;
6519 - (BOOL)canBecomeMainWindow
6521   return YES;
6524 @end
6526 /* ==========================================================================
6528     EmacsScroller implementation
6530    ========================================================================== */
6533 @implementation EmacsScroller
6535 /* for repeat button push */
6536 #define SCROLL_BAR_FIRST_DELAY 0.5
6537 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6539 + (CGFloat) scrollerWidth
6541   /* TODO: if we want to allow variable widths, this is the place to do it,
6542            however neither GNUstep nor Cocoa support it very well */
6543   return [NSScroller scrollerWidth];
6547 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6549   NSTRACE (EmacsScroller_initFrame);
6551   r.size.width = [EmacsScroller scrollerWidth];
6552   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6553   [self setContinuous: YES];
6554   [self setEnabled: YES];
6556   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6557      locked against the top and bottom edges, and right edge on OS X, where
6558      scrollers are on right. */
6559 #ifdef NS_IMPL_GNUSTEP
6560   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6561 #else
6562   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6563 #endif
6565   win = nwin;
6566   condemned = NO;
6567   pixel_height = NSHeight (r);
6568   if (pixel_height == 0) pixel_height = 1;
6569   min_portion = 20 / pixel_height;
6571   frame = XFRAME (XWINDOW (win)->frame);
6572   if (FRAME_LIVE_P (frame))
6573     {
6574       int i;
6575       EmacsView *view = FRAME_NS_VIEW (frame);
6576       NSView *sview = [[view window] contentView];
6577       NSArray *subs = [sview subviews];
6579       /* disable optimization stopping redraw of other scrollbars */
6580       view->scrollbarsNeedingUpdate = 0;
6581       for (i =[subs count]-1; i >= 0; i--)
6582         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6583           view->scrollbarsNeedingUpdate++;
6584       [sview addSubview: self];
6585     }
6587 /*  [self setFrame: r]; */
6589   return self;
6593 - (void)setFrame: (NSRect)newRect
6595   NSTRACE (EmacsScroller_setFrame);
6596 /*  block_input (); */
6597   pixel_height = NSHeight (newRect);
6598   if (pixel_height == 0) pixel_height = 1;
6599   min_portion = 20 / pixel_height;
6600   [super setFrame: newRect];
6601   [self display];
6602 /*  unblock_input (); */
6606 - (void)dealloc
6608   NSTRACE (EmacsScroller_dealloc);
6609   if (!NILP (win))
6610     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
6611   [super dealloc];
6615 - condemn
6617   NSTRACE (condemn);
6618   condemned =YES;
6619   return self;
6623 - reprieve
6625   NSTRACE (reprieve);
6626   condemned =NO;
6627   return self;
6631 - judge
6633   NSTRACE (judge);
6634   if (condemned)
6635     {
6636       EmacsView *view;
6637       block_input ();
6638       /* ensure other scrollbar updates after deletion */
6639       view = (EmacsView *)FRAME_NS_VIEW (frame);
6640       if (view != nil)
6641         view->scrollbarsNeedingUpdate++;
6642       [self removeFromSuperview];
6643       [self release];
6644       unblock_input ();
6645     }
6646   return self;
6650 - (void)resetCursorRects
6652   NSRect visible = [self visibleRect];
6653   NSTRACE (resetCursorRects);
6655   if (!NSIsEmptyRect (visible))
6656     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6657   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6661 - (int) checkSamePosition: (int) position portion: (int) portion
6662                     whole: (int) whole
6664   return em_position ==position && em_portion ==portion && em_whole ==whole
6665     && portion != whole; /* needed for resize empty buf */
6669 - setPosition: (int)position portion: (int)portion whole: (int)whole
6671   NSTRACE (setPosition);
6673   em_position = position;
6674   em_portion = portion;
6675   em_whole = whole;
6677   if (portion >= whole)
6678     {
6679 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6680       [self setKnobProportion: 1.0];
6681       [self setDoubleValue: 1.0];
6682 #else
6683       [self setFloatValue: 0.0 knobProportion: 1.0];
6684 #endif
6685     }
6686   else
6687     {
6688       float pos, por;
6689       portion = max ((float)whole*min_portion/pixel_height, portion);
6690       pos = (float)position / (whole - portion);
6691       por = (float)portion/whole;
6692 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6693       [self setKnobProportion: por];
6694       [self setDoubleValue: pos];
6695 #else
6696       [self setFloatValue: pos knobProportion: por];
6697 #endif
6698     }
6700   /* Events may come here even if the event loop is not running.
6701      If we don't enter the event loop, the scroll bar will not update.
6702      So send SIGIO to ourselves.  */
6703   if (apploopnr == 0) raise (SIGIO);
6705   return self;
6708 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6709      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6710 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6711                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6713   *part = last_hit_part;
6714   *window = win;
6715   XSETINT (*y, pixel_height);
6716   if ([self floatValue] > 0.999)
6717     XSETINT (*x, pixel_height);
6718   else
6719     XSETINT (*x, pixel_height * [self floatValue]);
6723 /* set up emacs_event */
6724 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6726   if (!emacs_event)
6727     return;
6729   emacs_event->part = last_hit_part;
6730   emacs_event->code = 0;
6731   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6732   emacs_event->frame_or_window = win;
6733   emacs_event->timestamp = EV_TIMESTAMP (e);
6734   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6735   emacs_event->arg = Qnil;
6736   XSETINT (emacs_event->x, loc * pixel_height);
6737   XSETINT (emacs_event->y, pixel_height-20);
6739   if (q_event_ptr)
6740     {
6741       n_emacs_events_pending++;
6742       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6743     }
6744   else
6745     hold_event (emacs_event);
6746   EVENT_INIT (*emacs_event);
6747   ns_send_appdefined (-1);
6751 /* called manually thru timer to implement repeated button action w/hold-down */
6752 - repeatScroll: (NSTimer *)scrollEntry
6754   NSEvent *e = [[self window] currentEvent];
6755   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6756   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6758   /* clear timer if need be */
6759   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6760     {
6761         [scroll_repeat_entry invalidate];
6762         [scroll_repeat_entry release];
6763         scroll_repeat_entry = nil;
6765         if (inKnob)
6766           return self;
6768         scroll_repeat_entry
6769           = [[NSTimer scheduledTimerWithTimeInterval:
6770                         SCROLL_BAR_CONTINUOUS_DELAY
6771                                             target: self
6772                                           selector: @selector (repeatScroll:)
6773                                           userInfo: 0
6774                                            repeats: YES]
6775               retain];
6776     }
6778   [self sendScrollEventAtLoc: 0 fromEvent: e];
6779   return self;
6783 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6784    mouseDragged events without going into a modal loop. */
6785 - (void)mouseDown: (NSEvent *)e
6787   NSRect sr, kr;
6788   /* hitPart is only updated AFTER event is passed on */
6789   NSScrollerPart part = [self testPart: [e locationInWindow]];
6790   double inc = 0.0, loc, kloc, pos;
6791   int edge = 0;
6793   NSTRACE (EmacsScroller_mouseDown);
6795   switch (part)
6796     {
6797     case NSScrollerDecrementPage:
6798         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6799     case NSScrollerIncrementPage:
6800         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6801     case NSScrollerDecrementLine:
6802       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6803     case NSScrollerIncrementLine:
6804       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6805     case NSScrollerKnob:
6806       last_hit_part = scroll_bar_handle; break;
6807     case NSScrollerKnobSlot:  /* GNUstep-only */
6808       last_hit_part = scroll_bar_move_ratio; break;
6809     default:  /* NSScrollerNoPart? */
6810       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6811                (long) part);
6812       return;
6813     }
6815   if (inc != 0.0)
6816     {
6817       pos = 0;      /* ignored */
6819       /* set a timer to repeat, as we can't let superclass do this modally */
6820       scroll_repeat_entry
6821         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6822                                             target: self
6823                                           selector: @selector (repeatScroll:)
6824                                           userInfo: 0
6825                                            repeats: YES]
6826             retain];
6827     }
6828   else
6829     {
6830       /* handle, or on GNUstep possibly slot */
6831       NSEvent *fake_event;
6833       /* compute float loc in slot and mouse offset on knob */
6834       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6835                       toView: nil];
6836       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6837       if (loc <= 0.0)
6838         {
6839           loc = 0.0;
6840           edge = -1;
6841         }
6842       else if (loc >= NSHeight (sr))
6843         {
6844           loc = NSHeight (sr);
6845           edge = 1;
6846         }
6848       if (edge)
6849         kloc = 0.5 * edge;
6850       else
6851         {
6852           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6853                           toView: nil];
6854           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6855         }
6856       last_mouse_offset = kloc;
6858       /* if knob, tell emacs a location offset by knob pos
6859          (to indicate top of handle) */
6860       if (part == NSScrollerKnob)
6861           pos = (loc - last_mouse_offset) / NSHeight (sr);
6862       else
6863         /* else this is a slot click on GNUstep: go straight there */
6864         pos = loc / NSHeight (sr);
6866       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6867       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6868                                       location: [e locationInWindow]
6869                                  modifierFlags: [e modifierFlags]
6870                                      timestamp: [e timestamp]
6871                                   windowNumber: [e windowNumber]
6872                                        context: [e context]
6873                                    eventNumber: [e eventNumber]
6874                                     clickCount: [e clickCount]
6875                                       pressure: [e pressure]];
6876       [super mouseUp: fake_event];
6877     }
6879   if (part != NSScrollerKnob)
6880     [self sendScrollEventAtLoc: pos fromEvent: e];
6884 /* Called as we manually track scroller drags, rather than superclass. */
6885 - (void)mouseDragged: (NSEvent *)e
6887     NSRect sr;
6888     double loc, pos;
6889     int edge = 0;
6891     NSTRACE (EmacsScroller_mouseDragged);
6893       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6894                       toView: nil];
6895       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6897       if (loc <= 0.0)
6898         {
6899           loc = 0.0;
6900           edge = -1;
6901         }
6902       else if (loc >= NSHeight (sr) + last_mouse_offset)
6903         {
6904           loc = NSHeight (sr) + last_mouse_offset;
6905           edge = 1;
6906         }
6908       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6909       [self sendScrollEventAtLoc: pos fromEvent: e];
6913 - (void)mouseUp: (NSEvent *)e
6915   if (scroll_repeat_entry)
6916     {
6917       [scroll_repeat_entry invalidate];
6918       [scroll_repeat_entry release];
6919       scroll_repeat_entry = nil;
6920     }
6921   last_hit_part = 0;
6925 /* treat scrollwheel events in the bar as though they were in the main window */
6926 - (void) scrollWheel: (NSEvent *)theEvent
6928   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6929   [view mouseDown: theEvent];
6932 @end  /* EmacsScroller */
6937 /* ==========================================================================
6939    Font-related functions; these used to be in nsfaces.m
6941    ========================================================================== */
6944 Lisp_Object
6945 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6947   struct font *font = XFONT_OBJECT (font_object);
6949   if (fontset < 0)
6950     fontset = fontset_from_font (font_object);
6951   FRAME_FONTSET (f) = fontset;
6953   if (FRAME_FONT (f) == font)
6954     /* This font is already set in frame F.  There's nothing more to
6955        do.  */
6956     return font_object;
6958   FRAME_FONT (f) = font;
6960   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6961   FRAME_COLUMN_WIDTH (f) = font->average_width;
6962   FRAME_LINE_HEIGHT (f) = font->height;
6964   compute_fringe_widths (f, 1);
6966   /* Compute the scroll bar width in character columns.  */
6967   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6968     {
6969       int wid = FRAME_COLUMN_WIDTH (f);
6970       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6971         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6972     }
6973   else
6974     {
6975       int wid = FRAME_COLUMN_WIDTH (f);
6976       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6977     }
6979   /* Now make the frame display the given font.  */
6980   if (FRAME_NS_WINDOW (f) != 0)
6981         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6983   return font_object;
6987 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6988 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6989          in 1.43. */
6991 const char *
6992 ns_xlfd_to_fontname (const char *xlfd)
6993 /* --------------------------------------------------------------------------
6994     Convert an X font name (XLFD) to an NS font name.
6995     Only family is used.
6996     The string returned is temporarily allocated.
6997    -------------------------------------------------------------------------- */
6999   char *name = xmalloc (180);
7000   int i, len;
7001   const char *ret;
7003   if (!strncmp (xlfd, "--", 2))
7004     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7005   else
7006     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7008   /* stopgap for malformed XLFD input */
7009   if (strlen (name) == 0)
7010     strcpy (name, "Monaco");
7012   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7013      also uppercase after '-' or ' ' */
7014   name[0] = c_toupper (name[0]);
7015   for (len =strlen (name), i =0; i<len; i++)
7016     {
7017       if (name[i] == '$')
7018         {
7019           name[i] = '-';
7020           if (i+1<len)
7021             name[i+1] = c_toupper (name[i+1]);
7022         }
7023       else if (name[i] == '_')
7024         {
7025           name[i] = ' ';
7026           if (i+1<len)
7027             name[i+1] = c_toupper (name[i+1]);
7028         }
7029     }
7030 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7031   ret = [[NSString stringWithUTF8String: name] UTF8String];
7032   xfree (name);
7033   return ret;
7037 void
7038 syms_of_nsterm (void)
7040   NSTRACE (syms_of_nsterm);
7042   ns_antialias_threshold = 10.0;
7044   /* from 23+ we need to tell emacs what modifiers there are.. */
7045   DEFSYM (Qmodifier_value, "modifier-value");
7046   DEFSYM (Qalt, "alt");
7047   DEFSYM (Qhyper, "hyper");
7048   DEFSYM (Qmeta, "meta");
7049   DEFSYM (Qsuper, "super");
7050   DEFSYM (Qcontrol, "control");
7051   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7053   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7054   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7055   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7056   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7057   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7059   DEFVAR_LISP ("ns-input-file", ns_input_file,
7060               "The file specified in the last NS event.");
7061   ns_input_file =Qnil;
7063   DEFVAR_LISP ("ns-input-text", ns_input_text,
7064               "The data received in the last NS text drag event.");
7065   ns_input_text =Qnil;
7067   DEFVAR_LISP ("ns-working-text", ns_working_text,
7068               "String for visualizing working composition sequence.");
7069   ns_working_text =Qnil;
7071   DEFVAR_LISP ("ns-input-font", ns_input_font,
7072               "The font specified in the last NS event.");
7073   ns_input_font =Qnil;
7075   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7076               "The fontsize specified in the last NS event.");
7077   ns_input_fontsize =Qnil;
7079   DEFVAR_LISP ("ns-input-line", ns_input_line,
7080                "The line specified in the last NS event.");
7081   ns_input_line =Qnil;
7083   DEFVAR_LISP ("ns-input-color", ns_input_color,
7084                "The color specified in the last NS event.");
7085   ns_input_color =Qnil;
7087   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7088                "The service name specified in the last NS event.");
7089   ns_input_spi_name =Qnil;
7091   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7092                "The service argument specified in the last NS event.");
7093   ns_input_spi_arg =Qnil;
7095   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7096                "This variable describes the behavior of the alternate or option key.\n\
7097 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7098 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7099 at all, allowing it to be used at a lower level for accented character entry.");
7100   ns_alternate_modifier = Qmeta;
7102   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7103                "This variable describes the behavior of the right alternate or option key.\n\
7104 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7105 Set to left means be the same key as `ns-alternate-modifier'.\n\
7106 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7107 at all, allowing it to be used at a lower level for accented character entry.");
7108   ns_right_alternate_modifier = Qleft;
7110   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7111                "This variable describes the behavior of the command key.\n\
7112 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7113   ns_command_modifier = Qsuper;
7115   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7116                "This variable describes the behavior of the right command key.\n\
7117 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7118 Set to left means be the same key as `ns-command-modifier'.\n\
7119 Set to none means that the command / option key is not interpreted by Emacs\n\
7120 at all, allowing it to be used at a lower level for accented character entry.");
7121   ns_right_command_modifier = Qleft;
7123   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7124                "This variable describes the behavior of the control key.\n\
7125 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7126   ns_control_modifier = Qcontrol;
7128   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7129                "This variable describes the behavior of the right control key.\n\
7130 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7131 Set to left means be the same key as `ns-control-modifier'.\n\
7132 Set to none means that the control / option key is not interpreted by Emacs\n\
7133 at all, allowing it to be used at a lower level for accented character entry.");
7134   ns_right_control_modifier = Qleft;
7136   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7137                "This variable describes the behavior of the function key (on laptops).\n\
7138 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7139 Set to none means that the function key is not interpreted by Emacs at all,\n\
7140 allowing it to be used at a lower level for accented character entry.");
7141   ns_function_modifier = Qnone;
7143   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7144                "Non-nil (the default) means to render text antialiased.");
7145   ns_antialias_text = Qt;
7147   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7148                "Whether to confirm application quit using dialog.");
7149   ns_confirm_quit = Qnil;
7151   staticpro (&ns_display_name_list);
7152   ns_display_name_list = Qnil;
7154   staticpro (&last_mouse_motion_frame);
7155   last_mouse_motion_frame = Qnil;
7157   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7158                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7159 Only works on OSX 10.6 or later.  */);
7160   ns_auto_hide_menu_bar = Qnil;
7162   /* TODO: move to common code */
7163   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7164                doc: /* Which toolkit scroll bars Emacs uses, if any.
7165 A value of nil means Emacs doesn't use toolkit scroll bars.
7166 With the X Window system, the value is a symbol describing the
7167 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7168 With MS Windows or Nextstep, the value is t.  */);
7169   Vx_toolkit_scroll_bars = Qt;
7171   DEFVAR_BOOL ("x-use-underline-position-properties",
7172                x_use_underline_position_properties,
7173      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7174 A value of nil means ignore them.  If you encounter fonts with bogus
7175 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7176 to 4.1, set this to nil. */);
7177   x_use_underline_position_properties = 0;
7179   DEFVAR_BOOL ("x-underline-at-descent-line",
7180                x_underline_at_descent_line,
7181      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7182 A value of nil means to draw the underline according to the value of the
7183 variable `x-use-underline-position-properties', which is usually at the
7184 baseline level.  The default value is nil.  */);
7185   x_underline_at_descent_line = 0;
7187   /* Tell emacs about this window system. */
7188   Fprovide (intern ("ns"), Qnil);