* admin/admin.el (add-release-logs): Use UTC for release date.
[emacs.git] / src / nsterm.m
blob1f09e0315920c69a2da449596ae83b77e877cccf
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 extern NSString *NSMenuDidBeginTrackingNotification;
74 /* ==========================================================================
76     Local declarations
78    ========================================================================== */
80 /* Convert a symbol indexed with an NSxxx value to a value as defined
81    in keyboard.c (lispy_function_key). I hope this is a correct way
82    of doing things... */
83 static unsigned convert_ns_to_X_keysym[] =
85   NSHomeFunctionKey,            0x50,
86   NSLeftArrowFunctionKey,       0x51,
87   NSUpArrowFunctionKey,         0x52,
88   NSRightArrowFunctionKey,      0x53,
89   NSDownArrowFunctionKey,       0x54,
90   NSPageUpFunctionKey,          0x55,
91   NSPageDownFunctionKey,        0x56,
92   NSEndFunctionKey,             0x57,
93   NSBeginFunctionKey,           0x58,
94   NSSelectFunctionKey,          0x60,
95   NSPrintFunctionKey,           0x61,
96   NSClearLineFunctionKey,       0x0B,
97   NSExecuteFunctionKey,         0x62,
98   NSInsertFunctionKey,          0x63,
99   NSUndoFunctionKey,            0x65,
100   NSRedoFunctionKey,            0x66,
101   NSMenuFunctionKey,            0x67,
102   NSFindFunctionKey,            0x68,
103   NSHelpFunctionKey,            0x6A,
104   NSBreakFunctionKey,           0x6B,
106   NSF1FunctionKey,              0xBE,
107   NSF2FunctionKey,              0xBF,
108   NSF3FunctionKey,              0xC0,
109   NSF4FunctionKey,              0xC1,
110   NSF5FunctionKey,              0xC2,
111   NSF6FunctionKey,              0xC3,
112   NSF7FunctionKey,              0xC4,
113   NSF8FunctionKey,              0xC5,
114   NSF9FunctionKey,              0xC6,
115   NSF10FunctionKey,             0xC7,
116   NSF11FunctionKey,             0xC8,
117   NSF12FunctionKey,             0xC9,
118   NSF13FunctionKey,             0xCA,
119   NSF14FunctionKey,             0xCB,
120   NSF15FunctionKey,             0xCC,
121   NSF16FunctionKey,             0xCD,
122   NSF17FunctionKey,             0xCE,
123   NSF18FunctionKey,             0xCF,
124   NSF19FunctionKey,             0xD0,
125   NSF20FunctionKey,             0xD1,
126   NSF21FunctionKey,             0xD2,
127   NSF22FunctionKey,             0xD3,
128   NSF23FunctionKey,             0xD4,
129   NSF24FunctionKey,             0xD5,
131   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
132   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
133   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
135   NSTabCharacter,               0x09,
136   0x19,                         0x09,  /* left tab->regular since pass shift */
137   NSCarriageReturnCharacter,    0x0D,
138   NSNewlineCharacter,           0x0D,
139   NSEnterCharacter,             0x8D,
141   0x41|NSNumericPadKeyMask,     0xAE,  /* KP_Decimal */
142   0x43|NSNumericPadKeyMask,     0xAA,  /* KP_Multiply */
143   0x45|NSNumericPadKeyMask,     0xAB,  /* KP_Add */
144   0x4B|NSNumericPadKeyMask,     0xAF,  /* KP_Divide */
145   0x4E|NSNumericPadKeyMask,     0xAD,  /* KP_Subtract */
146   0x51|NSNumericPadKeyMask,     0xBD,  /* KP_Equal */
147   0x52|NSNumericPadKeyMask,     0xB0,  /* KP_0 */
148   0x53|NSNumericPadKeyMask,     0xB1,  /* KP_1 */
149   0x54|NSNumericPadKeyMask,     0xB2,  /* KP_2 */
150   0x55|NSNumericPadKeyMask,     0xB3,  /* KP_3 */
151   0x56|NSNumericPadKeyMask,     0xB4,  /* KP_4 */
152   0x57|NSNumericPadKeyMask,     0xB5,  /* KP_5 */
153   0x58|NSNumericPadKeyMask,     0xB6,  /* KP_6 */
154   0x59|NSNumericPadKeyMask,     0xB7,  /* KP_7 */
155   0x5B|NSNumericPadKeyMask,     0xB8,  /* KP_8 */
156   0x5C|NSNumericPadKeyMask,     0xB9,  /* KP_9 */
158   0x1B,                         0x1B   /* escape */
161 static Lisp_Object Qmodifier_value;
162 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
163 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
165 static Lisp_Object QUTF8_STRING;
167 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
168    the maximum font size to NOT antialias.  On GNUstep there is currently
169    no way to control this behavior. */
170 float ns_antialias_threshold;
172 /* Used to pick up AppleHighlightColor on OS X */
173 NSString *ns_selection_color;
175 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
176 NSString *ns_app_name = @"Emacs";  /* default changed later */
178 /* Display variables */
179 struct ns_display_info *x_display_list; /* Chain of existing displays */
180 Lisp_Object ns_display_name_list;
181 long context_menu_value = 0;
183 /* display update */
184 NSPoint last_mouse_motion_position;
185 static NSRect last_mouse_glyph;
186 static Time last_mouse_movement_time = 0;
187 static Lisp_Object last_mouse_motion_frame;
188 static EmacsScroller *last_mouse_scroll_bar = nil;
189 static struct frame *ns_updating_frame;
190 static NSView *focus_view = NULL;
191 static int ns_window_num = 0;
192 #ifdef NS_IMPL_GNUSTEP
193 static NSRect uRect;
194 #endif
195 static BOOL gsaved = NO;
196 static BOOL ns_fake_keydown = NO;
197 int ns_tmp_flags; /* FIXME */
198 struct nsfont_info *ns_tmp_font; /* FIXME */
199 static BOOL ns_menu_bar_is_hidden = NO;
200 /*static int debug_lock = 0; */
202 /* event loop */
203 static BOOL send_appdefined = YES;
204 #define NO_APPDEFINED_DATA (-8)
205 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
206 static NSTimer *timed_entry = 0;
207 static NSTimer *scroll_repeat_entry = nil;
208 static fd_set select_readfds, select_writefds;
209 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
210 static int select_nfds = 0, select_valid = 0;
211 static EMACS_TIME select_timeout = { 0, 0 };
212 static int selfds[2] = { -1, -1 };
213 static pthread_mutex_t select_mutex;
214 static int apploopnr = 0;
215 static NSAutoreleasePool *outerpool;
216 static struct input_event *emacs_event = NULL;
217 static struct input_event *q_event_ptr = NULL;
218 static int n_emacs_events_pending = 0;
219 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
220   *ns_pending_service_args;
221 static BOOL ns_do_open_file = NO;
222 static BOOL ns_last_use_native_fullscreen;
224 static struct {
225   struct input_event *q;
226   int nr, cap;
227 } hold_event_q = {
228   NULL, 0, 0
231 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
232 #define NS_FUNCTION_KEY_MASK 0x800000
233 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
234 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
235 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
236 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
237 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
238 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
239 #define EV_MODIFIERS(e)                               \
240     ((([e modifierFlags] & NSHelpKeyMask) ?           \
241            hyper_modifier : 0)                        \
242      | (!EQ (ns_right_alternate_modifier, Qleft) && \
243         (([e modifierFlags] & NSRightAlternateKeyMask) \
244          == NSRightAlternateKeyMask) ? \
245            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
246      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
247            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
248      | (([e modifierFlags] & NSShiftKeyMask) ?     \
249            shift_modifier : 0)                        \
250      | (!EQ (ns_right_control_modifier, Qleft) && \
251         (([e modifierFlags] & NSRightControlKeyMask) \
252          == NSRightControlKeyMask) ? \
253            parse_solitary_modifier (ns_right_control_modifier) : 0) \
254      | (([e modifierFlags] & NSControlKeyMask) ?      \
255            parse_solitary_modifier (ns_control_modifier) : 0)     \
256      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
257            parse_solitary_modifier (ns_function_modifier) : 0)    \
258      | (!EQ (ns_right_command_modifier, Qleft) && \
259         (([e modifierFlags] & NSRightCommandKeyMask) \
260          == NSRightCommandKeyMask) ? \
261            parse_solitary_modifier (ns_right_command_modifier) : 0) \
262      | (([e modifierFlags] & NSCommandKeyMask) ?      \
263            parse_solitary_modifier (ns_command_modifier):0))
265 #define EV_UDMODIFIERS(e)                                      \
266     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
267      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
268      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
269      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
270      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
271      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
272      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
273      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
274      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
276 #define EV_BUTTON(e)                                                         \
277     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
278       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
279      [e buttonNumber] - 1)
281 /* Convert the time field to a timestamp in milliseconds. */
282 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
284 /* This is a piece of code which is common to all the event handling
285    methods.  Maybe it should even be a function.  */
286 #define EV_TRAILER(e)                                                   \
287     {                                                                   \
288       XSETFRAME (emacs_event->frame_or_window, emacsframe);             \
289       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
290       if (q_event_ptr)                                                  \
291         {                                                               \
292           n_emacs_events_pending++;                                     \
293           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
294         }                                                               \
295       else                                                              \
296         hold_event (emacs_event);                                       \
297       EVENT_INIT (*emacs_event);                                        \
298       ns_send_appdefined (-1);                                          \
299     }
301 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
303 /* TODO: get rid of need for these forward declarations */
304 static void ns_condemn_scroll_bars (struct frame *f);
305 static void ns_judge_scroll_bars (struct frame *f);
306 void x_set_frame_alpha (struct frame *f);
309 /* ==========================================================================
311     Utilities
313    ========================================================================== */
315 static void
316 hold_event (struct input_event *event)
318   if (hold_event_q.nr == hold_event_q.cap)
319     {
320       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
321       else hold_event_q.cap *= 2;
322       hold_event_q.q = (struct input_event *)
323         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof (*hold_event_q.q));
324     }
326   hold_event_q.q[hold_event_q.nr++] = *event;
327   /* Make sure ns_read_socket is called, i.e. we have input.  */
328   raise (SIGIO);
329   send_appdefined = YES;
332 static Lisp_Object
333 append2 (Lisp_Object list, Lisp_Object item)
334 /* --------------------------------------------------------------------------
335    Utility to append to a list
336    -------------------------------------------------------------------------- */
338   Lisp_Object array[2];
339   array[0] = list;
340   array[1] = Fcons (item, Qnil);
341   return Fnconc (2, &array[0]);
345 const char *
346 ns_etc_directory (void)
347 /* If running as a self-contained app bundle, return as a string the
348    filename of the etc directory, if present; else nil.  */
350   NSBundle *bundle = [NSBundle mainBundle];
351   NSString *resourceDir = [bundle resourcePath];
352   NSString *resourcePath;
353   NSFileManager *fileManager = [NSFileManager defaultManager];
354   BOOL isDir;
356   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
357   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
358     {
359       if (isDir) return [resourcePath UTF8String];
360     }
361   return NULL;
365 const char *
366 ns_exec_path (void)
367 /* If running as a self-contained app bundle, return as a path string
368    the filenames of the libexec and bin directories, ie libexec:bin.
369    Otherwise, return nil.
370    Normally, Emacs does not add its own bin/ directory to the PATH.
371    However, a self-contained NS build has a different layout, with
372    bin/ and libexec/ subdirectories in the directory that contains
373    Emacs.app itself.
374    We put libexec first, because init_callproc_1 uses the first
375    element to initialize exec-directory.  An alternative would be
376    for init_callproc to check for invocation-directory/libexec.
379   NSBundle *bundle = [NSBundle mainBundle];
380   NSString *resourceDir = [bundle resourcePath];
381   NSString *binDir = [bundle bundlePath];
382   NSString *resourcePath, *resourcePaths;
383   NSRange range;
384   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
385   NSFileManager *fileManager = [NSFileManager defaultManager];
386   NSArray *paths;
387   NSEnumerator *pathEnum;
388   BOOL isDir;
390   range = [resourceDir rangeOfString: @"Contents"];
391   if (range.location != NSNotFound)
392     {
393       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
394 #ifdef NS_IMPL_COCOA
395       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
396 #endif
397     }
399   paths = [binDir stringsByAppendingPaths:
400                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
401   pathEnum = [paths objectEnumerator];
402   resourcePaths = @"";
404   while ((resourcePath = [pathEnum nextObject]))
405     {
406       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
407         if (isDir)
408           {
409             if ([resourcePaths length] > 0)
410               resourcePaths
411                 = [resourcePaths stringByAppendingString: pathSeparator];
412             resourcePaths
413               = [resourcePaths stringByAppendingString: resourcePath];
414           }
415     }
416   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
418   return NULL;
422 const char *
423 ns_load_path (void)
424 /* If running as a self-contained app bundle, return as a path string
425    the filenames of the site-lisp, lisp and leim directories.
426    Ie, site-lisp:lisp:leim.  Otherwise, return nil.  */
428   NSBundle *bundle = [NSBundle mainBundle];
429   NSString *resourceDir = [bundle resourcePath];
430   NSString *resourcePath, *resourcePaths;
431   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
432   NSFileManager *fileManager = [NSFileManager defaultManager];
433   BOOL isDir;
434   NSArray *paths = [resourceDir stringsByAppendingPaths:
435                               [NSArray arrayWithObjects:
436                                          @"site-lisp", @"lisp", @"leim", nil]];
437   NSEnumerator *pathEnum = [paths objectEnumerator];
438   resourcePaths = @"";
440   /* Hack to skip site-lisp.  */
441   if (no_site_lisp) resourcePath = [pathEnum nextObject];
443   while ((resourcePath = [pathEnum nextObject]))
444     {
445       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
446         if (isDir)
447           {
448             if ([resourcePaths length] > 0)
449               resourcePaths
450                 = [resourcePaths stringByAppendingString: pathSeparator];
451             resourcePaths
452               = [resourcePaths stringByAppendingString: resourcePath];
453           }
454     }
455   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
457   return NULL;
460 static void
461 ns_timeout (int usecs)
462 /* --------------------------------------------------------------------------
463      Blocking timer utility used by ns_ring_bell
464    -------------------------------------------------------------------------- */
466   EMACS_TIME wakeup = add_emacs_time (current_emacs_time (),
467                                       make_emacs_time (0, usecs * 1000));
469   /* Keep waiting until past the time wakeup.  */
470   while (1)
471     {
472       EMACS_TIME timeout, now = current_emacs_time ();
473       if (EMACS_TIME_LE (wakeup, now))
474         break;
475       timeout = sub_emacs_time (wakeup, now);
477       /* Try to wait that long--but we might wake up sooner.  */
478       pselect (0, NULL, NULL, NULL, &timeout, NULL);
479     }
483 void
484 ns_release_object (void *obj)
485 /* --------------------------------------------------------------------------
486     Release an object (callable from C)
487    -------------------------------------------------------------------------- */
489     [(id)obj release];
493 void
494 ns_retain_object (void *obj)
495 /* --------------------------------------------------------------------------
496     Retain an object (callable from C)
497    -------------------------------------------------------------------------- */
499     [(id)obj retain];
503 void *
504 ns_alloc_autorelease_pool (void)
505 /* --------------------------------------------------------------------------
506      Allocate a pool for temporary objects (callable from C)
507    -------------------------------------------------------------------------- */
509   return [[NSAutoreleasePool alloc] init];
513 void
514 ns_release_autorelease_pool (void *pool)
515 /* --------------------------------------------------------------------------
516      Free a pool and temporary objects it refers to (callable from C)
517    -------------------------------------------------------------------------- */
519   ns_release_object (pool);
524 /* ==========================================================================
526     Focus (clipping) and screen update
528    ========================================================================== */
531 // Window constraining
532 // -------------------
534 // To ensure that the windows are not placed under the menu bar, they
535 // are typically moved by the call-back constrainFrameRect. However,
536 // by overriding it, it's possible to inhibit this, leaving the window
537 // in it's original position.
539 // It's possible to hide the menu bar. However, technically, it's only
540 // possible to hide it when the application is active. To ensure that
541 // this work properly, the menu bar and window constraining are
542 // deferred until the application becomes active.
544 // Even though it's not possible to manually move a window above the
545 // top of the screen, it is allowed if it's done programmatically,
546 // when the menu is hidden. This allows the editable area to cover the
547 // full screen height.
549 // Test cases
550 // ----------
552 // Use the following extra files:
554 //    init.el:
555 //       ;; Hide menu and place frame slightly above the top of the screen.
556 //       (setq ns-auto-hide-menu-bar t)
557 //       (set-frame-position (selected-frame) 0 -20)
559 // Test 1:
561 //    emacs -Q -l init.el
563 //    Result: No menu bar, and the title bar should be above the screen.
565 // Test 2:
567 //    emacs -Q
569 //    Result: Menu bar visible, frame placed immediately below the menu.
572 static void
573 ns_constrain_all_frames (void)
575   Lisp_Object tail, frame;
577   FOR_EACH_FRAME (tail, frame)
578     {
579       struct frame *f = XFRAME (frame);
580       if (FRAME_NS_P (f))
581         {
582           NSView *view = FRAME_NS_VIEW (f);
583           /* This no-op will trigger the default window placing
584            * constraint system. */
585           f->output_data.ns->dont_constrain = 0;
586           [[view window] setFrameOrigin:[[view window] frame].origin];
587         }
588     }
592 /* True, if the menu bar should be hidden.  */
594 static BOOL
595 ns_menu_bar_should_be_hidden (void)
597   return !NILP (ns_auto_hide_menu_bar)
598     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
602 /* Show or hide the menu bar, based on user setting.  */
604 static void
605 ns_update_auto_hide_menu_bar (void)
607 #ifdef NS_IMPL_COCOA
608 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
609   block_input ();
611   NSTRACE (ns_update_auto_hide_menu_bar);
613   if (NSApp != nil
614       && [NSApp isActive]
615       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
616     {
617       // Note, "setPresentationOptions" triggers an error unless the
618       // application is active.
619       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
621       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
622         {
623           NSApplicationPresentationOptions options
624             = NSApplicationPresentationAutoHideDock;
626           if (menu_bar_should_be_hidden)
627             options |= NSApplicationPresentationAutoHideMenuBar;
629           [NSApp setPresentationOptions: options];
631           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
633           if (!ns_menu_bar_is_hidden)
634             {
635               ns_constrain_all_frames ();
636             }
637         }
638     }
640   unblock_input ();
641 #endif
642 #endif
646 static void
647 ns_update_begin (struct frame *f)
648 /* --------------------------------------------------------------------------
649    Prepare for a grouped sequence of drawing calls
650    external (RIF) call; whole frame, called before update_window_begin
651    -------------------------------------------------------------------------- */
653   NSView *view = FRAME_NS_VIEW (f);
654   NSRect r = [view frame];
655   NSBezierPath *bp;
656   NSTRACE (ns_update_begin);
658   ns_update_auto_hide_menu_bar ();
660   ns_updating_frame = f;
661   [view lockFocus];
663   /* drawRect may have been called for say the minibuffer, and then clip path
664      is for the minibuffer.  But the display engine may draw more because
665      we have set the frame as garbaged.  So reset clip path to the whole
666      view.  */
667   bp = [[NSBezierPath bezierPathWithRect: r] retain];
668   [bp setClip];
669   [bp release];
671 #ifdef NS_IMPL_GNUSTEP
672   uRect = NSMakeRect (0, 0, 0, 0);
673 #endif
677 static void
678 ns_update_window_begin (struct window *w)
679 /* --------------------------------------------------------------------------
680    Prepare for a grouped sequence of drawing calls
681    external (RIF) call; for one window, called after update_begin
682    -------------------------------------------------------------------------- */
684   struct frame *f = XFRAME (WINDOW_FRAME (w));
685  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
686   NSTRACE (ns_update_window_begin);
687   updated_window = w;
688   set_output_cursor (&w->cursor);
690   block_input ();
692   if (f == hlinfo->mouse_face_mouse_frame)
693     {
694       /* Don't do highlighting for mouse motion during the update.  */
695       hlinfo->mouse_face_defer = 1;
697         /* If the frame needs to be redrawn,
698            simply forget about any prior mouse highlighting.  */
699       if (FRAME_GARBAGED_P (f))
700         hlinfo->mouse_face_window = Qnil;
702       /* (further code for mouse faces ifdef'd out in other terms elided) */
703     }
705   unblock_input ();
709 static void
710 ns_update_window_end (struct window *w, int cursor_on_p,
711                       int mouse_face_overwritten_p)
712 /* --------------------------------------------------------------------------
713    Finished a grouped sequence of drawing calls
714    external (RIF) call; for one window called before update_end
715    -------------------------------------------------------------------------- */
717   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
719   /* note: this fn is nearly identical in all terms */
720   if (!w->pseudo_window_p)
721     {
722       block_input ();
724       if (cursor_on_p)
725         display_and_set_cursor (w, 1,
726                                 output_cursor.hpos, output_cursor.vpos,
727                                 output_cursor.x, output_cursor.y);
729       if (draw_window_fringes (w, 1))
730         x_draw_vertical_border (w);
732       unblock_input ();
733     }
735   /* If a row with mouse-face was overwritten, arrange for
736      frame_up_to_date to redisplay the mouse highlight.  */
737   if (mouse_face_overwritten_p)
738     {
739       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
740       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
741       hlinfo->mouse_face_window = Qnil;
742     }
744   updated_window = NULL;
745   NSTRACE (update_window_end);
749 static void
750 ns_update_end (struct frame *f)
751 /* --------------------------------------------------------------------------
752    Finished a grouped sequence of drawing calls
753    external (RIF) call; for whole frame, called after update_window_end
754    -------------------------------------------------------------------------- */
756   NSView *view = FRAME_NS_VIEW (f);
758 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
759     MOUSE_HL_INFO (f)->mouse_face_defer = 0;
761     block_input ();
763 #ifdef NS_IMPL_GNUSTEP
764   /* trigger flush only in the rectangle we tracked as being drawn */
765   [view unlockFocusNeedsFlush: NO];
766 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
767   [view lockFocusInRect: uRect];
768 #endif
770   [view unlockFocus];
771   [[view window] flushWindow];
773   unblock_input ();
774   ns_updating_frame = NULL;
775   NSTRACE (ns_update_end);
779 static void
780 ns_flush (struct frame *f)
781 /* --------------------------------------------------------------------------
782    external (RIF) call
783    NS impl is no-op since currently we flush in ns_update_end and elsewhere
784    -------------------------------------------------------------------------- */
786     NSTRACE (ns_flush);
790 static void
791 ns_focus (struct frame *f, NSRect *r, int n)
792 /* --------------------------------------------------------------------------
793    Internal: Focus on given frame.  During small local updates this is used to
794      draw, however during large updates, ns_update_begin and ns_update_end are
795      called to wrap the whole thing, in which case these calls are stubbed out.
796      Except, on GNUstep, we accumulate the rectangle being drawn into, because
797      the back end won't do this automatically, and will just end up flushing
798      the entire window.
799    -------------------------------------------------------------------------- */
801 //  NSTRACE (ns_focus);
802 #ifdef NS_IMPL_GNUSTEP
803   NSRect u;
804     if (n == 2)
805       u = NSUnionRect (r[0], r[1]);
806     else if (r)
807       u = *r;
808 #endif
809 /* static int c =0;
810    fprintf (stderr, "focus: %d", c++);
811    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
812    fprintf (stderr, "\n"); */
814   if (f != ns_updating_frame)
815     {
816       NSView *view = FRAME_NS_VIEW (f);
817       if (view != focus_view)
818         {
819           if (focus_view != NULL)
820             {
821               [focus_view unlockFocus];
822               [[focus_view window] flushWindow];
823 /*debug_lock--; */
824             }
826           if (view)
827 #ifdef NS_IMPL_GNUSTEP
828             r ? [view lockFocusInRect: u] : [view lockFocus];
829 #else
830             [view lockFocus];
831 #endif
832           focus_view = view;
833 /*if (view) debug_lock++; */
834         }
835 #ifdef NS_IMPL_GNUSTEP
836       else
837         {
838           /* more than one rect being drawn into */
839           if (view && r)
840             {
841               [view unlockFocus]; /* add prev rect to redraw list */
842               [view lockFocusInRect: u]; /* focus for draw in new rect */
843             }
844         }
845 #endif
846     }
847 #ifdef NS_IMPL_GNUSTEP
848   else
849     {
850       /* in batch mode, but in GNUstep must still track rectangles explicitly */
851       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
852     }
853 #endif
855   /* clipping */
856   if (r)
857     {
858       [[NSGraphicsContext currentContext] saveGraphicsState];
859       if (n == 2)
860         NSRectClipList (r, 2);
861       else
862         NSRectClip (*r);
863       gsaved = YES;
864     }
868 static void
869 ns_unfocus (struct frame *f)
870 /* --------------------------------------------------------------------------
871      Internal: Remove focus on given frame
872    -------------------------------------------------------------------------- */
874 //  NSTRACE (ns_unfocus);
876   if (gsaved)
877     {
878       [[NSGraphicsContext currentContext] restoreGraphicsState];
879       gsaved = NO;
880     }
882   if (f != ns_updating_frame)
883     {
884       if (focus_view != NULL)
885         {
886           [focus_view unlockFocus];
887           [[focus_view window] flushWindow];
888           focus_view = NULL;
889 /*debug_lock--; */
890         }
891     }
895 static void
896 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
897 /* --------------------------------------------------------------------------
898      Internal (but parallels other terms): Focus drawing on given row
899    -------------------------------------------------------------------------- */
901   struct frame *f = XFRAME (WINDOW_FRAME (w));
902   NSRect clip_rect;
903   int window_x, window_y, window_width;
905   window_box (w, area, &window_x, &window_y, &window_width, 0);
907   clip_rect.origin.x = window_x;
908   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
909   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
910   clip_rect.size.width = window_width;
911   clip_rect.size.height = row->visible_height;
913   ns_focus (f, &clip_rect, 1);
917 static void
918 ns_ring_bell (struct frame *f)
919 /* --------------------------------------------------------------------------
920      "Beep" routine
921    -------------------------------------------------------------------------- */
923   NSTRACE (ns_ring_bell);
924   if (visible_bell)
925     {
926       NSAutoreleasePool *pool;
927       struct frame *frame = SELECTED_FRAME ();
928       NSView *view;
930       block_input ();
931       pool = [[NSAutoreleasePool alloc] init];
933       view = FRAME_NS_VIEW (frame);
934       if (view != nil)
935         {
936           NSRect r, surr;
937           NSPoint dim = NSMakePoint (128, 128);
939           r = [view bounds];
940           r.origin.x += (r.size.width - dim.x) / 2;
941           r.origin.y += (r.size.height - dim.y) / 2;
942           r.size.width = dim.x;
943           r.size.height = dim.y;
944           surr = NSInsetRect (r, -2, -2);
945           ns_focus (frame, &surr, 1);
946           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
947           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
948                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
949           NSRectFill (r);
950           [[view window] flushWindow];
951           ns_timeout (150000);
952           [[view window] restoreCachedImage];
953           [[view window] flushWindow];
954           ns_unfocus (frame);
955         }
956       [pool release];
957       unblock_input ();
958     }
959   else
960     {
961       NSBeep ();
962     }
966 static void
967 ns_reset_terminal_modes (struct terminal *terminal)
968 /*  Externally called as hook */
970   NSTRACE (ns_reset_terminal_modes);
974 static void
975 ns_set_terminal_modes (struct terminal *terminal)
976 /*  Externally called as hook */
978   NSTRACE (ns_set_terminal_modes);
983 /* ==========================================================================
985     Frame / window manager related functions
987    ========================================================================== */
990 static void
991 ns_raise_frame (struct frame *f)
992 /* --------------------------------------------------------------------------
993      Bring window to foreground and make it active
994    -------------------------------------------------------------------------- */
996   NSView *view = FRAME_NS_VIEW (f);
997   check_ns ();
998   block_input ();
999   if (FRAME_VISIBLE_P (f))
1000     [[view window] makeKeyAndOrderFront: NSApp];
1001   unblock_input ();
1005 static void
1006 ns_lower_frame (struct frame *f)
1007 /* --------------------------------------------------------------------------
1008      Send window to back
1009    -------------------------------------------------------------------------- */
1011   NSView *view = FRAME_NS_VIEW (f);
1012   check_ns ();
1013   block_input ();
1014   [[view window] orderBack: NSApp];
1015   unblock_input ();
1019 static void
1020 ns_frame_raise_lower (struct frame *f, int raise)
1021 /* --------------------------------------------------------------------------
1022      External (hook)
1023    -------------------------------------------------------------------------- */
1025   NSTRACE (ns_frame_raise_lower);
1027   if (raise)
1028     ns_raise_frame (f);
1029   else
1030     ns_lower_frame (f);
1034 static void
1035 ns_frame_rehighlight (struct frame *frame)
1036 /* --------------------------------------------------------------------------
1037      External (hook): called on things like window switching within frame
1038    -------------------------------------------------------------------------- */
1040   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1041   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1043   NSTRACE (ns_frame_rehighlight);
1044   if (dpyinfo->x_focus_frame)
1045     {
1046       dpyinfo->x_highlight_frame
1047         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1048            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1049            : dpyinfo->x_focus_frame);
1050       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1051         {
1052           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1053           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1054         }
1055     }
1056   else
1057       dpyinfo->x_highlight_frame = 0;
1059   if (dpyinfo->x_highlight_frame &&
1060          dpyinfo->x_highlight_frame != old_highlight)
1061     {
1062       if (old_highlight)
1063         {
1064           x_update_cursor (old_highlight, 1);
1065           x_set_frame_alpha (old_highlight);
1066         }
1067       if (dpyinfo->x_highlight_frame)
1068         {
1069           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1070           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1071         }
1072     }
1076 void
1077 x_make_frame_visible (struct frame *f)
1078 /* --------------------------------------------------------------------------
1079      External: Show the window (X11 semantics)
1080    -------------------------------------------------------------------------- */
1082   NSTRACE (x_make_frame_visible);
1083   /* XXX: at some points in past this was not needed, as the only place that
1084      called this (frame.c:Fraise_frame ()) also called raise_lower;
1085      if this ends up the case again, comment this out again. */
1086   if (!FRAME_VISIBLE_P (f))
1087     {
1088       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1090       SET_FRAME_VISIBLE (f, 1);
1091       ns_raise_frame (f);
1093       /* Making a new frame from a fullscreen frame will make the new frame
1094          fullscreen also.  So skip handleFS as this will print an error.  */
1095       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1096           && [view isFullscreen])
1097         return;
1099       if (f->want_fullscreen != FULLSCREEN_NONE)
1100         {
1101           block_input ();
1102           [view handleFS];
1103           unblock_input ();
1104         }
1105     }
1109 void
1110 x_make_frame_invisible (struct frame *f)
1111 /* --------------------------------------------------------------------------
1112      External: Hide the window (X11 semantics)
1113    -------------------------------------------------------------------------- */
1115   NSView * view = FRAME_NS_VIEW (f);
1116   NSTRACE (x_make_frame_invisible);
1117   check_ns ();
1118   [[view window] orderOut: NSApp];
1119   SET_FRAME_VISIBLE (f, 0);
1120   SET_FRAME_ICONIFIED (f, 0);
1124 void
1125 x_iconify_frame (struct frame *f)
1126 /* --------------------------------------------------------------------------
1127      External: Iconify window
1128    -------------------------------------------------------------------------- */
1130   NSView * view = FRAME_NS_VIEW (f);
1131   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1132   NSTRACE (x_iconify_frame);
1133   check_ns ();
1135   if (dpyinfo->x_highlight_frame == f)
1136     dpyinfo->x_highlight_frame = 0;
1138   if ([[view window] windowNumber] <= 0)
1139     {
1140       /* the window is still deferred.  Make it very small, bring it
1141          on screen and order it out. */
1142       NSRect s = { { 100, 100}, {0, 0} };
1143       NSRect t;
1144       t = [[view window] frame];
1145       [[view window] setFrame: s display: NO];
1146       [[view window] orderBack: NSApp];
1147       [[view window] orderOut: NSApp];
1148       [[view window] setFrame: t display: NO];
1149     }
1150   [[view window] miniaturize: NSApp];
1153 /* Free X resources of frame F.  */
1155 void
1156 x_free_frame_resources (struct frame *f)
1158   NSView *view = FRAME_NS_VIEW (f);
1159   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1160   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1161   NSTRACE (x_free_frame_resources);
1162   check_ns ();
1164   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1166   block_input ();
1168   free_frame_menubar (f);
1170   if (FRAME_FACE_CACHE (f))
1171     free_frame_faces (f);
1173   if (f == dpyinfo->x_focus_frame)
1174     dpyinfo->x_focus_frame = 0;
1175   if (f == dpyinfo->x_highlight_frame)
1176     dpyinfo->x_highlight_frame = 0;
1177   if (f == hlinfo->mouse_face_mouse_frame)
1178     {
1179       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1180       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1181       hlinfo->mouse_face_window = Qnil;
1182       hlinfo->mouse_face_mouse_frame = 0;
1183     }
1185   if (f->output_data.ns->miniimage != nil)
1186     [f->output_data.ns->miniimage release];
1188   [[view window] close];
1189   [view release];
1191   xfree (f->output_data.ns);
1193   unblock_input ();
1196 void
1197 x_destroy_window (struct frame *f)
1198 /* --------------------------------------------------------------------------
1199      External: Delete the window
1200    -------------------------------------------------------------------------- */
1202   NSTRACE (x_destroy_window);
1203   check_ns ();
1204   x_free_frame_resources (f);
1205   ns_window_num--;
1209 void
1210 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1211 /* --------------------------------------------------------------------------
1212      External: Position the window
1213    -------------------------------------------------------------------------- */
1215   NSView *view = FRAME_NS_VIEW (f);
1216   NSArray *screens = [NSScreen screens];
1217   NSScreen *fscreen = [screens objectAtIndex: 0];
1218   NSScreen *screen = [[view window] screen];
1220   NSTRACE (x_set_offset);
1222   block_input ();
1224   f->left_pos = xoff;
1225   f->top_pos = yoff;
1227   if (view != nil && screen && fscreen)
1228     {
1229       f->left_pos = f->size_hint_flags & XNegative
1230         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1231         : f->left_pos;
1232       /* We use visibleFrame here to take menu bar into account.
1233          Ideally we should also adjust left/top with visibleFrame.origin.  */
1235       f->top_pos = f->size_hint_flags & YNegative
1236         ? ([screen visibleFrame].size.height + f->top_pos
1237            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1238            - FRAME_TOOLBAR_HEIGHT (f))
1239         : f->top_pos;
1240 #ifdef NS_IMPL_GNUSTEP
1241       if (f->left_pos < 100)
1242         f->left_pos = 100;  /* don't overlap menu */
1243 #endif
1244       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1245          menu bar.  */
1246       f->output_data.ns->dont_constrain = 0;
1247       [[view window] setFrameTopLeftPoint:
1248                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1249                                     SCREENMAXBOUND ([fscreen frame].size.height
1250                                                     - NS_TOP_POS (f)))];
1251       f->size_hint_flags &= ~(XNegative|YNegative);
1252     }
1254   unblock_input ();
1258 void
1259 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1260 /* --------------------------------------------------------------------------
1261      Adjust window pixel size based on given character grid size
1262      Impl is a bit more complex than other terms, need to do some
1263      internal clipping.
1264    -------------------------------------------------------------------------- */
1266   EmacsView *view = FRAME_NS_VIEW (f);
1267   NSWindow *window = [view window];
1268   NSRect wr = [window frame];
1269   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1270   int pixelwidth, pixelheight;
1272   NSTRACE (x_set_window_size);
1274   if (view == nil)
1275     return;
1277 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1279   block_input ();
1281   check_frame_size (f, &rows, &cols);
1283   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1284   compute_fringe_widths (f, 0);
1286   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1287   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1289   /* If we have a toolbar, take its height into account. */
1290   if (tb && ! [view isFullscreen])
1291     /* NOTE: previously this would generate wrong result if toolbar not
1292              yet displayed and fixing toolbar_height=32 helped, but
1293              now (200903) seems no longer needed */
1294     FRAME_TOOLBAR_HEIGHT (f) =
1295       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1296         - FRAME_NS_TITLEBAR_HEIGHT (f);
1297   else
1298     FRAME_TOOLBAR_HEIGHT (f) = 0;
1300   wr.size.width = pixelwidth + f->border_width;
1301   wr.size.height = pixelheight;
1302   if (! [view isFullscreen])
1303     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1304       + FRAME_TOOLBAR_HEIGHT (f);
1306   /* Do not try to constrain to this screen.  We may have multiple
1307      screens, and want Emacs to span those.  Constraining to screen
1308      prevents that, and that is not nice to the user.  */
1309  if (f->output_data.ns->zooming)
1310    f->output_data.ns->zooming = 0;
1311  else
1312    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1314   [view setRows: rows andColumns: cols];
1315   [window setFrame: wr display: YES];
1317 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1319   /* This is a trick to compensate for Emacs' managing the scrollbar area
1320      as a fixed number of standard character columns.  Instead of leaving
1321      blank space for the extra, we chopped it off above.  Now for
1322      left-hand scrollbars, we shift all rendering to the left by the
1323      difference between the real width and Emacs' imagined one.  For
1324      right-hand bars, don't worry about it since the extra is never used.
1325      (Obviously doesn't work for vertically split windows tho..) */
1326   {
1327     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1328       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1329                      - NS_SCROLL_BAR_WIDTH (f), 0)
1330       : NSMakePoint (0, 0);
1331     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1332     [view setBoundsOrigin: origin];
1333   }
1335   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1336   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1337   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1338 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1340   mark_window_cursors_off (XWINDOW (f->root_window));
1341   cancel_mouse_face (f);
1343   unblock_input ();
1347 static void
1348 ns_fullscreen_hook (FRAME_PTR f)
1350   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1352   if (!FRAME_VISIBLE_P (f))
1353     return;
1355    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1356     {
1357       /* Old style fs don't initiate correctly if created from
1358          init/default-frame alist, so use a timer (not nice...).
1359       */
1360       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1361                                      selector: @selector (handleFS)
1362                                      userInfo: nil repeats: NO];
1363       return;
1364     }
1366   block_input ();
1367   [view handleFS];
1368   unblock_input ();
1371 /* ==========================================================================
1373     Color management
1375    ========================================================================== */
1378 NSColor *
1379 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1381   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1382   if (idx < 1 || idx >= color_table->avail)
1383     return nil;
1384   return color_table->colors[idx];
1388 unsigned long
1389 ns_index_color (NSColor *color, struct frame *f)
1391   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1392   ptrdiff_t idx;
1393   ptrdiff_t i;
1395   if (!color_table->colors)
1396     {
1397       color_table->size = NS_COLOR_CAPACITY;
1398       color_table->avail = 1; /* skip idx=0 as marker */
1399       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1400       color_table->colors[0] = nil;
1401       color_table->empty_indices = [[NSMutableSet alloc] init];
1402     }
1404   /* do we already have this color ? */
1405   for (i = 1; i < color_table->avail; i++)
1406     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1407       return i;
1409   if ([color_table->empty_indices count] > 0)
1410     {
1411       NSNumber *index = [color_table->empty_indices anyObject];
1412       [color_table->empty_indices removeObject: index];
1413       idx = [index unsignedLongValue];
1414     }
1415   else
1416     {
1417       if (color_table->avail == color_table->size)
1418         color_table->colors =
1419           xpalloc (color_table->colors, &color_table->size, 1,
1420                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1421       idx = color_table->avail++;
1422     }
1424   color_table->colors[idx] = color;
1425   [color retain];
1426 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1427   return idx;
1431 void
1432 ns_free_indexed_color (unsigned long idx, struct frame *f)
1434   struct ns_color_table *color_table;
1435   NSColor *color;
1436   NSNumber *index;
1438   if (!f)
1439     return;
1441   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1443   if (idx <= 0 || idx >= color_table->size) {
1444     message1 ("ns_free_indexed_color: Color index out of range.\n");
1445     return;
1446   }
1448   index = [NSNumber numberWithUnsignedInt: idx];
1449   if ([color_table->empty_indices containsObject: index]) {
1450     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1451     return;
1452   }
1454   color = color_table->colors[idx];
1455   [color release];
1456   color_table->colors[idx] = nil;
1457   [color_table->empty_indices addObject: index];
1458 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1462 static int
1463 ns_get_color (const char *name, NSColor **col)
1464 /* --------------------------------------------------------------------------
1465      Parse a color name
1466    -------------------------------------------------------------------------- */
1467 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1468    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1469    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1471   NSColor *new = nil;
1472   static char hex[20];
1473   int scaling;
1474   float r = -1.0, g, b;
1475   NSString *nsname = [NSString stringWithUTF8String: name];
1477 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1478   block_input ();
1480   if ([nsname isEqualToString: @"ns_selection_color"])
1481     {
1482       nsname = ns_selection_color;
1483       name = [ns_selection_color UTF8String];
1484     }
1486   /* First, check for some sort of numeric specification. */
1487   hex[0] = '\0';
1489   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1490     {
1491       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1492       [scanner scanFloat: &r];
1493       [scanner scanFloat: &g];
1494       [scanner scanFloat: &b];
1495     }
1496   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1497     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1498   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1499     {
1500       int len = (strlen(name) - 1);
1501       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1502       int i;
1503       scaling = strlen(name+start) / 3;
1504       for (i = 0; i < 3; i++)
1505         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1506                  name + start + i * scaling);
1507       hex[3 * (scaling + 1) - 1] = '\0';
1508     }
1510   if (hex[0])
1511     {
1512       int rr, gg, bb;
1513       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1514       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1515         {
1516           r = rr / fscale;
1517           g = gg / fscale;
1518           b = bb / fscale;
1519         }
1520     }
1522   if (r >= 0.0)
1523     {
1524       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1525       unblock_input ();
1526       return 0;
1527     }
1529   /* Otherwise, color is expected to be from a list */
1530   {
1531     NSEnumerator *lenum, *cenum;
1532     NSString *name;
1533     NSColorList *clist;
1535 #ifdef NS_IMPL_GNUSTEP
1536     /* XXX: who is wrong, the requestor or the implementation? */
1537     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1538         == NSOrderedSame)
1539       nsname = @"highlightColor";
1540 #endif
1542     lenum = [[NSColorList availableColorLists] objectEnumerator];
1543     while ( (clist = [lenum nextObject]) && new == nil)
1544       {
1545         cenum = [[clist allKeys] objectEnumerator];
1546         while ( (name = [cenum nextObject]) && new == nil )
1547           {
1548             if ([name compare: nsname
1549                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1550               new = [clist colorWithKey: name];
1551           }
1552       }
1553   }
1555   if (new)
1556     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1557   unblock_input ();
1558   return new ? 0 : 1;
1563 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1564 /* --------------------------------------------------------------------------
1565      Convert a Lisp string object to a NS color
1566    -------------------------------------------------------------------------- */
1568   NSTRACE (ns_lisp_to_color);
1569   if (STRINGP (color))
1570     return ns_get_color (SSDATA (color), col);
1571   else if (SYMBOLP (color))
1572     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1573   return 1;
1577 Lisp_Object
1578 ns_color_to_lisp (NSColor *col)
1579 /* --------------------------------------------------------------------------
1580      Convert a color to a lisp string with the RGB equivalent
1581    -------------------------------------------------------------------------- */
1583   CGFloat red, green, blue, alpha, gray;
1584   char buf[1024];
1585   const char *str;
1586   NSTRACE (ns_color_to_lisp);
1588   block_input ();
1589   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1591       if ((str =[[col colorNameComponent] UTF8String]))
1592         {
1593           unblock_input ();
1594           return build_string ((char *)str);
1595         }
1597     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1598         getRed: &red green: &green blue: &blue alpha: &alpha];
1599   if (red ==green && red ==blue)
1600     {
1601       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1602             getWhite: &gray alpha: &alpha];
1603       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1604                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1605       unblock_input ();
1606       return build_string (buf);
1607     }
1609   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1610             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1612   unblock_input ();
1613   return build_string (buf);
1617 void
1618 ns_query_color(void *col, XColor *color_def, int setPixel)
1619 /* --------------------------------------------------------------------------
1620          Get ARGB values out of NSColor col and put them into color_def.
1621          If setPixel, set the pixel to a concatenated version.
1622          and set color_def pixel to the resulting index.
1623    -------------------------------------------------------------------------- */
1625   CGFloat r, g, b, a;
1627   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1628   color_def->red   = r * 65535;
1629   color_def->green = g * 65535;
1630   color_def->blue  = b * 65535;
1632   if (setPixel == YES)
1633     color_def->pixel
1634       = ARGB_TO_ULONG((int)(a*255),
1635                       (int)(r*255), (int)(g*255), (int)(b*255));
1639 bool
1640 ns_defined_color (struct frame *f,
1641                   const char *name,
1642                   XColor *color_def,
1643                   bool alloc,
1644                   bool makeIndex)
1645 /* --------------------------------------------------------------------------
1646          Return true if named color found, and set color_def rgb accordingly.
1647          If makeIndex and alloc are nonzero put the color in the color_table,
1648          and set color_def pixel to the resulting index.
1649          If makeIndex is zero, set color_def pixel to ARGB.
1650          Return false if not found
1651    -------------------------------------------------------------------------- */
1653   NSColor *col;
1654   NSTRACE (ns_defined_color);
1656   block_input ();
1657   if (ns_get_color (name, &col) != 0) /* Color not found  */
1658     {
1659       unblock_input ();
1660       return 0;
1661     }
1662   if (makeIndex && alloc)
1663     color_def->pixel = ns_index_color (col, f);
1664   ns_query_color (col, color_def, !makeIndex);
1665   unblock_input ();
1666   return 1;
1670 unsigned long
1671 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1672 /* --------------------------------------------------------------------------
1673     return an autoreleased RGB color
1674    -------------------------------------------------------------------------- */
1676 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1677   if (r < 0.0) r = 0.0;
1678   else if (r > 1.0) r = 1.0;
1679   if (g < 0.0) g = 0.0;
1680   else if (g > 1.0) g = 1.0;
1681   if (b < 0.0) b = 0.0;
1682   else if (b > 1.0) b = 1.0;
1683   if (a < 0.0) a = 0.0;
1684   else if (a > 1.0) a = 1.0;
1685   return (unsigned long) ns_index_color(
1686     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1690 void
1691 x_set_frame_alpha (struct frame *f)
1692 /* --------------------------------------------------------------------------
1693      change the entire-frame transparency
1694    -------------------------------------------------------------------------- */
1696   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1697   EmacsView *view = FRAME_NS_VIEW (f);
1698   double alpha = 1.0;
1699   double alpha_min = 1.0;
1701   if (dpyinfo->x_highlight_frame == f)
1702     alpha = f->alpha[0];
1703   else
1704     alpha = f->alpha[1];
1706   if (FLOATP (Vframe_alpha_lower_limit))
1707     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1708   else if (INTEGERP (Vframe_alpha_lower_limit))
1709     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1711   if (alpha < 0.0)
1712     return;
1713   else if (1.0 < alpha)
1714     alpha = 1.0;
1715   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1716     alpha = alpha_min;
1718 #ifdef NS_IMPL_COCOA
1719   [[view window] setAlphaValue: alpha];
1720 #endif
1724 /* ==========================================================================
1726     Mouse handling
1728    ========================================================================== */
1731 void
1732 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1733 /* --------------------------------------------------------------------------
1734      Programmatically reposition mouse pointer in pixel coordinates
1735    -------------------------------------------------------------------------- */
1737   NSTRACE (x_set_mouse_pixel_position);
1738   ns_raise_frame (f);
1739 #if 0
1740   /* FIXME: this does not work, and what about GNUstep? */
1741 #ifdef NS_IMPL_COCOA
1742   [FRAME_NS_VIEW (f) lockFocus];
1743   PSsetmouse ((float)pix_x, (float)pix_y);
1744   [FRAME_NS_VIEW (f) unlockFocus];
1745 #endif
1746 #endif
1750 void
1751 x_set_mouse_position (struct frame *f, int h, int v)
1752 /* --------------------------------------------------------------------------
1753      Programmatically reposition mouse pointer in character coordinates
1754    -------------------------------------------------------------------------- */
1756   int pix_x, pix_y;
1758   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1759   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1761   if (pix_x < 0) pix_x = 0;
1762   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1764   if (pix_y < 0) pix_y = 0;
1765   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1767   x_set_mouse_pixel_position (f, pix_x, pix_y);
1771 static int
1772 note_mouse_movement (struct frame *frame, float x, float y)
1773 /*   ------------------------------------------------------------------------
1774      Called by EmacsView on mouseMovement events.  Passes on
1775      to emacs mainstream code if we moved off of a rect of interest
1776      known as last_mouse_glyph.
1777      ------------------------------------------------------------------------ */
1779 //  NSTRACE (note_mouse_movement);
1781   XSETFRAME (last_mouse_motion_frame, frame);
1783   /* Note, this doesn't get called for enter/leave, since we don't have a
1784      position.  Those are taken care of in the corresponding NSView methods. */
1786   /* has movement gone beyond last rect we were tracking? */
1787   if (x < last_mouse_glyph.origin.x ||
1788       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1789       y < last_mouse_glyph.origin.y ||
1790       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1791     {
1792       ns_update_begin(frame);
1793       frame->mouse_moved = 1;
1794       note_mouse_highlight (frame, x, y);
1795       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1796       ns_update_end(frame);
1797       return 1;
1798     }
1800   return 0;
1804 static void
1805 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1806                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1807                    Time *time)
1808 /* --------------------------------------------------------------------------
1809     External (hook): inform emacs about mouse position and hit parts.
1810     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1811     x & y should be position in the scrollbar (the whole bar, not the handle)
1812     and length of scrollbar respectively
1813    -------------------------------------------------------------------------- */
1815   id view;
1816   NSPoint position;
1817   Lisp_Object frame, tail;
1818   struct frame *f;
1819   struct ns_display_info *dpyinfo;
1821   NSTRACE (ns_mouse_position);
1823   if (*fp == NULL)
1824     {
1825       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1826       return;
1827     }
1829   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1831   block_input ();
1833   if (last_mouse_scroll_bar != nil && insist == 0)
1834     {
1835       /* TODO: we do not use this path at the moment because drag events will
1836            go directly to the EmacsScroller.  Leaving code in for now. */
1837       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1838                                               x: x y: y];
1839       if (time) *time = last_mouse_movement_time;
1840       last_mouse_scroll_bar = nil;
1841     }
1842   else
1843     {
1844       /* Clear the mouse-moved flag for every frame on this display.  */
1845       FOR_EACH_FRAME (tail, frame)
1846         if (FRAME_NS_P (XFRAME (frame))
1847             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1848           XFRAME (frame)->mouse_moved = 0;
1850       last_mouse_scroll_bar = nil;
1851       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1852         f = last_mouse_frame;
1853       else
1854         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1855                                     : SELECTED_FRAME ();
1857       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1858         {
1859           view = FRAME_NS_VIEW (*fp);
1861           position = [[view window] mouseLocationOutsideOfEventStream];
1862           position = [view convertPoint: position fromView: nil];
1863           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1864 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1866           if (bar_window) *bar_window = Qnil;
1867           if (part) *part = 0; /*scroll_bar_handle; */
1869           if (x) XSETINT (*x, lrint (position.x));
1870           if (y) XSETINT (*y, lrint (position.y));
1871           if (time) *time = last_mouse_movement_time;
1872           *fp = f;
1873         }
1874     }
1876   unblock_input ();
1880 static void
1881 ns_frame_up_to_date (struct frame *f)
1882 /* --------------------------------------------------------------------------
1883     External (hook): Fix up mouse highlighting right after a full update.
1884     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1885    -------------------------------------------------------------------------- */
1887   NSTRACE (ns_frame_up_to_date);
1889   if (FRAME_NS_P (f))
1890     {
1891       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1892       if (f == hlinfo->mouse_face_mouse_frame)
1893         {
1894           block_input ();
1895           ns_update_begin(f);
1896           if (hlinfo->mouse_face_mouse_frame)
1897             note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1898                                   hlinfo->mouse_face_mouse_x,
1899                                   hlinfo->mouse_face_mouse_y);
1900           ns_update_end(f);
1901           unblock_input ();
1902         }
1903     }
1907 static void
1908 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1909 /* --------------------------------------------------------------------------
1910     External (RIF): set frame mouse pointer type.
1911    -------------------------------------------------------------------------- */
1913   NSTRACE (ns_define_frame_cursor);
1914   if (FRAME_POINTER_TYPE (f) != cursor)
1915     {
1916       EmacsView *view = FRAME_NS_VIEW (f);
1917       FRAME_POINTER_TYPE (f) = cursor;
1918       [[view window] invalidateCursorRectsForView: view];
1919       /* Redisplay assumes this function also draws the changed frame
1920          cursor, but this function doesn't, so do it explicitly.  */
1921       x_update_cursor (f, 1);
1922     }
1927 /* ==========================================================================
1929     Keyboard handling
1931    ========================================================================== */
1934 static unsigned
1935 ns_convert_key (unsigned code)
1936 /* --------------------------------------------------------------------------
1937     Internal call used by NSView-keyDown.
1938    -------------------------------------------------------------------------- */
1940   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1941                                 / sizeof (convert_ns_to_X_keysym[0]));
1942   unsigned keysym;
1943   /* An array would be faster, but less easy to read. */
1944   for (keysym = 0; keysym < last_keysym; keysym += 2)
1945     if (code == convert_ns_to_X_keysym[keysym])
1946       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1947   return 0;
1948 /* if decide to use keyCode and Carbon table, use this line:
1949      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1953 char *
1954 x_get_keysym_name (int keysym)
1955 /* --------------------------------------------------------------------------
1956     Called by keyboard.c.  Not sure if the return val is important, except
1957     that it be unique.
1958    -------------------------------------------------------------------------- */
1960   static char value[16];
1961   NSTRACE (x_get_keysym_name);
1962   sprintf (value, "%d", keysym);
1963   return value;
1968 /* ==========================================================================
1970     Block drawing operations
1972    ========================================================================== */
1975 static void
1976 ns_redraw_scroll_bars (struct frame *f)
1978   int i;
1979   id view;
1980   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1981   NSTRACE (ns_redraw_scroll_bars);
1982   for (i =[subviews count]-1; i >= 0; i--)
1983     {
1984       view = [subviews objectAtIndex: i];
1985       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1986       [view display];
1987     }
1991 void
1992 ns_clear_frame (struct frame *f)
1993 /* --------------------------------------------------------------------------
1994       External (hook): Erase the entire frame
1995    -------------------------------------------------------------------------- */
1997   NSView *view = FRAME_NS_VIEW (f);
1998   NSRect r;
2000   NSTRACE (ns_clear_frame);
2002  /* comes on initial frame because we have
2003     after-make-frame-functions = select-frame */
2004  if (!FRAME_DEFAULT_FACE (f))
2005    return;
2007   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2009   output_cursor.hpos = output_cursor.vpos = 0;
2010   output_cursor.x = -1;
2012   r = [view bounds];
2014   block_input ();
2015   ns_focus (f, &r, 1);
2016   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2017   NSRectFill (r);
2018   ns_unfocus (f);
2020   /* as of 2006/11 or so this is now needed */
2021   ns_redraw_scroll_bars (f);
2022   unblock_input ();
2026 static void
2027 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2028 /* --------------------------------------------------------------------------
2029     External (RIF):  Clear section of frame
2030    -------------------------------------------------------------------------- */
2032   NSRect r = NSMakeRect (x, y, width, height);
2033   NSView *view = FRAME_NS_VIEW (f);
2034   struct face *face = FRAME_DEFAULT_FACE (f);
2036   if (!view || !face)
2037     return;
2039   NSTRACE (ns_clear_frame_area);
2041   r = NSIntersectionRect (r, [view frame]);
2042   ns_focus (f, &r, 1);
2043   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2045   NSRectFill (r);
2047   ns_unfocus (f);
2048   return;
2052 static void
2053 ns_scroll_run (struct window *w, struct run *run)
2054 /* --------------------------------------------------------------------------
2055     External (RIF):  Insert or delete n lines at line vpos
2056    -------------------------------------------------------------------------- */
2058   struct frame *f = XFRAME (w->frame);
2059   int x, y, width, height, from_y, to_y, bottom_y;
2061   NSTRACE (ns_scroll_run);
2063   /* begin copy from other terms */
2064   /* Get frame-relative bounding box of the text display area of W,
2065      without mode lines.  Include in this box the left and right
2066      fringe of W.  */
2067   window_box (w, -1, &x, &y, &width, &height);
2069   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2070   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2071   bottom_y = y + height;
2073   if (to_y < from_y)
2074     {
2075       /* Scrolling up.  Make sure we don't copy part of the mode
2076          line at the bottom.  */
2077       if (from_y + run->height > bottom_y)
2078         height = bottom_y - from_y;
2079       else
2080         height = run->height;
2081     }
2082   else
2083     {
2084       /* Scrolling down.  Make sure we don't copy over the mode line.
2085          at the bottom.  */
2086       if (to_y + run->height > bottom_y)
2087         height = bottom_y - to_y;
2088       else
2089         height = run->height;
2090     }
2091   /* end copy from other terms */
2093   if (height == 0)
2094       return;
2096   block_input ();
2098   updated_window = w;
2099   x_clear_cursor (w);
2101   {
2102     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2103     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2104     NSPoint dstOrigin = NSMakePoint (x, to_y);
2106     ns_focus (f, &dstRect, 1);
2107     NSCopyBits (0, srcRect , dstOrigin);
2108     ns_unfocus (f);
2109   }
2111   unblock_input ();
2115 static void
2116 ns_after_update_window_line (struct glyph_row *desired_row)
2117 /* --------------------------------------------------------------------------
2118     External (RIF): preparatory to fringe update after text was updated
2119    -------------------------------------------------------------------------- */
2121   struct window *w = updated_window;
2122   struct frame *f;
2123   int width, height;
2125   NSTRACE (ns_after_update_window_line);
2127   /* begin copy from other terms */
2128   eassert (w);
2130   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2131     desired_row->redraw_fringe_bitmaps_p = 1;
2133   /* When a window has disappeared, make sure that no rest of
2134      full-width rows stays visible in the internal border.  */
2135   if (windows_or_buffers_changed
2136       && desired_row->full_width_p
2137       && (f = XFRAME (w->frame),
2138           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2139           width != 0)
2140       && (height = desired_row->visible_height,
2141           height > 0))
2142     {
2143       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2145       block_input ();
2146       ns_clear_frame_area (f, 0, y, width, height);
2147       ns_clear_frame_area (f,
2148                            FRAME_PIXEL_WIDTH (f) - width,
2149                            y, width, height);
2150       unblock_input ();
2151     }
2155 static void
2156 ns_shift_glyphs_for_insert (struct frame *f,
2157                            int x, int y, int width, int height,
2158                            int shift_by)
2159 /* --------------------------------------------------------------------------
2160     External (RIF): copy an area horizontally, don't worry about clearing src
2161    -------------------------------------------------------------------------- */
2163   NSRect srcRect = NSMakeRect (x, y, width, height);
2164   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2165   NSPoint dstOrigin = dstRect.origin;
2167   NSTRACE (ns_shift_glyphs_for_insert);
2169   ns_focus (f, &dstRect, 1);
2170   NSCopyBits (0, srcRect, dstOrigin);
2171   ns_unfocus (f);
2176 /* ==========================================================================
2178     Character encoding and metrics
2180    ========================================================================== */
2183 static void
2184 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2185 /* --------------------------------------------------------------------------
2186      External (RIF); compute left/right overhang of whole string and set in s
2187    -------------------------------------------------------------------------- */
2189   struct font *font = s->font;
2191   if (s->char2b)
2192     {
2193       struct font_metrics metrics;
2194       unsigned int codes[2];
2195       codes[0] = *(s->char2b);
2196       codes[1] = *(s->char2b + s->nchars - 1);
2198       font->driver->text_extents (font, codes, 2, &metrics);
2199       s->left_overhang = -metrics.lbearing;
2200       s->right_overhang
2201         = metrics.rbearing > metrics.width
2202         ? metrics.rbearing - metrics.width : 0;
2203     }
2204   else
2205     {
2206       s->left_overhang = 0;
2207       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2208         FONT_HEIGHT (font) * 0.2 : 0;
2209     }
2214 /* ==========================================================================
2216     Fringe and cursor drawing
2218    ========================================================================== */
2221 extern int max_used_fringe_bitmap;
2222 static void
2223 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2224                       struct draw_fringe_bitmap_params *p)
2225 /* --------------------------------------------------------------------------
2226     External (RIF); fringe-related
2227    -------------------------------------------------------------------------- */
2229   struct frame *f = XFRAME (WINDOW_FRAME (w));
2230   struct face *face = p->face;
2231   int rowY;
2232   static EmacsImage **bimgs = NULL;
2233   static int nBimgs = 0;
2235   /* grow bimgs if needed */
2236   if (nBimgs < max_used_fringe_bitmap)
2237     {
2238       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2239       memset (bimgs + nBimgs, 0,
2240               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2241       nBimgs = max_used_fringe_bitmap;
2242     }
2244   /* Must clip because of partially visible lines.  */
2245   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2246   ns_clip_to_row (w, row, -1, YES);
2248   if (!p->overlay_p)
2249     {
2250       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2252       /* If the fringe is adjacent to the left (right) scroll bar of a
2253          leftmost (rightmost, respectively) window, then extend its
2254          background to the gap between the fringe and the bar.  */
2255       if ((WINDOW_LEFTMOST_P (w)
2256            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2257           || (WINDOW_RIGHTMOST_P (w)
2258               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2259         {
2260           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2262           if (sb_width > 0)
2263             {
2264               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2265               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2266                                     * FRAME_COLUMN_WIDTH (f));
2268               if (bx < 0)
2269                 {
2270                   /* Bitmap fills the fringe.  */
2271                   if (bar_area_x + bar_area_width == p->x)
2272                     bx = bar_area_x + sb_width;
2273                   else if (p->x + p->wd == bar_area_x)
2274                     bx = bar_area_x;
2275                   if (bx >= 0)
2276                     {
2277                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2279                       nx = bar_area_width - sb_width;
2280                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2281                                                             row->y));
2282                       ny = row->visible_height;
2283                     }
2284                 }
2285               else
2286                 {
2287                   if (bar_area_x + bar_area_width == bx)
2288                     {
2289                       bx = bar_area_x + sb_width;
2290                       nx += bar_area_width - sb_width;
2291                     }
2292                   else if (bx + nx == bar_area_x)
2293                     nx += bar_area_width - sb_width;
2294                 }
2295             }
2296         }
2298       if (bx >= 0 && nx > 0)
2299         {
2300           NSRect r = NSMakeRect (bx, by, nx, ny);
2301           NSRectClip (r);
2302           [ns_lookup_indexed_color (face->background, f) set];
2303           NSRectFill (r);
2304         }
2305     }
2307   if (p->which)
2308     {
2309       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2310       EmacsImage *img = bimgs[p->which - 1];
2312       if (!img)
2313         {
2314           unsigned short *bits = p->bits + p->dh;
2315           int len = p->h;
2316           int i;
2317           unsigned char *cbits = xmalloc (len);
2319           for (i = 0; i < len; i++)
2320             cbits[i] = ~(bits[i] & 0xff);
2321           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2322                                            flip: NO];
2323           bimgs[p->which - 1] = img;
2324           xfree (cbits);
2325         }
2327       NSRectClip (r);
2328       /* Since we composite the bitmap instead of just blitting it, we need
2329          to erase the whole background. */
2330       [ns_lookup_indexed_color(face->background, f) set];
2331       NSRectFill (r);
2332       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2333 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2334       [img drawInRect: r
2335               fromRect: NSZeroRect
2336              operation: NSCompositeSourceOver
2337               fraction: 1.0
2338            respectFlipped: YES
2339                 hints: nil];
2340 #else
2341       {
2342         NSPoint pt = r.origin;
2343         pt.y += p->h;
2344         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2345       }
2346 #endif
2347     }
2348   ns_unfocus (f);
2352 static void
2353 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2354                        int x, int y, int cursor_type, int cursor_width,
2355                        int on_p, int active_p)
2356 /* --------------------------------------------------------------------------
2357      External call (RIF): draw cursor.
2358      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2359    -------------------------------------------------------------------------- */
2361   NSRect r, s;
2362   int fx, fy, h, cursor_height;
2363   struct frame *f = WINDOW_XFRAME (w);
2364   struct glyph *phys_cursor_glyph;
2365   int overspill;
2366   struct glyph *cursor_glyph;
2367   struct face *face;
2368   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2370   /* If cursor is out of bounds, don't draw garbage.  This can happen
2371      in mini-buffer windows when switching between echo area glyphs
2372      and mini-buffer.  */
2374   NSTRACE (dumpcursor);
2376   if (!on_p)
2377     return;
2379   w->phys_cursor_type = cursor_type;
2380   w->phys_cursor_on_p = on_p;
2382   if (cursor_type == NO_CURSOR)
2383     {
2384       w->phys_cursor_width = 0;
2385       return;
2386     }
2388   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2389     {
2390       if (glyph_row->exact_window_width_line_p
2391           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2392         {
2393           glyph_row->cursor_in_fringe_p = 1;
2394           draw_fringe_bitmap (w, glyph_row, 0);
2395         }
2396       return;
2397     }
2399   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2400      (other terminals do it the other way round).  We must set
2401      w->phys_cursor_width to the cursor width.  For bar cursors, that
2402      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2403   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2405   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2406      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2407   if (cursor_type == BAR_CURSOR)
2408     {
2409       if (cursor_width < 1)
2410         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2411       w->phys_cursor_width = cursor_width;
2412     }
2413   /* If we have an HBAR, "cursor_width" MAY specify height. */
2414   else if (cursor_type == HBAR_CURSOR)
2415     {
2416       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2417       fy += h - cursor_height;
2418       h = cursor_height;
2419     }
2421   r.origin.x = fx, r.origin.y = fy;
2422   r.size.height = h;
2423   r.size.width = w->phys_cursor_width;
2425   /* TODO: only needed in rare cases with last-resort font in HELLO..
2426      should we do this more efficiently? */
2427   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2430   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2431   if (face && NS_FACE_BACKGROUND (face)
2432       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2433     {
2434       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2435       hollow_color = FRAME_CURSOR_COLOR (f);
2436     }
2437   else
2438     [FRAME_CURSOR_COLOR (f) set];
2440 #ifdef NS_IMPL_COCOA
2441   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2442            atomic.  Cleaner ways of doing this should be investigated.
2443            One way would be to set a global variable DRAWING_CURSOR
2444            when making the call to draw_phys..(), don't focus in that
2445            case, then move the ns_unfocus() here after that call. */
2446   NSDisableScreenUpdates ();
2447 #endif
2449   switch (cursor_type)
2450     {
2451     case NO_CURSOR:
2452       break;
2453     case FILLED_BOX_CURSOR:
2454       NSRectFill (r);
2455       break;
2456     case HOLLOW_BOX_CURSOR:
2457       NSRectFill (r);
2458       [hollow_color set];
2459       NSRectFill (NSInsetRect (r, 1, 1));
2460       [FRAME_CURSOR_COLOR (f) set];
2461       break;
2462     case HBAR_CURSOR:
2463       NSRectFill (r);
2464       break;
2465     case BAR_CURSOR:
2466       s = r;
2467       /* If the character under cursor is R2L, draw the bar cursor
2468          on the right of its glyph, rather than on the left.  */
2469       cursor_glyph = get_phys_cursor_glyph (w);
2470       if ((cursor_glyph->resolved_level & 1) != 0)
2471         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2473       NSRectFill (s);
2474       break;
2475     }
2476   ns_unfocus (f);
2478   /* draw the character under the cursor */
2479   if (cursor_type != NO_CURSOR)
2480     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2482 #ifdef NS_IMPL_COCOA
2483   NSEnableScreenUpdates ();
2484 #endif
2489 static void
2490 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2491 /* --------------------------------------------------------------------------
2492      External (RIF): Draw a vertical line.
2493    -------------------------------------------------------------------------- */
2495   struct frame *f = XFRAME (WINDOW_FRAME (w));
2496   struct face *face;
2497   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2499   NSTRACE (ns_draw_vertical_window_border);
2501   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2502   if (face)
2503       [ns_lookup_indexed_color(face->foreground, f) set];
2505   ns_focus (f, &r, 1);
2506   NSRectFill(r);
2507   ns_unfocus (f);
2511 void
2512 show_hourglass (struct atimer *timer)
2514   if (hourglass_shown_p)
2515     return;
2517   block_input ();
2519   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2521   hourglass_shown_p = 1;
2522   unblock_input ();
2526 void
2527 hide_hourglass (void)
2529   if (!hourglass_shown_p)
2530     return;
2532   block_input ();
2534   /* TODO: remove NSProgressIndicator from all frames */
2536   hourglass_shown_p = 0;
2537   unblock_input ();
2542 /* ==========================================================================
2544     Glyph drawing operations
2546    ========================================================================== */
2548 static int
2549 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2550 /* --------------------------------------------------------------------------
2551     Wrapper utility to account for internal border width on full-width lines,
2552     and allow top full-width rows to hit the frame top.  nr should be pointer
2553     to two successive NSRects.  Number of rects actually used is returned.
2554    -------------------------------------------------------------------------- */
2556   int n = get_glyph_string_clip_rects (s, nr, 2);
2557   return n;
2560 /* --------------------------------------------------------------------
2561    Draw a wavy line under glyph string s. The wave fills wave_height
2562    pixels from y.
2564                     x          wave_length = 2
2565                                  --
2566                 y    *   *   *   *   *
2567                      |* * * * * * * * *
2568     wave_height = 3  | *   *   *   *
2569   --------------------------------------------------------------------- */
2571 static void
2572 ns_draw_underwave (struct glyph_string *s, CGFloat width, CGFloat x)
2574   int wave_height = 3, wave_length = 2;
2575   int y, dx, dy, odd, xmax;
2576   NSPoint a, b;
2577   NSRect waveClip;
2579   dx = wave_length;
2580   dy = wave_height - 1;
2581   y =  s->ybase - wave_height + 3;
2582   xmax = x + width;
2584   /* Find and set clipping rectangle */
2585   waveClip = NSMakeRect (x, y, width, wave_height);
2586   [[NSGraphicsContext currentContext] saveGraphicsState];
2587   NSRectClip (waveClip);
2589   /* Draw the waves */
2590   a.x = x - ((int)(x) % dx) + 0.5;
2591   b.x = a.x + dx;
2592   odd = (int)(a.x/dx) % 2;
2593   a.y = b.y = y + 0.5;
2595   if (odd)
2596     a.y += dy;
2597   else
2598     b.y += dy;
2600   while (a.x <= xmax)
2601     {
2602       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2603       a.x = b.x, a.y = b.y;
2604       b.x += dx, b.y = y + 0.5 + odd*dy;
2605       odd = !odd;
2606     }
2608   /* Restore previous clipping rectangle(s) */
2609   [[NSGraphicsContext currentContext] restoreGraphicsState];
2614 void
2615 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2616                          NSColor *defaultCol, CGFloat width, CGFloat x)
2617 /* --------------------------------------------------------------------------
2618    Draw underline, overline, and strike-through on glyph string s.
2619    -------------------------------------------------------------------------- */
2621   if (s->for_overlaps)
2622     return;
2624   /* Do underline. */
2625   if (face->underline_p)
2626     {
2627       if (s->face->underline_type == FACE_UNDER_WAVE)
2628         {
2629           if (face->underline_defaulted_p)
2630             [defaultCol set];
2631           else
2632             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2634           ns_draw_underwave (s, width, x);
2635         }
2636       else if (s->face->underline_type == FACE_UNDER_LINE)
2637         {
2639           NSRect r;
2640           unsigned long thickness, position;
2642           /* If the prev was underlined, match its appearance. */
2643           if (s->prev && s->prev->face->underline_p
2644               && s->prev->face->underline_type == FACE_UNDER_LINE
2645               && s->prev->underline_thickness > 0)
2646             {
2647               thickness = s->prev->underline_thickness;
2648               position = s->prev->underline_position;
2649             }
2650           else
2651             {
2652               struct font *font;
2653               unsigned long descent;
2655               font=s->font;
2656               descent = s->y + s->height - s->ybase;
2658               /* Use underline thickness of font, defaulting to 1. */
2659               thickness = (font && font->underline_thickness > 0)
2660                 ? font->underline_thickness : 1;
2662               /* Determine the offset of underlining from the baseline. */
2663               if (x_underline_at_descent_line)
2664                 position = descent - thickness;
2665               else if (x_use_underline_position_properties
2666                        && font && font->underline_position >= 0)
2667                 position = font->underline_position;
2668               else if (font)
2669                 position = lround (font->descent / 2);
2670               else
2671                 position = underline_minimum_offset;
2673               position = max (position, underline_minimum_offset);
2675               /* Ensure underlining is not cropped. */
2676               if (descent <= position)
2677                 {
2678                   position = descent - 1;
2679                   thickness = 1;
2680                 }
2681               else if (descent < position + thickness)
2682                 thickness = 1;
2683             }
2685           s->underline_thickness = thickness;
2686           s->underline_position = position;
2688           r = NSMakeRect (x, s->ybase + position, width, thickness);
2690           if (face->underline_defaulted_p)
2691             [defaultCol set];
2692           else
2693             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2694           NSRectFill (r);
2695         }
2696     }
2697   /* Do overline. We follow other terms in using a thickness of 1
2698      and ignoring overline_margin. */
2699   if (face->overline_p)
2700     {
2701       NSRect r;
2702       r = NSMakeRect (x, s->y, width, 1);
2704       if (face->overline_color_defaulted_p)
2705         [defaultCol set];
2706       else
2707         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2708       NSRectFill (r);
2709     }
2711   /* Do strike-through.  We follow other terms for thickness and
2712      vertical position.*/
2713   if (face->strike_through_p)
2714     {
2715       NSRect r;
2716       unsigned long dy;
2718       dy = lrint ((s->height - 1) / 2);
2719       r = NSMakeRect (x, s->y + dy, width, 1);
2721       if (face->strike_through_color_defaulted_p)
2722         [defaultCol set];
2723       else
2724         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2725       NSRectFill (r);
2726     }
2729 static void
2730 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2731 /* --------------------------------------------------------------------------
2732     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2733     Note we can't just use an NSDrawRect command, because of the possibility
2734     of some sides not being drawn, and because the rect will be filled.
2735    -------------------------------------------------------------------------- */
2737   NSRect s = r;
2738   [col set];
2740   /* top, bottom */
2741   s.size.height = thickness;
2742   NSRectFill (s);
2743   s.origin.y += r.size.height - thickness;
2744   NSRectFill (s);
2746   s.size.height = r.size.height;
2747   s.origin.y = r.origin.y;
2749   /* left, right (optional) */
2750   s.size.width = thickness;
2751   if (left_p)
2752     NSRectFill (s);
2753   if (right_p)
2754     {
2755       s.origin.x += r.size.width - thickness;
2756       NSRectFill (s);
2757     }
2761 static void
2762 ns_draw_relief (NSRect r, int thickness, char raised_p,
2763                char top_p, char bottom_p, char left_p, char right_p,
2764                struct glyph_string *s)
2765 /* --------------------------------------------------------------------------
2766     Draw a relief rect inside r, optionally leaving some sides open.
2767     Note we can't just use an NSDrawBezel command, because of the possibility
2768     of some sides not being drawn, and because the rect will be filled.
2769    -------------------------------------------------------------------------- */
2771   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2772   NSColor *newBaseCol = nil;
2773   NSRect sr = r;
2775   NSTRACE (ns_draw_relief);
2777   /* set up colors */
2779   if (s->face->use_box_color_for_shadows_p)
2780     {
2781       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2782     }
2783 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2784            && s->img->pixmap
2785            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2786        {
2787          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2788        } */
2789   else
2790     {
2791       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2792     }
2794   if (newBaseCol == nil)
2795     newBaseCol = [NSColor grayColor];
2797   if (newBaseCol != baseCol)  /* TODO: better check */
2798     {
2799       [baseCol release];
2800       baseCol = [newBaseCol retain];
2801       [lightCol release];
2802       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2803       [darkCol release];
2804       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2805     }
2807   [(raised_p ? lightCol : darkCol) set];
2809   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2811   /* top */
2812   sr.size.height = thickness;
2813   if (top_p) NSRectFill (sr);
2815   /* left */
2816   sr.size.height = r.size.height;
2817   sr.size.width = thickness;
2818   if (left_p) NSRectFill (sr);
2820   [(raised_p ? darkCol : lightCol) set];
2822   /* bottom */
2823   sr.size.width = r.size.width;
2824   sr.size.height = thickness;
2825   sr.origin.y += r.size.height - thickness;
2826   if (bottom_p) NSRectFill (sr);
2828   /* right */
2829   sr.size.height = r.size.height;
2830   sr.origin.y = r.origin.y;
2831   sr.size.width = thickness;
2832   sr.origin.x += r.size.width - thickness;
2833   if (right_p) NSRectFill (sr);
2837 static void
2838 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2839 /* --------------------------------------------------------------------------
2840       Function modeled after x_draw_glyph_string_box ().
2841       Sets up parameters for drawing.
2842    -------------------------------------------------------------------------- */
2844   int right_x, last_x;
2845   char left_p, right_p;
2846   struct glyph *last_glyph;
2847   NSRect r;
2848   int thickness;
2849   struct face *face;
2851   if (s->hl == DRAW_MOUSE_FACE)
2852     {
2853       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2854       if (!face)
2855         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2856     }
2857   else
2858     face = s->face;
2860   thickness = face->box_line_width;
2862   NSTRACE (ns_dumpglyphs_box_or_relief);
2864   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2865             ? WINDOW_RIGHT_EDGE_X (s->w)
2866             : window_box_right (s->w, s->area));
2867   last_glyph = (s->cmp || s->img
2868                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2870   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2871               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2873   left_p = (s->first_glyph->left_box_line_p
2874             || (s->hl == DRAW_MOUSE_FACE
2875                 && (s->prev == NULL || s->prev->hl != s->hl)));
2876   right_p = (last_glyph->right_box_line_p
2877              || (s->hl == DRAW_MOUSE_FACE
2878                  && (s->next == NULL || s->next->hl != s->hl)));
2880   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2882   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2883   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2884     {
2885       ns_draw_box (r, abs (thickness),
2886                    ns_lookup_indexed_color (face->box_color, s->f),
2887                   left_p, right_p);
2888     }
2889   else
2890     {
2891       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2892                      1, 1, left_p, right_p, s);
2893     }
2897 static void
2898 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2899 /* --------------------------------------------------------------------------
2900       Modeled after x_draw_glyph_string_background, which draws BG in
2901       certain cases.  Others are left to the text rendering routine.
2902    -------------------------------------------------------------------------- */
2904   NSTRACE (ns_maybe_dumpglyphs_background);
2906   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2907     {
2908       int box_line_width = max (s->face->box_line_width, 0);
2909       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2910           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2911         {
2912           struct face *face;
2913           if (s->hl == DRAW_MOUSE_FACE)
2914             {
2915               face = FACE_FROM_ID (s->f,
2916                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2917               if (!face)
2918                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2919             }
2920           else
2921             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2922           if (!face->stipple)
2923             [(NS_FACE_BACKGROUND (face) != 0
2924               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2925               : FRAME_BACKGROUND_COLOR (s->f)) set];
2926           else
2927             {
2928               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2929               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2930             }
2932           if (s->hl != DRAW_CURSOR)
2933             {
2934               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2935                                     s->background_width,
2936                                     s->height-2*box_line_width);
2937               NSRectFill (r);
2938             }
2940           s->background_filled_p = 1;
2941         }
2942     }
2946 static void
2947 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2948 /* --------------------------------------------------------------------------
2949       Renders an image and associated borders.
2950    -------------------------------------------------------------------------- */
2952   EmacsImage *img = s->img->pixmap;
2953   int box_line_vwidth = max (s->face->box_line_width, 0);
2954   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2955   int bg_x, bg_y, bg_height;
2956   int th;
2957   char raised_p;
2958   NSRect br;
2959   struct face *face;
2960   NSColor *tdCol;
2962   NSTRACE (ns_dumpglyphs_image);
2964   if (s->face->box != FACE_NO_BOX
2965       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2966     x += abs (s->face->box_line_width);
2968   bg_x = x;
2969   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2970   bg_height = s->height;
2971   /* other terms have this, but was causing problems w/tabbar mode */
2972   /* - 2 * box_line_vwidth; */
2974   if (s->slice.x == 0) x += s->img->hmargin;
2975   if (s->slice.y == 0) y += s->img->vmargin;
2977   /* Draw BG: if we need larger area than image itself cleared, do that,
2978      otherwise, since we composite the image under NS (instead of mucking
2979      with its background color), we must clear just the image area. */
2980   if (s->hl == DRAW_MOUSE_FACE)
2981     {
2982       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2983       if (!face)
2984        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2985     }
2986   else
2987     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2989   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2991   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2992       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2993     {
2994       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2995       s->background_filled_p = 1;
2996     }
2997   else
2998     {
2999       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3000     }
3002   NSRectFill (br);
3004   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3005   if (img != nil)
3006     {
3007 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
3008       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3009       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3010                               s->slice.width, s->slice.height);
3011       [img drawInRect: dr
3012              fromRect: ir
3013              operation: NSCompositeSourceOver
3014               fraction: 1.0
3015            respectFlipped: YES
3016                 hints: nil];
3017 #else
3018       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3019                   operation: NSCompositeSourceOver];
3020 #endif
3021     }
3023   if (s->hl == DRAW_CURSOR)
3024     {
3025     [FRAME_CURSOR_COLOR (s->f) set];
3026     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3027       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3028     else
3029       /* Currently on NS img->mask is always 0. Since
3030          get_window_cursor_type specifies a hollow box cursor when on
3031          a non-masked image we never reach this clause. But we put it
3032          in in anticipation of better support for image masks on
3033          NS. */
3034       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3035     }
3036   else
3037     {
3038       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3039     }
3041   /* Draw underline, overline, strike-through. */
3042   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3044   /* Draw relief, if requested */
3045   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3046     {
3047       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3048         {
3049           th = tool_bar_button_relief >= 0 ?
3050             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3051           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3052         }
3053       else
3054         {
3055           th = abs (s->img->relief);
3056           raised_p = (s->img->relief > 0);
3057         }
3059       r.origin.x = x - th;
3060       r.origin.y = y - th;
3061       r.size.width = s->slice.width + 2*th-1;
3062       r.size.height = s->slice.height + 2*th-1;
3063       ns_draw_relief (r, th, raised_p,
3064                       s->slice.y == 0,
3065                       s->slice.y + s->slice.height == s->img->height,
3066                       s->slice.x == 0,
3067                       s->slice.x + s->slice.width == s->img->width, s);
3068     }
3070   /* If there is no mask, the background won't be seen,
3071      so draw a rectangle on the image for the cursor.
3072      Do this for all images, getting transparency right is not reliable.  */
3073   if (s->hl == DRAW_CURSOR)
3074     {
3075       int thickness = abs (s->img->relief);
3076       if (thickness == 0) thickness = 1;
3077       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3078     }
3082 static void
3083 ns_dumpglyphs_stretch (struct glyph_string *s)
3085   NSRect r[2];
3086   int n, i;
3087   struct face *face;
3088   NSColor *fgCol, *bgCol;
3090   if (!s->background_filled_p)
3091     {
3092       n = ns_get_glyph_string_clip_rect (s, r);
3093       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3095       ns_focus (s->f, r, n);
3097       if (s->hl == DRAW_MOUSE_FACE)
3098        {
3099          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3100          if (!face)
3101            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3102        }
3103       else
3104        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3106       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3107       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3109       for (i = 0; i < n; ++i)
3110         {
3111           if (!s->row->full_width_p)
3112             {
3113               int overrun, leftoverrun;
3115               /* truncate to avoid overwriting fringe and/or scrollbar */
3116               overrun = max (0, (s->x + s->background_width)
3117                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3118                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3119               r[i].size.width -= overrun;
3121               /* truncate to avoid overwriting to left of the window box */
3122               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3123                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3125               if (leftoverrun > 0)
3126                 {
3127                   r[i].origin.x += leftoverrun;
3128                   r[i].size.width -= leftoverrun;
3129                 }
3131               /* XXX: Try to work between problem where a stretch glyph on
3132                  a partially-visible bottom row will clear part of the
3133                  modeline, and another where list-buffers headers and similar
3134                  rows erroneously have visible_height set to 0.  Not sure
3135                  where this is coming from as other terms seem not to show. */
3136               r[i].size.height = min (s->height, s->row->visible_height);
3137             }
3139           [bgCol set];
3141           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3142              overwriting cursor (usually when cursor on a tab) */
3143           if (s->hl == DRAW_CURSOR)
3144             {
3145               CGFloat x, width;
3147               x = r[i].origin.x;
3148               width = s->w->phys_cursor_width;
3149               r[i].size.width -= width;
3150               r[i].origin.x += width;
3152               NSRectFill (r[i]);
3154               /* Draw overlining, etc. on the cursor. */
3155               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3156                 ns_draw_text_decoration (s, face, bgCol, width, x);
3157               else
3158                 ns_draw_text_decoration (s, face, fgCol, width, x);
3159             }
3160           else
3161             {
3162               NSRectFill (r[i]);
3163             }
3165           /* Draw overlining, etc. on the stretch glyph (or the part
3166              of the stretch glyph after the cursor). */
3167           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3168                                    r[i].origin.x);
3169         }
3170       ns_unfocus (s->f);
3171       s->background_filled_p = 1;
3172     }
3176 static void
3177 ns_draw_glyph_string (struct glyph_string *s)
3178 /* --------------------------------------------------------------------------
3179       External (RIF): Main draw-text call.
3180    -------------------------------------------------------------------------- */
3182   /* TODO (optimize): focus for box and contents draw */
3183   NSRect r[2];
3184   int n;
3185   char box_drawn_p = 0;
3187   NSTRACE (ns_draw_glyph_string);
3189   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3190     {
3191       int width;
3192       struct glyph_string *next;
3194       for (width = 0, next = s->next;
3195            next && width < s->right_overhang;
3196            width += next->width, next = next->next)
3197         if (next->first_glyph->type != IMAGE_GLYPH)
3198           {
3199             if (next->first_glyph->type != STRETCH_GLYPH)
3200               {
3201                 n = ns_get_glyph_string_clip_rect (s->next, r);
3202                 ns_focus (s->f, r, n);
3203                 ns_maybe_dumpglyphs_background (s->next, 1);
3204                 ns_unfocus (s->f);
3205               }
3206             else
3207               {
3208                 ns_dumpglyphs_stretch (s->next);
3209               }
3210             next->num_clips = 0;
3211           }
3212     }
3214   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3215         && (s->first_glyph->type == CHAR_GLYPH
3216             || s->first_glyph->type == COMPOSITE_GLYPH))
3217     {
3218       n = ns_get_glyph_string_clip_rect (s, r);
3219       ns_focus (s->f, r, n);
3220       ns_maybe_dumpglyphs_background (s, 1);
3221       ns_dumpglyphs_box_or_relief (s);
3222       ns_unfocus (s->f);
3223       box_drawn_p = 1;
3224     }
3226   switch (s->first_glyph->type)
3227     {
3229     case IMAGE_GLYPH:
3230       n = ns_get_glyph_string_clip_rect (s, r);
3231       ns_focus (s->f, r, n);
3232       ns_dumpglyphs_image (s, r[0]);
3233       ns_unfocus (s->f);
3234       break;
3236     case STRETCH_GLYPH:
3237       ns_dumpglyphs_stretch (s);
3238       break;
3240     case CHAR_GLYPH:
3241     case COMPOSITE_GLYPH:
3242       n = ns_get_glyph_string_clip_rect (s, r);
3243       ns_focus (s->f, r, n);
3245       if (s->for_overlaps || (s->cmp_from > 0
3246                               && ! s->first_glyph->u.cmp.automatic))
3247         s->background_filled_p = 1;
3248       else
3249         ns_maybe_dumpglyphs_background
3250           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3252       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3253                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3254                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3255                       NS_DUMPGLYPH_NORMAL));
3256       ns_tmp_font = (struct nsfont_info *)s->face->font;
3257       if (ns_tmp_font == NULL)
3258           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3260       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3261         {
3262           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3263           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3264           NS_FACE_FOREGROUND (s->face) = tmp;
3265         }
3267       ns_tmp_font->font.driver->draw
3268         (s, 0, s->nchars, s->x, s->y,
3269          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3270          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3272       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3273         {
3274           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3275           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3276           NS_FACE_FOREGROUND (s->face) = tmp;
3277         }
3279       ns_unfocus (s->f);
3280       break;
3282     case GLYPHLESS_GLYPH:
3283       n = ns_get_glyph_string_clip_rect (s, r);
3284       ns_focus (s->f, r, n);
3286       if (s->for_overlaps || (s->cmp_from > 0
3287                               && ! s->first_glyph->u.cmp.automatic))
3288         s->background_filled_p = 1;
3289       else
3290         ns_maybe_dumpglyphs_background
3291           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3292       /* ... */
3293       /* Not yet implemented.  */
3294       /* ... */
3295       ns_unfocus (s->f);
3296       break;
3298     default:
3299       emacs_abort ();
3300     }
3302   /* Draw box if not done already. */
3303   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3304     {
3305       n = ns_get_glyph_string_clip_rect (s, r);
3306       ns_focus (s->f, r, n);
3307       ns_dumpglyphs_box_or_relief (s);
3308       ns_unfocus (s->f);
3309     }
3311   s->num_clips = 0;
3316 /* ==========================================================================
3318     Event loop
3320    ========================================================================== */
3323 static void
3324 ns_send_appdefined (int value)
3325 /* --------------------------------------------------------------------------
3326     Internal: post an appdefined event which EmacsApp-sendEvent will
3327               recognize and take as a command to halt the event loop.
3328    -------------------------------------------------------------------------- */
3330   /*NSTRACE (ns_send_appdefined); */
3332   /* Only post this event if we haven't already posted one.  This will end
3333        the [NXApp run] main loop after having processed all events queued at
3334        this moment.  */
3335   if (send_appdefined)
3336     {
3337       NSEvent *nxev;
3339       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3340       send_appdefined = NO;
3342       /* Don't need wakeup timer any more */
3343       if (timed_entry)
3344         {
3345           [timed_entry invalidate];
3346           [timed_entry release];
3347           timed_entry = nil;
3348         }
3350       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3351                                 location: NSMakePoint (0, 0)
3352                            modifierFlags: 0
3353                                timestamp: 0
3354                             windowNumber: [[NSApp mainWindow] windowNumber]
3355                                  context: [NSApp context]
3356                                  subtype: 0
3357                                    data1: value
3358                                    data2: 0];
3360       /* Post an application defined event on the event queue.  When this is
3361          received the [NXApp run] will return, thus having processed all
3362          events which are currently queued.  */
3363       [NSApp postEvent: nxev atStart: NO];
3364     }
3367 #ifdef HAVE_NATIVE_FS
3368 static void
3369 check_native_fs ()
3371   Lisp_Object frame, tail;
3373   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3374     return;
3376   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3378   /* Clear the mouse-moved flag for every frame on this display.  */
3379   FOR_EACH_FRAME (tail, frame)
3380     {
3381       struct frame *f = XFRAME (frame);
3382       if (FRAME_NS_P (f))
3383         {
3384           EmacsView *view = FRAME_NS_VIEW (f);
3385           [view updateCollectionBehaviour];
3386         }
3387     }
3389 #endif
3391 static int
3392 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3393 /* --------------------------------------------------------------------------
3394      External (hook): Post an event to ourself and keep reading events until
3395      we read it back again.  In effect process all events which were waiting.
3396      From 21+ we have to manage the event buffer ourselves.
3397    -------------------------------------------------------------------------- */
3399   struct input_event ev;
3400   int nevents;
3402 /* NSTRACE (ns_read_socket); */
3404 #ifdef HAVE_NATIVE_FS
3405   check_native_fs ();
3406 #endif
3408   if ([NSApp modalWindow] != nil)
3409     return -1;
3411   if (hold_event_q.nr > 0)
3412     {
3413       int i;
3414       for (i = 0; i < hold_event_q.nr; ++i)
3415         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3416       hold_event_q.nr = 0;
3417       return i;
3418     }
3420   block_input ();
3421   n_emacs_events_pending = 0;
3422   EVENT_INIT (ev);
3423   emacs_event = &ev;
3424   q_event_ptr = hold_quit;
3426   /* we manage autorelease pools by allocate/reallocate each time around
3427      the loop; strict nesting is occasionally violated but seems not to
3428      matter.. earlier methods using full nesting caused major memory leaks */
3429   [outerpool release];
3430   outerpool = [[NSAutoreleasePool alloc] init];
3432   /* If have pending open-file requests, attend to the next one of those. */
3433   if (ns_pending_files && [ns_pending_files count] != 0
3434       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3435     {
3436       [ns_pending_files removeObjectAtIndex: 0];
3437     }
3438   /* Deal with pending service requests. */
3439   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3440     && [(EmacsApp *)
3441          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3442                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3443     {
3444       [ns_pending_service_names removeObjectAtIndex: 0];
3445       [ns_pending_service_args removeObjectAtIndex: 0];
3446     }
3447   else
3448     {
3449       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3450          to ourself, otherwise [NXApp run] will never exit.  */
3451       send_appdefined = YES;
3452       ns_send_appdefined (-1);
3454       if (++apploopnr != 1)
3455         {
3456           emacs_abort ();
3457         }
3458       [NSApp run];
3459       --apploopnr;
3460     }
3462   nevents = n_emacs_events_pending;
3463   n_emacs_events_pending = 0;
3464   emacs_event = q_event_ptr = NULL;
3465   unblock_input ();
3467   return nevents;
3472 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3473            fd_set *exceptfds, EMACS_TIME *timeout, sigset_t *sigmask)
3474 /* --------------------------------------------------------------------------
3475      Replacement for select, checking for events
3476    -------------------------------------------------------------------------- */
3478   int result;
3479   int t, k, nr = 0;
3480   struct input_event event;
3481   char c;
3483 /*  NSTRACE (ns_select); */
3485 #ifdef HAVE_NATIVE_FS
3486   check_native_fs ();
3487 #endif
3489   if (hold_event_q.nr > 0)
3490     {
3491       /* We already have events pending. */
3492       raise (SIGIO);
3493       errno = EINTR;
3494       return -1;
3495     }
3497   for (k = 0; k < nfds+1; k++)
3498     {
3499       if (readfds && FD_ISSET(k, readfds)) ++nr;
3500       if (writefds && FD_ISSET(k, writefds)) ++nr;
3501     }
3503   if (NSApp == nil
3504       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3505     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3507   [outerpool release];
3508   outerpool = [[NSAutoreleasePool alloc] init];
3511   send_appdefined = YES;
3512   if (nr > 0)
3513     {
3514       pthread_mutex_lock (&select_mutex);
3515       select_nfds = nfds;
3516       select_valid = 0;
3517       if (readfds)
3518         {
3519           select_readfds = *readfds;
3520           select_valid += SELECT_HAVE_READ;
3521         }
3522       if (writefds)
3523         {
3524           select_writefds = *writefds;
3525           select_valid += SELECT_HAVE_WRITE;
3526         }
3528       if (timeout)
3529         {
3530           select_timeout = *timeout;
3531           select_valid += SELECT_HAVE_TMO;
3532         }
3534       pthread_mutex_unlock (&select_mutex);
3536       /* Inform fd_handler that select should be called */
3537       c = 'g';
3538       emacs_write (selfds[1], &c, 1);
3539     }
3540   else if (nr == 0 && timeout)
3541     {
3542       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3543       double time = EMACS_TIME_TO_DOUBLE (*timeout);
3544       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3545                                                       target: NSApp
3546                                                     selector:
3547                                   @selector (timeout_handler:)
3548                                                     userInfo: 0
3549                                                      repeats: NO]
3550                       retain];
3551     }
3552   else /* No timeout and no file descriptors, can this happen?  */
3553     {
3554       /* Send appdefined so we exit from the loop */
3555       ns_send_appdefined (-1);
3556     }
3558   EVENT_INIT (event);
3559   block_input ();
3560   emacs_event = &event;
3561   if (++apploopnr != 1)
3562     {
3563       emacs_abort ();
3564     }
3565   [NSApp run];
3566   --apploopnr;
3567   emacs_event = NULL;
3568   if (nr > 0 && readfds)
3569     {
3570       c = 's';
3571       emacs_write (selfds[1], &c, 1);
3572     }
3573   unblock_input ();
3575   t = last_appdefined_event_data;
3577   if (t != NO_APPDEFINED_DATA)
3578     {
3579       last_appdefined_event_data = NO_APPDEFINED_DATA;
3581       if (t == -2)
3582         {
3583           /* The NX_APPDEFINED event we received was a timeout. */
3584           result = 0;
3585         }
3586       else if (t == -1)
3587         {
3588           /* The NX_APPDEFINED event we received was the result of
3589              at least one real input event arriving.  */
3590           errno = EINTR;
3591           result = -1;
3592         }
3593       else
3594         {
3595           /* Received back from select () in fd_handler; copy the results */
3596           pthread_mutex_lock (&select_mutex);
3597           if (readfds) *readfds = select_readfds;
3598           if (writefds) *writefds = select_writefds;
3599           if (timeout) *timeout = select_timeout;
3600           pthread_mutex_unlock (&select_mutex);
3601           result = t;
3602         }
3603     }
3605   return result;
3610 /* ==========================================================================
3612     Scrollbar handling
3614    ========================================================================== */
3617 static void
3618 ns_set_vertical_scroll_bar (struct window *window,
3619                            int portion, int whole, int position)
3620 /* --------------------------------------------------------------------------
3621       External (hook): Update or add scrollbar
3622    -------------------------------------------------------------------------- */
3624   Lisp_Object win;
3625   NSRect r, v;
3626   struct frame *f = XFRAME (WINDOW_FRAME (window));
3627   EmacsView *view = FRAME_NS_VIEW (f);
3628   int window_y, window_height;
3629   int top, left, height, width, sb_width, sb_left;
3630   EmacsScroller *bar;
3631   BOOL fringe_extended_p;
3633   /* optimization; display engine sends WAY too many of these.. */
3634   if (!NILP (window->vertical_scroll_bar))
3635     {
3636       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3637       if ([bar checkSamePosition: position portion: portion whole: whole])
3638         {
3639           if (view->scrollbarsNeedingUpdate == 0)
3640             {
3641               if (!windows_or_buffers_changed)
3642                   return;
3643             }
3644           else
3645             view->scrollbarsNeedingUpdate--;
3646         }
3647     }
3649   NSTRACE (ns_set_vertical_scroll_bar);
3651   /* Get dimensions.  */
3652   window_box (window, -1, 0, &window_y, 0, &window_height);
3653   top = window_y;
3654   height = window_height;
3655   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3656   left = WINDOW_SCROLL_BAR_AREA_X (window);
3658   /* allow for displaying a skinnier scrollbar than char area allotted */
3659   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3660     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3661   sb_left = left;
3663   r = NSMakeRect (sb_left, top, sb_width, height);
3664   /* the parent view is flipped, so we need to flip y value */
3665   v = [view frame];
3666   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3668   if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (window))
3669     fringe_extended_p = (WINDOW_LEFTMOST_P (window)
3670                          && WINDOW_LEFT_FRINGE_WIDTH (window)
3671                          && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (window)
3672                              || WINDOW_LEFT_MARGIN_COLS (window) == 0));
3673   else
3674     fringe_extended_p = (WINDOW_RIGHTMOST_P (window)
3675                          && WINDOW_RIGHT_FRINGE_WIDTH (window)
3676                          && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (window)
3677                              || WINDOW_RIGHT_MARGIN_COLS (window) == 0));
3679   XSETWINDOW (win, window);
3680   block_input ();
3682   /* we want at least 5 lines to display a scrollbar */
3683   if (WINDOW_TOTAL_LINES (window) < 5)
3684     {
3685       if (!NILP (window->vertical_scroll_bar))
3686         {
3687           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3688           [bar removeFromSuperview];
3689           wset_vertical_scroll_bar (window, Qnil);
3690         }
3691       ns_clear_frame_area (f, sb_left, top, width, height);
3692       unblock_input ();
3693       return;
3694     }
3696   if (NILP (window->vertical_scroll_bar))
3697     {
3698       if (width > 0 && height > 0)
3699         {
3700           if (fringe_extended_p)
3701             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3702           else
3703             ns_clear_frame_area (f, left, top, width, height);
3704         }
3706       bar = [[EmacsScroller alloc] initFrame: r window: win];
3707       wset_vertical_scroll_bar (window, make_save_pointer (bar));
3708     }
3709   else
3710     {
3711       NSRect oldRect;
3712       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3713       oldRect = [bar frame];
3714       r.size.width = oldRect.size.width;
3715       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3716         {
3717           if (oldRect.origin.x != r.origin.x)
3718               ns_clear_frame_area (f, sb_left, top, width, height);
3719           [bar setFrame: r];
3720         }
3721     }
3723   [bar setPosition: position portion: portion whole: whole];
3724   unblock_input ();
3728 static void
3729 ns_condemn_scroll_bars (struct frame *f)
3730 /* --------------------------------------------------------------------------
3731      External (hook): arrange for all frame's scrollbars to be removed
3732      at next call to judge_scroll_bars, except for those redeemed.
3733    -------------------------------------------------------------------------- */
3735   int i;
3736   id view;
3737   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3739   NSTRACE (ns_condemn_scroll_bars);
3741   for (i =[subviews count]-1; i >= 0; i--)
3742     {
3743       view = [subviews objectAtIndex: i];
3744       if ([view isKindOfClass: [EmacsScroller class]])
3745         [view condemn];
3746     }
3750 static void
3751 ns_redeem_scroll_bar (struct window *window)
3752 /* --------------------------------------------------------------------------
3753      External (hook): arrange to spare this window's scrollbar
3754      at next call to judge_scroll_bars.
3755    -------------------------------------------------------------------------- */
3757   id bar;
3758   NSTRACE (ns_redeem_scroll_bar);
3759   if (!NILP (window->vertical_scroll_bar))
3760     {
3761       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3762       [bar reprieve];
3763     }
3767 static void
3768 ns_judge_scroll_bars (struct frame *f)
3769 /* --------------------------------------------------------------------------
3770      External (hook): destroy all scrollbars on frame that weren't
3771      redeemed after call to condemn_scroll_bars.
3772    -------------------------------------------------------------------------- */
3774   int i;
3775   id view;
3776   EmacsView *eview = FRAME_NS_VIEW (f);
3777   NSArray *subviews = [[eview superview] subviews];
3778   BOOL removed = NO;
3780   NSTRACE (ns_judge_scroll_bars);
3781   for (i = [subviews count]-1; i >= 0; --i)
3782     {
3783       view = [subviews objectAtIndex: i];
3784       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3785       [view judge];
3786       removed = YES;
3787     }
3789   if (removed)
3790     [eview updateFrameSize: NO];
3794 void
3795 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3797   /* XXX irrelevant under NS */
3802 /* ==========================================================================
3804     Initialization
3806    ========================================================================== */
3809 x_display_pixel_height (struct ns_display_info *dpyinfo)
3811   NSScreen *screen = [NSScreen mainScreen];
3812   return [screen frame].size.height;
3816 x_display_pixel_width (struct ns_display_info *dpyinfo)
3818   NSScreen *screen = [NSScreen mainScreen];
3819   return [screen frame].size.width;
3823 static Lisp_Object ns_string_to_lispmod (const char *s)
3824 /* --------------------------------------------------------------------------
3825      Convert modifier name to lisp symbol
3826    -------------------------------------------------------------------------- */
3828   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3829     return Qmeta;
3830   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3831     return Qsuper;
3832   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3833     return Qcontrol;
3834   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3835     return Qalt;
3836   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3837     return Qhyper;
3838   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3839     return Qnone;
3840   else
3841     return Qnil;
3845 static void
3846 ns_default (const char *parameter, Lisp_Object *result,
3847            Lisp_Object yesval, Lisp_Object noval,
3848            BOOL is_float, BOOL is_modstring)
3849 /* --------------------------------------------------------------------------
3850       Check a parameter value in user's preferences
3851    -------------------------------------------------------------------------- */
3853   const char *value = ns_get_defaults_value (parameter);
3855   if (value)
3856     {
3857       double f;
3858       char *pos;
3859       if (c_strcasecmp (value, "YES") == 0)
3860         *result = yesval;
3861       else if (c_strcasecmp (value, "NO") == 0)
3862         *result = noval;
3863       else if (is_float && (f = strtod (value, &pos), pos != value))
3864         *result = make_float (f);
3865       else if (is_modstring && value)
3866         *result = ns_string_to_lispmod (value);
3867       else fprintf (stderr,
3868                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3869     }
3873 static void
3874 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3875 /* --------------------------------------------------------------------------
3876       Initialize global info and storage for display.
3877    -------------------------------------------------------------------------- */
3879     NSScreen *screen = [NSScreen mainScreen];
3880     NSWindowDepth depth = [screen depth];
3881     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3883     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3884     dpyinfo->resy = 72.27;
3885     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3886                                                   NSColorSpaceFromDepth (depth)]
3887                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3888                                                  NSColorSpaceFromDepth (depth)];
3889     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3890     dpyinfo->image_cache = make_image_cache ();
3891     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
3892     dpyinfo->color_table->colors = NULL;
3893     dpyinfo->root_window = 42; /* a placeholder.. */
3895     hlinfo->mouse_face_mouse_frame = NULL;
3896     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3897     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3898     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3899     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3900     hlinfo->mouse_face_hidden = 0;
3902     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3903     hlinfo->mouse_face_defer = 0;
3905     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3907     dpyinfo->n_fonts = 0;
3908     dpyinfo->smallest_font_height = 1;
3909     dpyinfo->smallest_char_width = 1;
3913 /* This and next define (many of the) public functions in this file. */
3914 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3915          with using despite presence in the "system dependent" redisplay
3916          interface.  In addition, many of the ns_ methods have code that is
3917          shared with all terms, indicating need for further refactoring. */
3918 extern frame_parm_handler ns_frame_parm_handlers[];
3919 static struct redisplay_interface ns_redisplay_interface =
3921   ns_frame_parm_handlers,
3922   x_produce_glyphs,
3923   x_write_glyphs,
3924   x_insert_glyphs,
3925   x_clear_end_of_line,
3926   ns_scroll_run,
3927   ns_after_update_window_line,
3928   ns_update_window_begin,
3929   ns_update_window_end,
3930   x_cursor_to,
3931   ns_flush,
3932   0, /* flush_display_optional */
3933   x_clear_window_mouse_face,
3934   x_get_glyph_overhangs,
3935   x_fix_overlapping_area,
3936   ns_draw_fringe_bitmap,
3937   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3938   0, /* destroy_fringe_bitmap */
3939   ns_compute_glyph_string_overhangs,
3940   ns_draw_glyph_string, /* interface to nsfont.m */
3941   ns_define_frame_cursor,
3942   ns_clear_frame_area,
3943   ns_draw_window_cursor,
3944   ns_draw_vertical_window_border,
3945   ns_shift_glyphs_for_insert
3949 static void
3950 ns_delete_display (struct ns_display_info *dpyinfo)
3952   /* TODO... */
3956 /* This function is called when the last frame on a display is deleted. */
3957 static void
3958 ns_delete_terminal (struct terminal *terminal)
3960   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3962   /* Protect against recursive calls.  delete_frame in
3963      delete_terminal calls us back when it deletes our last frame.  */
3964   if (!terminal->name)
3965     return;
3967   block_input ();
3969   x_destroy_all_bitmaps (dpyinfo);
3970   ns_delete_display (dpyinfo);
3971   unblock_input ();
3975 static struct terminal *
3976 ns_create_terminal (struct ns_display_info *dpyinfo)
3977 /* --------------------------------------------------------------------------
3978       Set up use of NS before we make the first connection.
3979    -------------------------------------------------------------------------- */
3981   struct terminal *terminal;
3983   NSTRACE (ns_create_terminal);
3985   terminal = create_terminal ();
3987   terminal->type = output_ns;
3988   terminal->display_info.ns = dpyinfo;
3989   dpyinfo->terminal = terminal;
3991   terminal->rif = &ns_redisplay_interface;
3993   terminal->clear_frame_hook = ns_clear_frame;
3994   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3995   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3996   terminal->ring_bell_hook = ns_ring_bell;
3997   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3998   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3999   terminal->update_begin_hook = ns_update_begin;
4000   terminal->update_end_hook = ns_update_end;
4001   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4002   terminal->read_socket_hook = ns_read_socket;
4003   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4004   terminal->mouse_position_hook = ns_mouse_position;
4005   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4006   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4008   terminal->fullscreen_hook = ns_fullscreen_hook;
4010   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4011   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4012   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4013   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4015   terminal->delete_frame_hook = x_destroy_window;
4016   terminal->delete_terminal_hook = ns_delete_terminal;
4018   terminal->scroll_region_ok = 1;
4019   terminal->char_ins_del_ok = 1;
4020   terminal->line_ins_del_ok = 1;
4021   terminal->fast_clear_end_of_line = 1;
4022   terminal->memory_below_frame = 0;
4024   return terminal;
4028 struct ns_display_info *
4029 ns_term_init (Lisp_Object display_name)
4030 /* --------------------------------------------------------------------------
4031      Start the Application and get things rolling.
4032    -------------------------------------------------------------------------- */
4034   struct terminal *terminal;
4035   struct ns_display_info *dpyinfo;
4036   static int ns_initialized = 0;
4037   Lisp_Object tmp;
4039   if (ns_initialized) return x_display_list;
4040   ns_initialized = 1;
4042   NSTRACE (ns_term_init);
4044   [outerpool release];
4045   outerpool = [[NSAutoreleasePool alloc] init];
4047   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4048   /*GSDebugAllocationActive (YES); */
4049   block_input ();
4051   baud_rate = 38400;
4052   Fset_input_interrupt_mode (Qnil);
4054   if (selfds[0] == -1)
4055     {
4056       if (pipe (selfds) == -1)
4057         {
4058           fprintf (stderr, "Failed to create pipe: %s\n",
4059                    emacs_strerror (errno));
4060           emacs_abort ();
4061         }
4063       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4064       FD_ZERO (&select_readfds);
4065       FD_ZERO (&select_writefds);
4066       pthread_mutex_init (&select_mutex, NULL);
4067     }
4069   ns_pending_files = [[NSMutableArray alloc] init];
4070   ns_pending_service_names = [[NSMutableArray alloc] init];
4071   ns_pending_service_args = [[NSMutableArray alloc] init];
4073 /* Start app and create the main menu, window, view.
4074      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4075      The view will then ask the NSApp to stop and return to Emacs. */
4076   [EmacsApp sharedApplication];
4077   if (NSApp == nil)
4078     return NULL;
4079   [NSApp setDelegate: NSApp];
4081   /* Start the select thread.  */
4082   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4083                            toTarget:NSApp
4084                          withObject:nil];
4086   /* debugging: log all notifications */
4087   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4088                                          selector: @selector (logNotification:)
4089                                              name: nil object: nil]; */
4091   dpyinfo = xzalloc (sizeof *dpyinfo);
4093   ns_initialize_display_info (dpyinfo);
4094   terminal = ns_create_terminal (dpyinfo);
4096   terminal->kboard = xmalloc (sizeof *terminal->kboard);
4097   init_kboard (terminal->kboard);
4098   kset_window_system (terminal->kboard, Qns);
4099   terminal->kboard->next_kboard = all_kboards;
4100   all_kboards = terminal->kboard;
4101   /* Don't let the initial kboard remain current longer than necessary.
4102      That would cause problems if a file loaded on startup tries to
4103      prompt in the mini-buffer.  */
4104   if (current_kboard == initial_kboard)
4105     current_kboard = terminal->kboard;
4106   terminal->kboard->reference_count++;
4108   dpyinfo->next = x_display_list;
4109   x_display_list = dpyinfo;
4111   /* Put it on ns_display_name_list */
4112   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4113                                 ns_display_name_list);
4114   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4116   terminal->name = xstrdup (SSDATA (display_name));
4118   unblock_input ();
4120   if (!inhibit_x_resources)
4121     {
4122       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4123                  Qt, Qnil, NO, NO);
4124       tmp = Qnil;
4125       /* this is a standard variable */
4126       ns_default ("AppleAntiAliasingThreshold", &tmp,
4127                  make_float (10.0), make_float (6.0), YES, NO);
4128       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4129     }
4131   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4132                          stringForKey: @"AppleHighlightColor"];
4133   if (ns_selection_color == nil)
4134     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4136   {
4137     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4139     if ( cl == nil )
4140       {
4141         Lisp_Object color_file, color_map, color;
4142         unsigned long c;
4143         char *name;
4145         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4146                          Fsymbol_value (intern ("data-directory")));
4148         color_map = Fx_load_color_file (color_file);
4149         if (NILP (color_map))
4150           fatal ("Could not read %s.\n", SDATA (color_file));
4152         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4153         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4154           {
4155             color = XCAR (color_map);
4156             name = SSDATA (XCAR (color));
4157             c = XINT (XCDR (color));
4158             [cl setColor:
4159                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4160                                             green: GREEN_FROM_ULONG (c) / 255.0
4161                                              blue: BLUE_FROM_ULONG (c) / 255.0
4162                                             alpha: 1.0]
4163                   forKey: [NSString stringWithUTF8String: name]];
4164           }
4165         [cl writeToFile: nil];
4166       }
4167   }
4169   {
4170 #ifdef NS_IMPL_GNUSTEP
4171     Vwindow_system_version = build_string (gnustep_base_version);
4172 #else
4173     /*PSnextrelease (128, c); */
4174     char c[DBL_BUFSIZE_BOUND];
4175     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4176     Vwindow_system_version = make_unibyte_string (c, len);
4177 #endif
4178   }
4180   delete_keyboard_wait_descriptor (0);
4182   ns_app_name = [[NSProcessInfo processInfo] processName];
4184 /* Set up OS X app menu */
4185 #ifdef NS_IMPL_COCOA
4186   {
4187     NSMenu *appMenu;
4188     NSMenuItem *item;
4189     /* set up the application menu */
4190     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4191     [svcsMenu setAutoenablesItems: NO];
4192     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4193     [appMenu setAutoenablesItems: NO];
4194     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4195     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4197     [appMenu insertItemWithTitle: @"About Emacs"
4198                           action: @selector (orderFrontStandardAboutPanel:)
4199                    keyEquivalent: @""
4200                          atIndex: 0];
4201     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4202     [appMenu insertItemWithTitle: @"Preferences..."
4203                           action: @selector (showPreferencesWindow:)
4204                    keyEquivalent: @","
4205                          atIndex: 2];
4206     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4207     item = [appMenu insertItemWithTitle: @"Services"
4208                                  action: @selector (menuDown:)
4209                           keyEquivalent: @""
4210                                 atIndex: 4];
4211     [appMenu setSubmenu: svcsMenu forItem: item];
4212     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4213     [appMenu insertItemWithTitle: @"Hide Emacs"
4214                           action: @selector (hide:)
4215                    keyEquivalent: @"h"
4216                          atIndex: 6];
4217     item =  [appMenu insertItemWithTitle: @"Hide Others"
4218                           action: @selector (hideOtherApplications:)
4219                    keyEquivalent: @"h"
4220                          atIndex: 7];
4221     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4222     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4223     [appMenu insertItemWithTitle: @"Quit Emacs"
4224                           action: @selector (terminate:)
4225                    keyEquivalent: @"q"
4226                          atIndex: 9];
4228     item = [mainMenu insertItemWithTitle: ns_app_name
4229                                   action: @selector (menuDown:)
4230                            keyEquivalent: @""
4231                                  atIndex: 0];
4232     [mainMenu setSubmenu: appMenu forItem: item];
4233     [dockMenu insertItemWithTitle: @"New Frame"
4234                            action: @selector (newFrame:)
4235                     keyEquivalent: @""
4236                           atIndex: 0];
4238     [NSApp setMainMenu: mainMenu];
4239     [NSApp setAppleMenu: appMenu];
4240     [NSApp setServicesMenu: svcsMenu];
4241     /* Needed at least on Cocoa, to get dock menu to show windows */
4242     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4244     [[NSNotificationCenter defaultCenter]
4245       addObserver: mainMenu
4246          selector: @selector (trackingNotification:)
4247              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4248     [[NSNotificationCenter defaultCenter]
4249       addObserver: mainMenu
4250          selector: @selector (trackingNotification:)
4251              name: NSMenuDidEndTrackingNotification object: mainMenu];
4252   }
4253 #endif /* MAC OS X menu setup */
4255   /* Register our external input/output types, used for determining
4256      applicable services and also drag/drop eligibility. */
4257   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4258   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4259                       retain];
4260   ns_drag_types = [[NSArray arrayWithObjects:
4261                             NSStringPboardType,
4262                             NSTabularTextPboardType,
4263                             NSFilenamesPboardType,
4264                             NSURLPboardType,
4265                             NSColorPboardType,
4266                             NSFontPboardType, nil] retain];
4268   /* If fullscreen is in init/default-frame-alist, focus isn't set
4269      right for fullscreen windows, so set this.  */
4270   [NSApp activateIgnoringOtherApps:YES];
4272   [NSApp run];
4273   ns_do_open_file = YES;
4274   return dpyinfo;
4278 void
4279 ns_term_shutdown (int sig)
4281   [[NSUserDefaults standardUserDefaults] synchronize];
4283   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4284   if (STRINGP (Vauto_save_list_file_name))
4285     unlink (SSDATA (Vauto_save_list_file_name));
4287   if (sig == 0 || sig == SIGTERM)
4288     {
4289       [NSApp terminate: NSApp];
4290     }
4291   else // force a stack trace to happen
4292     {
4293       emacs_abort ();
4294     }
4298 /* ==========================================================================
4300     EmacsApp implementation
4302    ========================================================================== */
4305 @implementation EmacsApp
4307 - (void)logNotification: (NSNotification *)notification
4309   const char *name = [[notification name] UTF8String];
4310   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4311       && !strstr (name, "WindowNumber"))
4312     NSLog (@"notification: '%@'", [notification name]);
4316 - (void)sendEvent: (NSEvent *)theEvent
4317 /* --------------------------------------------------------------------------
4318      Called when NSApp is running for each event received.  Used to stop
4319      the loop when we choose, since there's no way to just run one iteration.
4320    -------------------------------------------------------------------------- */
4322   int type = [theEvent type];
4323   NSWindow *window = [theEvent window];
4324 /*  NSTRACE (sendEvent); */
4325 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4327 #ifdef NS_IMPL_COCOA
4328   if (type == NSApplicationDefined
4329       && [theEvent data2] == NSAPP_DATA2_RUNASSCRIPT)
4330     {
4331       ns_run_ascript ();
4332       [self stop: self];
4333       return;
4334     }
4335 #endif
4337   if (type == NSCursorUpdate && window == nil)
4338     {
4339       fprintf (stderr, "Dropping external cursor update event.\n");
4340       return;
4341     }
4343   if (type == NSApplicationDefined)
4344     {
4345       /* Events posted by ns_send_appdefined interrupt the run loop here.
4346          But, if a modal window is up, an appdefined can still come through,
4347          (e.g., from a makeKeyWindow event) but stopping self also stops the
4348          modal loop. Just defer it until later. */
4349       if ([NSApp modalWindow] == nil)
4350         {
4351           last_appdefined_event_data = [theEvent data1];
4352           [self stop: self];
4353         }
4354       else
4355         {
4356           send_appdefined = YES;
4357         }
4358     }
4360   [super sendEvent: theEvent];
4364 - (void)showPreferencesWindow: (id)sender
4366   struct frame *emacsframe = SELECTED_FRAME ();
4367   NSEvent *theEvent = [NSApp currentEvent];
4369   if (!emacs_event)
4370     return;
4371   emacs_event->kind = NS_NONKEY_EVENT;
4372   emacs_event->code = KEY_NS_SHOW_PREFS;
4373   emacs_event->modifiers = 0;
4374   EV_TRAILER (theEvent);
4378 - (void)newFrame: (id)sender
4380   struct frame *emacsframe = SELECTED_FRAME ();
4381   NSEvent *theEvent = [NSApp currentEvent];
4383   if (!emacs_event)
4384     return;
4385   emacs_event->kind = NS_NONKEY_EVENT;
4386   emacs_event->code = KEY_NS_NEW_FRAME;
4387   emacs_event->modifiers = 0;
4388   EV_TRAILER (theEvent);
4392 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4393 - (BOOL) openFile: (NSString *)fileName
4395   struct frame *emacsframe = SELECTED_FRAME ();
4396   NSEvent *theEvent = [NSApp currentEvent];
4398   if (!emacs_event)
4399     return NO;
4401   emacs_event->kind = NS_NONKEY_EVENT;
4402   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4403   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4404   ns_input_line = Qnil; /* can be start or cons start,end */
4405   emacs_event->modifiers =0;
4406   EV_TRAILER (theEvent);
4408   return YES;
4412 /* **************************************************************************
4414       EmacsApp delegate implementation
4416    ************************************************************************** */
4418 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4419 /* --------------------------------------------------------------------------
4420      When application is loaded, terminate event loop in ns_term_init
4421    -------------------------------------------------------------------------- */
4423   NSTRACE (applicationDidFinishLaunching);
4424   [NSApp setServicesProvider: NSApp];
4425   ns_send_appdefined (-2);
4429 /* Termination sequences:
4430     C-x C-c:
4431     Cmd-Q:
4432     MenuBar | File | Exit:
4433     Select Quit from App menubar:
4434         -terminate
4435         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4436         ns_term_shutdown()
4438     Select Quit from Dock menu:
4439     Logout attempt:
4440         -appShouldTerminate
4441           Cancel -> Nothing else
4442           Accept ->
4444           -terminate
4445           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4446           ns_term_shutdown()
4450 - (void) terminate: (id)sender
4452   struct frame *emacsframe = SELECTED_FRAME ();
4454   if (!emacs_event)
4455     return;
4457   emacs_event->kind = NS_NONKEY_EVENT;
4458   emacs_event->code = KEY_NS_POWER_OFF;
4459   emacs_event->arg = Qt; /* mark as non-key event */
4460   EV_TRAILER ((id)nil);
4464 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4466   int ret;
4468   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4469     return NSTerminateNow;
4471     ret = NSRunAlertPanel(ns_app_name,
4472                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4473                           @"Save Buffers and Exit", @"Cancel", nil);
4475     if (ret == NSAlertDefaultReturn)
4476         return NSTerminateNow;
4477     else if (ret == NSAlertAlternateReturn)
4478         return NSTerminateCancel;
4479     return NSTerminateNow;  /* just in case */
4482 static int
4483 not_in_argv (NSString *arg)
4485   int k;
4486   const char *a = [arg UTF8String];
4487   for (k = 1; k < initial_argc; ++k)
4488     if (strcmp (a, initial_argv[k]) == 0) return 0;
4489   return 1;
4492 /*   Notification from the Workspace to open a file */
4493 - (BOOL)application: sender openFile: (NSString *)file
4495   if (ns_do_open_file || not_in_argv (file))
4496     [ns_pending_files addObject: file];
4497   return YES;
4501 /*   Open a file as a temporary file */
4502 - (BOOL)application: sender openTempFile: (NSString *)file
4504   if (ns_do_open_file || not_in_argv (file))
4505     [ns_pending_files addObject: file];
4506   return YES;
4510 /*   Notification from the Workspace to open a file noninteractively (?) */
4511 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4513   if (ns_do_open_file || not_in_argv (file))
4514     [ns_pending_files addObject: file];
4515   return YES;
4518 /*   Notification from the Workspace to open multiple files */
4519 - (void)application: sender openFiles: (NSArray *)fileList
4521   NSEnumerator *files = [fileList objectEnumerator];
4522   NSString *file;
4523   /* Don't open files from the command line unconditionally,
4524      Cocoa parses the command line wrong, --option value tries to open value
4525      if --option is the last option.  */
4526   while ((file = [files nextObject]) != nil)
4527     if (ns_do_open_file || not_in_argv (file))
4528       [ns_pending_files addObject: file];
4530   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4535 /* Handle dock menu requests.  */
4536 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4538   return dockMenu;
4542 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4543 - (void)applicationWillBecomeActive: (NSNotification *)notification
4545   //ns_app_active=YES;
4547 - (void)applicationDidBecomeActive: (NSNotification *)notification
4549   NSTRACE (applicationDidBecomeActive);
4551   //ns_app_active=YES;
4553   ns_update_auto_hide_menu_bar ();
4554   // No constraining takes place when the application is not active.
4555   ns_constrain_all_frames ();
4557 - (void)applicationDidResignActive: (NSNotification *)notification
4559   //ns_app_active=NO;
4560   ns_send_appdefined (-1);
4565 /* ==========================================================================
4567     EmacsApp aux handlers for managing event loop
4569    ========================================================================== */
4572 - (void)timeout_handler: (NSTimer *)timedEntry
4573 /* --------------------------------------------------------------------------
4574      The timeout specified to ns_select has passed.
4575    -------------------------------------------------------------------------- */
4577   /*NSTRACE (timeout_handler); */
4578   ns_send_appdefined (-2);
4581 - (void)fd_handler:(id)unused
4582 /* --------------------------------------------------------------------------
4583      Check data waiting on file descriptors and terminate if so
4584    -------------------------------------------------------------------------- */
4586   int result;
4587   int waiting = 1, nfds;
4588   char c;
4590   SELECT_TYPE readfds, writefds, *wfds;
4591   EMACS_TIME timeout, *tmo;
4592   NSAutoreleasePool *pool = nil;
4594   /* NSTRACE (fd_handler); */
4596   for (;;)
4597     {
4598       [pool release];
4599       pool = [[NSAutoreleasePool alloc] init];
4601       if (waiting)
4602         {
4603           SELECT_TYPE fds;
4604           FD_ZERO (&fds);
4605           FD_SET (selfds[0], &fds);
4606           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4607           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4608             waiting = 0;
4609         }
4610       else
4611         {
4612           pthread_mutex_lock (&select_mutex);
4613           nfds = select_nfds;
4615           if (select_valid & SELECT_HAVE_READ)
4616             readfds = select_readfds;
4617           else
4618             FD_ZERO (&readfds);
4620           if (select_valid & SELECT_HAVE_WRITE)
4621             {
4622               writefds = select_writefds;
4623               wfds = &writefds;
4624             }
4625           else
4626             wfds = NULL;
4627           if (select_valid & SELECT_HAVE_TMO)
4628             {
4629               timeout = select_timeout;
4630               tmo = &timeout;
4631             }
4632           else
4633             tmo = NULL;
4635           pthread_mutex_unlock (&select_mutex);
4637           FD_SET (selfds[0], &readfds);
4638           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4640           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4642           if (result == 0)
4643             ns_send_appdefined (-2);
4644           else if (result > 0)
4645             {
4646               if (FD_ISSET (selfds[0], &readfds))
4647                 {
4648                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4649                     waiting = 1;
4650                 }
4651               else
4652                 {
4653                   pthread_mutex_lock (&select_mutex);
4654                   if (select_valid & SELECT_HAVE_READ)
4655                     select_readfds = readfds;
4656                   if (select_valid & SELECT_HAVE_WRITE)
4657                     select_writefds = writefds;
4658                   if (select_valid & SELECT_HAVE_TMO)
4659                     select_timeout = timeout;
4660                   pthread_mutex_unlock (&select_mutex);
4662                   ns_send_appdefined (result);
4663                 }
4664             }
4665           waiting = 1;
4666         }
4667     }
4672 /* ==========================================================================
4674     Service provision
4676    ========================================================================== */
4678 /* called from system: queue for next pass through event loop */
4679 - (void)requestService: (NSPasteboard *)pboard
4680               userData: (NSString *)userData
4681                  error: (NSString **)error
4683   [ns_pending_service_names addObject: userData];
4684   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4685       SSDATA (ns_string_from_pasteboard (pboard))]];
4689 /* called from ns_read_socket to clear queue */
4690 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4692   struct frame *emacsframe = SELECTED_FRAME ();
4693   NSEvent *theEvent = [NSApp currentEvent];
4695   if (!emacs_event)
4696     return NO;
4698   emacs_event->kind = NS_NONKEY_EVENT;
4699   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4700   ns_input_spi_name = build_string ([name UTF8String]);
4701   ns_input_spi_arg = build_string ([arg UTF8String]);
4702   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4703   EV_TRAILER (theEvent);
4705   return YES;
4709 @end  /* EmacsApp */
4713 /* ==========================================================================
4715     EmacsView implementation
4717    ========================================================================== */
4720 @implementation EmacsView
4722 /* needed to inform when window closed from LISP */
4723 - (void) setWindowClosing: (BOOL)closing
4725   windowClosing = closing;
4729 - (void)dealloc
4731   NSTRACE (EmacsView_dealloc);
4732   [toolbar release];
4733   if (fs_state == FULLSCREEN_BOTH)
4734     [nonfs_window release];
4735   [super dealloc];
4739 /* called on font panel selection */
4740 - (void)changeFont: (id)sender
4742   NSEvent *e =[[self window] currentEvent];
4743   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4744   id newFont;
4745   float size;
4747   NSTRACE (changeFont);
4748   if (!emacs_event)
4749     return;
4751   if ((newFont = [sender convertFont:
4752                            ((struct nsfont_info *)face->font)->nsfont]))
4753     {
4754       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4756       emacs_event->kind = NS_NONKEY_EVENT;
4757       emacs_event->modifiers = 0;
4758       emacs_event->code = KEY_NS_CHANGE_FONT;
4760       size = [newFont pointSize];
4761       ns_input_fontsize = make_number (lrint (size));
4762       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4763       EV_TRAILER (e);
4764     }
4768 - (BOOL)acceptsFirstResponder
4770   NSTRACE (acceptsFirstResponder);
4771   return YES;
4775 - (void)resetCursorRects
4777   NSRect visible = [self visibleRect];
4778   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4779   NSTRACE (resetCursorRects);
4781   if (currentCursor == nil)
4782     currentCursor = [NSCursor arrowCursor];
4784   if (!NSIsEmptyRect (visible))
4785     [self addCursorRect: visible cursor: currentCursor];
4786   [currentCursor setOnMouseEntered: YES];
4791 /*****************************************************************************/
4792 /* Keyboard handling. */
4793 #define NS_KEYLOG 0
4795 - (void)keyDown: (NSEvent *)theEvent
4797   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4798   int code;
4799   unsigned fnKeysym = 0;
4800   static NSMutableArray *nsEvArray;
4801 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4802   static BOOL firstTime = YES;
4803 #endif
4804   int left_is_none;
4805   unsigned int flags = [theEvent modifierFlags];
4807   NSTRACE (keyDown);
4809   /* Rhapsody and OS X give up and down events for the arrow keys */
4810   if (ns_fake_keydown == YES)
4811     ns_fake_keydown = NO;
4812   else if ([theEvent type] != NSKeyDown)
4813     return;
4815   if (!emacs_event)
4816     return;
4818  if (![[self window] isKeyWindow]
4819      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4820      /* we must avoid an infinite loop here. */
4821      && (EmacsView *)[[theEvent window] delegate] != self)
4822    {
4823      /* XXX: There is an occasional condition in which, when Emacs display
4824          updates a different frame from the current one, and temporarily
4825          selects it, then processes some interrupt-driven input
4826          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4827          for some reason that window has its first responder set to the NSView
4828          most recently updated (I guess), which is not the correct one. */
4829      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4830      return;
4831    }
4833   if (nsEvArray == nil)
4834     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4836   [NSCursor setHiddenUntilMouseMoves: YES];
4838   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4839     {
4840       clear_mouse_face (hlinfo);
4841       hlinfo->mouse_face_hidden = 1;
4842     }
4844   if (!processingCompose)
4845     {
4846       /* When using screen sharing, no left or right information is sent,
4847          so use Left key in those cases.  */
4848       int is_left_key, is_right_key;
4850       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4851         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4853       /* (Carbon way: [theEvent keyCode]) */
4855       /* is it a "function key"? */
4856       fnKeysym = (code < 0x00ff && (flags&NSNumericPadKeyMask))
4857         ? ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask)
4858         : ns_convert_key (code);
4860       if (fnKeysym)
4861         {
4862           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4863              because Emacs treats Delete and KP-Delete same (in simple.el). */
4864           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4865             code = 0xFF08; /* backspace */
4866           else
4867             code = fnKeysym;
4868         }
4870       /* are there modifiers? */
4871       emacs_event->modifiers = 0;
4873       if (flags & NSHelpKeyMask)
4874           emacs_event->modifiers |= hyper_modifier;
4876       if (flags & NSShiftKeyMask)
4877         emacs_event->modifiers |= shift_modifier;
4879       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
4880       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
4881         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
4883       if (is_right_key)
4884         emacs_event->modifiers |= parse_solitary_modifier
4885           (EQ (ns_right_command_modifier, Qleft)
4886            ? ns_command_modifier
4887            : ns_right_command_modifier);
4889       if (is_left_key)
4890         {
4891           emacs_event->modifiers |= parse_solitary_modifier
4892             (ns_command_modifier);
4894           /* if super (default), take input manager's word so things like
4895              dvorak / qwerty layout work */
4896           if (EQ (ns_command_modifier, Qsuper)
4897               && !fnKeysym
4898               && [[theEvent characters] length] != 0)
4899             {
4900               /* XXX: the code we get will be unshifted, so if we have
4901                  a shift modifier, must convert ourselves */
4902               if (!(flags & NSShiftKeyMask))
4903                 code = [[theEvent characters] characterAtIndex: 0];
4904 #if 0
4905               /* this is ugly and also requires linking w/Carbon framework
4906                  (for LMGetKbdType) so for now leave this rare (?) case
4907                  undealt with.. in future look into CGEvent methods */
4908               else
4909                 {
4910                   long smv = GetScriptManagerVariable (smKeyScript);
4911                   Handle uchrHandle = GetResource
4912                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4913                   UInt32 dummy = 0;
4914                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4915                                  [[theEvent characters] characterAtIndex: 0],
4916                                  kUCKeyActionDisplay,
4917                                  (flags & ~NSCommandKeyMask) >> 8,
4918                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4919                                  &dummy, 1, &dummy, &code);
4920                   code &= 0xFF;
4921                 }
4922 #endif
4923             }
4924         }
4926       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
4927       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
4928         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
4930       if (is_right_key)
4931           emacs_event->modifiers |= parse_solitary_modifier
4932               (EQ (ns_right_control_modifier, Qleft)
4933                ? ns_control_modifier
4934                : ns_right_control_modifier);
4936       if (is_left_key)
4937         emacs_event->modifiers |= parse_solitary_modifier
4938           (ns_control_modifier);
4940       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4941           emacs_event->modifiers |=
4942             parse_solitary_modifier (ns_function_modifier);
4944       left_is_none = NILP (ns_alternate_modifier)
4945         || EQ (ns_alternate_modifier, Qnone);
4947       is_right_key = (flags & NSRightAlternateKeyMask)
4948         == NSRightAlternateKeyMask;
4949       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
4950         || (! is_right_key
4951             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
4953       if (is_right_key)
4954         {
4955           if ((NILP (ns_right_alternate_modifier)
4956                || EQ (ns_right_alternate_modifier, Qnone)
4957                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4958               && !fnKeysym)
4959             {   /* accept pre-interp alt comb */
4960               if ([[theEvent characters] length] > 0)
4961                 code = [[theEvent characters] characterAtIndex: 0];
4962               /*HACK: clear lone shift modifier to stop next if from firing */
4963               if (emacs_event->modifiers == shift_modifier)
4964                 emacs_event->modifiers = 0;
4965             }
4966           else
4967             emacs_event->modifiers |= parse_solitary_modifier
4968               (EQ (ns_right_alternate_modifier, Qleft)
4969                ? ns_alternate_modifier
4970                : ns_right_alternate_modifier);
4971         }
4973       if (is_left_key) /* default = meta */
4974         {
4975           if (left_is_none && !fnKeysym)
4976             {   /* accept pre-interp alt comb */
4977               if ([[theEvent characters] length] > 0)
4978                 code = [[theEvent characters] characterAtIndex: 0];
4979               /*HACK: clear lone shift modifier to stop next if from firing */
4980               if (emacs_event->modifiers == shift_modifier)
4981                 emacs_event->modifiers = 0;
4982             }
4983           else
4984               emacs_event->modifiers |=
4985                 parse_solitary_modifier (ns_alternate_modifier);
4986         }
4988   if (NS_KEYLOG)
4989     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4990              code, fnKeysym, flags, emacs_event->modifiers);
4992       /* if it was a function key or had modifiers, pass it directly to emacs */
4993       if (fnKeysym || (emacs_event->modifiers
4994                        && (emacs_event->modifiers != shift_modifier)
4995                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4996 /*[[theEvent characters] length] */
4997         {
4998           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4999           if (code < 0x20)
5000             code |= (1<<28)|(3<<16);
5001           else if (code == 0x7f)
5002             code |= (1<<28)|(3<<16);
5003           else if (!fnKeysym)
5004             emacs_event->kind = code > 0xFF
5005               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5007           emacs_event->code = code;
5008           EV_TRAILER (theEvent);
5009           processingCompose = NO;
5010           return;
5011         }
5012     }
5015 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5016   /* if we get here we should send the key for input manager processing */
5017   if (firstTime && [[NSInputManager currentInputManager]
5018                      wantsToDelayTextChangeNotifications] == NO)
5019     fprintf (stderr,
5020           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5021   firstTime = NO;
5022 #endif
5023   if (NS_KEYLOG && !processingCompose)
5024     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5026   processingCompose = YES;
5027   [nsEvArray addObject: theEvent];
5028   [self interpretKeyEvents: nsEvArray];
5029   [nsEvArray removeObject: theEvent];
5033 #ifdef NS_IMPL_COCOA
5034 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5035    decided not to send key-down for.
5036    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5037    This only applies on Tiger and earlier.
5038    If it matches one of these, send it on to keyDown. */
5039 -(void)keyUp: (NSEvent *)theEvent
5041   int flags = [theEvent modifierFlags];
5042   int code = [theEvent keyCode];
5043   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5044       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5045     {
5046       if (NS_KEYLOG)
5047         fprintf (stderr, "keyUp: passed test");
5048       ns_fake_keydown = YES;
5049       [self keyDown: theEvent];
5050     }
5052 #endif
5055 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5058 /* <NSTextInput>: called when done composing;
5059    NOTE: also called when we delete over working text, followed immed.
5060          by doCommandBySelector: deleteBackward: */
5061 - (void)insertText: (id)aString
5063   int code;
5064   int len = [(NSString *)aString length];
5065   int i;
5067   if (NS_KEYLOG)
5068     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5069   processingCompose = NO;
5071   if (!emacs_event)
5072     return;
5074   /* first, clear any working text */
5075   if (workingText != nil)
5076     [self deleteWorkingText];
5078   /* now insert the string as keystrokes */
5079   for (i =0; i<len; i++)
5080     {
5081       code = [aString characterAtIndex: i];
5082       /* TODO: still need this? */
5083       if (code == 0x2DC)
5084         code = '~'; /* 0x7E */
5085       if (code != 32) /* Space */
5086         emacs_event->modifiers = 0;
5087       emacs_event->kind
5088         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5089       emacs_event->code = code;
5090       EV_TRAILER ((id)nil);
5091     }
5095 /* <NSTextInput>: inserts display of composing characters */
5096 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5098   NSString *str = [aString respondsToSelector: @selector (string)] ?
5099     [aString string] : aString;
5100   if (NS_KEYLOG)
5101     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
5102            selRange.length, selRange.location);
5104   if (workingText != nil)
5105     [self deleteWorkingText];
5106   if ([str length] == 0)
5107     return;
5109   if (!emacs_event)
5110     return;
5112   processingCompose = YES;
5113   workingText = [str copy];
5114   ns_working_text = build_string ([workingText UTF8String]);
5116   emacs_event->kind = NS_TEXT_EVENT;
5117   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5118   EV_TRAILER ((id)nil);
5122 /* delete display of composing characters [not in <NSTextInput>] */
5123 - (void)deleteWorkingText
5125   if (workingText == nil)
5126     return;
5127   if (NS_KEYLOG)
5128     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
5129   [workingText release];
5130   workingText = nil;
5131   processingCompose = NO;
5133   if (!emacs_event)
5134     return;
5136   emacs_event->kind = NS_TEXT_EVENT;
5137   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5138   EV_TRAILER ((id)nil);
5142 - (BOOL)hasMarkedText
5144   return workingText != nil;
5148 - (NSRange)markedRange
5150   NSRange rng = workingText != nil
5151     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5152   if (NS_KEYLOG)
5153     NSLog (@"markedRange request");
5154   return rng;
5158 - (void)unmarkText
5160   if (NS_KEYLOG)
5161     NSLog (@"unmark (accept) text");
5162   [self deleteWorkingText];
5163   processingCompose = NO;
5167 /* used to position char selection windows, etc. */
5168 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5170   NSRect rect;
5171   NSPoint pt;
5172   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5173   if (NS_KEYLOG)
5174     NSLog (@"firstRectForCharRange request");
5176   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5177   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5178   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5179   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5180                                        +FRAME_LINE_HEIGHT (emacsframe));
5182   pt = [self convertPoint: pt toView: nil];
5183   pt = [[self window] convertBaseToScreen: pt];
5184   rect.origin = pt;
5185   return rect;
5189 - (NSInteger)conversationIdentifier
5191   return (NSInteger)self;
5195 - (void)doCommandBySelector: (SEL)aSelector
5197   if (NS_KEYLOG)
5198     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5200   processingCompose = NO;
5201   if (aSelector == @selector (deleteBackward:))
5202     {
5203       /* happens when user backspaces over an ongoing composition:
5204          throw a 'delete' into the event queue */
5205       if (!emacs_event)
5206         return;
5207       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5208       emacs_event->code = 0xFF08;
5209       EV_TRAILER ((id)nil);
5210     }
5213 - (NSArray *)validAttributesForMarkedText
5215   static NSArray *arr = nil;
5216   if (arr == nil) arr = [NSArray new];
5217  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5218   return arr;
5221 - (NSRange)selectedRange
5223   if (NS_KEYLOG)
5224     NSLog (@"selectedRange request");
5225   return NSMakeRange (NSNotFound, 0);
5228 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5230   if (NS_KEYLOG)
5231     NSLog (@"characterIndexForPoint request");
5232   return 0;
5235 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5237   static NSAttributedString *str = nil;
5238   if (str == nil) str = [NSAttributedString new];
5239   if (NS_KEYLOG)
5240     NSLog (@"attributedSubstringFromRange request");
5241   return str;
5244 /* End <NSTextInput> impl. */
5245 /*****************************************************************************/
5248 /* This is what happens when the user presses a mouse button.  */
5249 - (void)mouseDown: (NSEvent *)theEvent
5251   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5253   NSTRACE (mouseDown);
5255   [self deleteWorkingText];
5257   if (!emacs_event)
5258     return;
5260   last_mouse_frame = emacsframe;
5261   /* appears to be needed to prevent spurious movement events generated on
5262      button clicks */
5263   last_mouse_frame->mouse_moved = 0;
5265   if ([theEvent type] == NSScrollWheel)
5266     {
5267       float delta = [theEvent deltaY];
5268       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5269       if (delta == 0)
5270         return;
5271       emacs_event->kind = WHEEL_EVENT;
5272       emacs_event->code = 0;
5273       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5274         ((delta > 0) ? up_modifier : down_modifier);
5275     }
5276   else
5277     {
5278       emacs_event->kind = MOUSE_CLICK_EVENT;
5279       emacs_event->code = EV_BUTTON (theEvent);
5280       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5281                              | EV_UDMODIFIERS (theEvent);
5282     }
5283   XSETINT (emacs_event->x, lrint (p.x));
5284   XSETINT (emacs_event->y, lrint (p.y));
5285   EV_TRAILER (theEvent);
5289 - (void)rightMouseDown: (NSEvent *)theEvent
5291   NSTRACE (rightMouseDown);
5292   [self mouseDown: theEvent];
5296 - (void)otherMouseDown: (NSEvent *)theEvent
5298   NSTRACE (otherMouseDown);
5299   [self mouseDown: theEvent];
5303 - (void)mouseUp: (NSEvent *)theEvent
5305   NSTRACE (mouseUp);
5306   [self mouseDown: theEvent];
5310 - (void)rightMouseUp: (NSEvent *)theEvent
5312   NSTRACE (rightMouseUp);
5313   [self mouseDown: theEvent];
5317 - (void)otherMouseUp: (NSEvent *)theEvent
5319   NSTRACE (otherMouseUp);
5320   [self mouseDown: theEvent];
5324 - (void) scrollWheel: (NSEvent *)theEvent
5326   NSTRACE (scrollWheel);
5327   [self mouseDown: theEvent];
5331 /* Tell emacs the mouse has moved. */
5332 - (void)mouseMoved: (NSEvent *)e
5334   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5335   Lisp_Object frame;
5337 //  NSTRACE (mouseMoved);
5339   last_mouse_movement_time = EV_TIMESTAMP (e);
5340   last_mouse_motion_position
5341     = [self convertPoint: [e locationInWindow] fromView: nil];
5343   /* update any mouse face */
5344   if (hlinfo->mouse_face_hidden)
5345     {
5346       hlinfo->mouse_face_hidden = 0;
5347       clear_mouse_face (hlinfo);
5348     }
5350   /* tooltip handling */
5351   previous_help_echo_string = help_echo_string;
5352   help_echo_string = Qnil;
5354   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5355                             last_mouse_motion_position.y))
5356     help_echo_string = previous_help_echo_string;
5358   XSETFRAME (frame, emacsframe);
5359   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5360     {
5361       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5362          (note_mouse_highlight), which is called through the
5363          note_mouse_movement () call above */
5364       gen_help_event (help_echo_string, frame, help_echo_window,
5365                       help_echo_object, help_echo_pos);
5366     }
5367   else
5368     {
5369       help_echo_string = Qnil;
5370       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5371     }
5373   if (emacsframe->mouse_moved && send_appdefined)
5374     ns_send_appdefined (-1);
5378 - (void)mouseDragged: (NSEvent *)e
5380   NSTRACE (mouseDragged);
5381   [self mouseMoved: e];
5385 - (void)rightMouseDragged: (NSEvent *)e
5387   NSTRACE (rightMouseDragged);
5388   [self mouseMoved: e];
5392 - (void)otherMouseDragged: (NSEvent *)e
5394   NSTRACE (otherMouseDragged);
5395   [self mouseMoved: e];
5399 - (BOOL)windowShouldClose: (id)sender
5401   NSEvent *e =[[self window] currentEvent];
5403   NSTRACE (windowShouldClose);
5404   windowClosing = YES;
5405   if (!emacs_event)
5406     return NO;
5407   emacs_event->kind = DELETE_WINDOW_EVENT;
5408   emacs_event->modifiers = 0;
5409   emacs_event->code = 0;
5410   EV_TRAILER (e);
5411   /* Don't close this window, let this be done from lisp code.  */
5412   return NO;
5415 - (void) updateFrameSize: (BOOL) delay;
5417   NSWindow *window = [self window];
5418   NSRect wr = [window frame];
5419   int extra = 0;
5420   int gsextra = 0;
5421 #ifdef NS_IMPL_GNUSTEP
5422   gsextra = 3;
5423 #endif
5425   int oldc = cols, oldr = rows;
5426   int oldw = FRAME_PIXEL_WIDTH (emacsframe),
5427     oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5428   int neww, newh;
5430   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, wr.size.width + gsextra);
5432   if (cols < MINWIDTH)
5433     cols = MINWIDTH;
5435   if (! [self isFullscreen])
5436     {
5437       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5438         + FRAME_TOOLBAR_HEIGHT (emacsframe) - gsextra;
5439     }
5441   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, wr.size.height - extra);
5443   if (rows < MINHEIGHT)
5444     rows = MINHEIGHT;
5446   neww = (int)wr.size.width - emacsframe->border_width;
5447   newh = (int)wr.size.height - extra;
5449   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5450     {
5451       NSView *view = FRAME_NS_VIEW (emacsframe);
5452       FRAME_PIXEL_WIDTH (emacsframe) = neww;
5453       FRAME_PIXEL_HEIGHT (emacsframe) = newh;
5454       change_frame_size (emacsframe, rows, cols, 0, delay, 0);
5455       SET_FRAME_GARBAGED (emacsframe);
5456       cancel_mouse_face (emacsframe);
5457       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5458       [self windowDidMove:nil];   // Update top/left.
5459     }
5462 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5463 /* normalize frame to gridded text size */
5465   int extra = 0;
5466   int gsextra = 0;
5467 #ifdef NS_IMPL_GNUSTEP
5468   gsextra = 3;
5469 #endif
5470   
5471   NSTRACE (windowWillResize);
5472 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5474   if (fs_state == FULLSCREEN_MAXIMIZED
5475       && (maximized_width != (int)frameSize.width
5476           || maximized_height != (int)frameSize.height))
5477     [self setFSValue: FULLSCREEN_NONE];
5478   else if (fs_state == FULLSCREEN_WIDTH
5479            && maximized_width != (int)frameSize.width)
5480     [self setFSValue: FULLSCREEN_NONE];
5481   else if (fs_state == FULLSCREEN_HEIGHT
5482            && maximized_height != (int)frameSize.height)
5483     [self setFSValue: FULLSCREEN_NONE];
5484   if (fs_state == FULLSCREEN_NONE)
5485     maximized_width = maximized_height = -1;
5487   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5488                                          frameSize.width + gsextra);
5489   if (cols < MINWIDTH)
5490     cols = MINWIDTH;
5492   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5493                                            frameSize.height - extra);
5494   if (rows < MINHEIGHT)
5495     rows = MINHEIGHT;
5496 #ifdef NS_IMPL_COCOA
5497   {
5498     /* this sets window title to have size in it; the wm does this under GS */
5499     NSRect r = [[self window] frame];
5500     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5501       {
5502         if (old_title != 0)
5503           {
5504             xfree (old_title);
5505             old_title = 0;
5506           }
5507       }
5508     else
5509       {
5510         char *size_title;
5511         NSWindow *window = [self window];
5512         if (old_title == 0)
5513           {
5514             const char *t = [[[self window] title] UTF8String];
5515             char *pos = strstr (t, "  â€”  ");
5516             if (pos)
5517               *pos = '\0';
5518             old_title = xstrdup (t);
5519           }
5520         size_title = xmalloc (strlen (old_title) + 40);
5521         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5522         [window setTitle: [NSString stringWithUTF8String: size_title]];
5523         [window display];
5524         xfree (size_title);
5525       }
5526   }
5527 #endif /* NS_IMPL_COCOA */
5528 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5530   return frameSize;
5534 - (void)windowDidResize: (NSNotification *)notification
5536   if (! [self fsIsNative]) 
5537     {
5538       NSWindow *theWindow = [notification object];
5539       /* We can get notification on the non-FS window when in
5540          fullscreen mode.  */
5541       if ([self window] != theWindow) return;
5542     }
5544 #ifdef NS_IMPL_GNUSTEP
5545   NSWindow *theWindow = [notification object];
5547    /* In GNUstep, at least currently, it's possible to get a didResize
5548       without getting a willResize.. therefore we need to act as if we got
5549       the willResize now */
5550   NSSize sz = [theWindow frame].size;
5551   sz = [self windowWillResize: theWindow toSize: sz];
5552 #endif /* NS_IMPL_GNUSTEP */
5554   NSTRACE (windowDidResize);
5555 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5557 #ifdef NS_IMPL_COCOA
5558   if (old_title != 0)
5559     {
5560       xfree (old_title);
5561       old_title = 0;
5562     }
5563 #endif /* NS_IMPL_COCOA */
5565   if (cols > 0 && rows > 0)
5566     {
5567       [self updateFrameSize: YES];
5568     }
5570   ns_send_appdefined (-1);
5574 - (void)windowDidBecomeKey: (NSNotification *)notification
5575 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5577   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5578   struct frame *old_focus = dpyinfo->x_focus_frame;
5580   NSTRACE (windowDidBecomeKey);
5582   if (emacsframe != old_focus)
5583     dpyinfo->x_focus_frame = emacsframe;
5585   ns_frame_rehighlight (emacsframe);
5587   if (emacs_event)
5588     {
5589       emacs_event->kind = FOCUS_IN_EVENT;
5590       EV_TRAILER ((id)nil);
5591     }
5595 - (void)windowDidResignKey: (NSNotification *)notification
5596 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5598   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5599   NSTRACE (windowDidResignKey);
5601   if (dpyinfo->x_focus_frame == emacsframe)
5602     dpyinfo->x_focus_frame = 0;
5604   ns_frame_rehighlight (emacsframe);
5606   /* FIXME: for some reason needed on second and subsequent clicks away
5607             from sole-frame Emacs to get hollow box to show */
5608   if (!windowClosing && [[self window] isVisible] == YES)
5609     {
5610       x_update_cursor (emacsframe, 1);
5611       x_set_frame_alpha (emacsframe);
5612     }
5614   if (emacs_event)
5615     {
5616       [self deleteWorkingText];
5617       emacs_event->kind = FOCUS_IN_EVENT;
5618       EV_TRAILER ((id)nil);
5619     }
5623 - (void)windowWillMiniaturize: sender
5625   NSTRACE (windowWillMiniaturize);
5629 - (BOOL)isFlipped
5631   return YES;
5635 - (BOOL)isOpaque
5637   return NO;
5641 - initFrameFromEmacs: (struct frame *)f
5643   NSRect r, wr;
5644   Lisp_Object tem;
5645   NSWindow *win;
5646   NSButton *toggleButton;
5647   NSSize sz;
5648   NSColor *col;
5649   NSString *name;
5651   NSTRACE (initFrameFromEmacs);
5653   windowClosing = NO;
5654   processingCompose = NO;
5655   scrollbarsNeedingUpdate = 0;
5656   fs_state = FULLSCREEN_NONE;
5657   fs_before_fs = next_maximized = -1;
5658 #ifdef HAVE_NATIVE_FS
5659   fs_is_native = ns_use_native_fullscreen;
5660 #else
5661   fs_is_native = NO;
5662 #endif
5663   maximized_width = maximized_height = -1;
5664   nonfs_window = nil;
5666 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5668   ns_userRect = NSMakeRect (0, 0, 0, 0);
5669   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5670                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5671   [self initWithFrame: r];
5672   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5674   FRAME_NS_VIEW (f) = self;
5675   emacsframe = f;
5676   old_title = 0;
5678   win = [[EmacsWindow alloc]
5679             initWithContentRect: r
5680                       styleMask: (NSResizableWindowMask |
5681 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5682                                   NSTitledWindowMask |
5683 #endif
5684                                   NSMiniaturizableWindowMask |
5685                                   NSClosableWindowMask)
5686                         backing: NSBackingStoreBuffered
5687                           defer: YES];
5689 #ifdef HAVE_NATIVE_FS
5690     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
5691 #endif
5693   wr = [win frame];
5694   bwidth = f->border_width = wr.size.width - r.size.width;
5695   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5697   [win setAcceptsMouseMovedEvents: YES];
5698   [win setDelegate: self];
5699   [win useOptimizedDrawing: YES];
5701   sz.width = FRAME_COLUMN_WIDTH (f);
5702   sz.height = FRAME_LINE_HEIGHT (f);
5703   [win setResizeIncrements: sz];
5705   [[win contentView] addSubview: self];
5707   if (ns_drag_types)
5708     [self registerForDraggedTypes: ns_drag_types];
5710   tem = f->name;
5711   name = [NSString stringWithUTF8String:
5712                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5713   [win setTitle: name];
5715   /* toolbar support */
5716   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5717                          [NSString stringWithFormat: @"Emacs Frame %d",
5718                                    ns_window_num]];
5719   [win setToolbar: toolbar];
5720   [toolbar setVisible: NO];
5721 #ifdef NS_IMPL_COCOA
5722   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5723   [toggleButton setTarget: self];
5724   [toggleButton setAction: @selector (toggleToolbar: )];
5725 #endif
5726   FRAME_TOOLBAR_HEIGHT (f) = 0;
5728   tem = f->icon_name;
5729   if (!NILP (tem))
5730     [win setMiniwindowTitle:
5731            [NSString stringWithUTF8String: SSDATA (tem)]];
5733   {
5734     NSScreen *screen = [win screen];
5736     if (screen != 0)
5737       [win setFrameTopLeftPoint: NSMakePoint
5738            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5739             IN_BOUND (-SCREENMAX,
5740                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5741   }
5743   [win makeFirstResponder: self];
5745   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5746                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5747   [win setBackgroundColor: col];
5748   if ([col alphaComponent] != 1.0)
5749     [win setOpaque: NO];
5751   [self allocateGState];
5753   [NSApp registerServicesMenuSendTypes: ns_send_types
5754                            returnTypes: nil];
5756   ns_window_num++;
5757   return self;
5761 - (void)windowDidMove: sender
5763   NSWindow *win = [self window];
5764   NSRect r = [win frame];
5765   NSArray *screens = [NSScreen screens];
5766   NSScreen *screen = [screens objectAtIndex: 0];
5768   NSTRACE (windowDidMove);
5770   if (!emacsframe->output_data.ns)
5771     return;
5772   if (screen != nil)
5773     {
5774       emacsframe->left_pos = r.origin.x;
5775       emacsframe->top_pos =
5776         [screen frame].size.height - (r.origin.y + r.size.height);
5777     }
5781 /* Called AFTER method below, but before our windowWillResize call there leads
5782    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5783    location so set_window_size moves the frame. */
5784 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5786   emacsframe->output_data.ns->zooming = 1;
5787   return YES;
5791 /* Override to do something slightly nonstandard, but nice.  First click on
5792    zoom button will zoom vertically.  Second will zoom completely.  Third
5793    returns to original. */
5794 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5795                         defaultFrame:(NSRect)defaultFrame
5797   NSRect result = [sender frame];
5799   NSTRACE (windowWillUseStandardFrame);
5801   if (fs_before_fs != -1) /* Entering fullscreen */
5802       {
5803         result = defaultFrame;
5804       }
5805   else if (next_maximized == FULLSCREEN_HEIGHT
5806       || (next_maximized == -1
5807           && abs (defaultFrame.size.height - result.size.height)
5808           > FRAME_LINE_HEIGHT (emacsframe)))
5809     {
5810       /* first click */
5811       ns_userRect = result;
5812       maximized_height = result.size.height = defaultFrame.size.height;
5813       maximized_width = -1;
5814       result.origin.y = defaultFrame.origin.y;
5815       [self setFSValue: FULLSCREEN_HEIGHT];
5816     }
5817   else if (next_maximized == FULLSCREEN_WIDTH)
5818     {
5819       ns_userRect = result;
5820       maximized_width = result.size.width = defaultFrame.size.width;
5821       maximized_height = -1;
5822       result.origin.x = defaultFrame.origin.x;
5823       [self setFSValue: FULLSCREEN_WIDTH];
5824     }
5825   else if (next_maximized == FULLSCREEN_MAXIMIZED
5826            || (next_maximized == -1
5827                && abs (defaultFrame.size.width - result.size.width)
5828                > FRAME_COLUMN_WIDTH (emacsframe)))
5829     {
5830       result = defaultFrame;  /* second click */
5831       maximized_width = result.size.width;
5832       maximized_height = result.size.height;
5833       [self setFSValue: FULLSCREEN_MAXIMIZED];
5834     }
5835   else
5836     {
5837       /* restore */
5838       result = ns_userRect.size.height ? ns_userRect : result;
5839       ns_userRect = NSMakeRect (0, 0, 0, 0);
5840       [self setFSValue: FULLSCREEN_NONE];
5841       maximized_width = maximized_width = -1;
5842     }
5844   if (fs_before_fs == -1) next_maximized = -1;
5845   [self windowWillResize: sender toSize: result.size];
5846   return result;
5850 - (void)windowDidDeminiaturize: sender
5852   NSTRACE (windowDidDeminiaturize);
5853   if (!emacsframe->output_data.ns)
5854     return;
5856   SET_FRAME_ICONIFIED (emacsframe, 0);
5857   SET_FRAME_VISIBLE (emacsframe, 1);
5858   windows_or_buffers_changed++;
5860   if (emacs_event)
5861     {
5862       emacs_event->kind = DEICONIFY_EVENT;
5863       EV_TRAILER ((id)nil);
5864     }
5868 - (void)windowDidExpose: sender
5870   NSTRACE (windowDidExpose);
5871   if (!emacsframe->output_data.ns)
5872     return;
5874   SET_FRAME_VISIBLE (emacsframe, 1);
5875   SET_FRAME_GARBAGED (emacsframe);
5877   if (send_appdefined)
5878     ns_send_appdefined (-1);
5882 - (void)windowDidMiniaturize: sender
5884   NSTRACE (windowDidMiniaturize);
5885   if (!emacsframe->output_data.ns)
5886     return;
5888   SET_FRAME_ICONIFIED (emacsframe, 1);
5889   SET_FRAME_VISIBLE (emacsframe, 0);
5891   if (emacs_event)
5892     {
5893       emacs_event->kind = ICONIFY_EVENT;
5894       EV_TRAILER ((id)nil);
5895     }
5898 #ifdef HAVE_NATIVE_FS
5899 - (NSApplicationPresentationOptions)window:(NSWindow *)window
5900       willUseFullScreenPresentationOptions:
5901   (NSApplicationPresentationOptions)proposedOptions
5903   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
5905 #endif
5907 - (void)windowWillEnterFullScreen:(NSNotification *)notification
5909   fs_before_fs = fs_state;
5912 - (void)windowDidEnterFullScreen:(NSNotification *)notification
5914   [self setFSValue: FULLSCREEN_BOTH];
5915   if (! [self fsIsNative])
5916     {
5917       [self windowDidBecomeKey:notification];
5918       [nonfs_window orderOut:self];
5919     }
5920   else if (! FRAME_EXTERNAL_TOOL_BAR (emacsframe))
5921     [toolbar setVisible:NO];
5924 - (void)windowWillExitFullScreen:(NSNotification *)notification
5926   if (next_maximized != -1)
5927     fs_before_fs = next_maximized;
5930 - (void)windowDidExitFullScreen:(NSNotification *)notification
5932   [self setFSValue: fs_before_fs];
5933   fs_before_fs = -1;
5934   [self updateCollectionBehaviour];
5935   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
5936     {
5937       [toolbar setVisible:YES];
5938       update_frame_tool_bar (emacsframe);
5939       [self updateFrameSize:YES];
5940       [[self window] display];
5941     }
5942   else
5943     [toolbar setVisible:NO];
5945   if (next_maximized != -1)
5946     [[self window] performZoom:self];
5949 - (BOOL)fsIsNative
5951   return fs_is_native;
5954 - (BOOL)isFullscreen
5956   if (! fs_is_native) return nonfs_window != nil;
5957 #ifdef HAVE_NATIVE_FS
5958   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
5959 #else
5960   return NO;
5961 #endif
5964 #ifdef HAVE_NATIVE_FS
5965 - (void)updateCollectionBehaviour
5967   if (! [self isFullscreen])
5968     {
5969       NSWindow *win = [self window];
5970       NSWindowCollectionBehavior b = [win collectionBehavior];
5971       if (ns_use_native_fullscreen)
5972         b |= NSWindowCollectionBehaviorFullScreenPrimary;
5973       else
5974         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
5976       [win setCollectionBehavior: b];
5977       fs_is_native = ns_use_native_fullscreen;
5978     }
5980 #endif
5982 - (void)toggleFullScreen: (id)sender
5984   NSWindow *w, *fw;
5985   BOOL onFirstScreen;
5986   struct frame *f;
5987   NSSize sz;
5988   NSRect r, wr;
5989   NSColor *col;
5991   if (fs_is_native)
5992     {
5993       [[self window] toggleFullScreen:sender];
5994       return;
5995     }
5997   w = [self window];
5998   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
5999   f = emacsframe;
6000   wr = [w frame];
6001   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6002                                  (FRAME_DEFAULT_FACE (f)),
6003                                  f);
6005   sz.width = FRAME_COLUMN_WIDTH (f);
6006   sz.height = FRAME_LINE_HEIGHT (f);
6008   if (fs_state != FULLSCREEN_BOTH)
6009     {
6010       /* Hide dock and menubar if we are on the primary screen.  */
6011       if (onFirstScreen)
6012         {
6013 #if defined (NS_IMPL_COCOA) && \
6014   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6015           NSApplicationPresentationOptions options
6016             = NSApplicationPresentationAutoHideDock
6017             | NSApplicationPresentationAutoHideMenuBar;
6019           [NSApp setPresentationOptions: options];
6020 #else
6021           [NSMenu setMenuBarVisible:NO];
6022 #endif
6023         }
6025       fw = [[EmacsFSWindow alloc]
6026                        initWithContentRect:[w contentRectForFrameRect:wr]
6027                                  styleMask:NSBorderlessWindowMask
6028                                    backing:NSBackingStoreBuffered
6029                                      defer:YES
6030                                     screen:[w screen]];
6032       [fw setContentView:[w contentView]];
6033       [fw setTitle:[w title]];
6034       [fw setDelegate:self];
6035       [fw setAcceptsMouseMovedEvents: YES];
6036       [fw useOptimizedDrawing: YES];
6037       [fw setResizeIncrements: sz];
6038       [fw setBackgroundColor: col];
6039       if ([col alphaComponent] != 1.0)
6040         [fw setOpaque: NO];
6042       f->border_width = 0;
6043       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6044       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6045       FRAME_TOOLBAR_HEIGHT (f) = 0;
6047       nonfs_window = w;
6049       [self windowWillEnterFullScreen:nil];
6050       [fw makeKeyAndOrderFront:NSApp];
6051       [fw makeFirstResponder:self];
6052       [w orderOut:self];
6053       r = [fw frameRectForContentRect:[[fw screen] frame]];
6054       [fw setFrame: r display:YES animate:YES];
6055       [self windowDidEnterFullScreen:nil];
6056       [fw display];
6057     }
6058   else
6059     {
6060       fw = w;
6061       w = nonfs_window;
6062       nonfs_window = nil;
6064       if (onFirstScreen)
6065         {
6066 #if defined (NS_IMPL_COCOA) && \
6067   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6068           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6069 #else
6070           [NSMenu setMenuBarVisible:YES];
6071 #endif
6072         }
6074       [w setContentView:[fw contentView]];
6075       [w setResizeIncrements: sz];
6076       [w setBackgroundColor: col];
6077       if ([col alphaComponent] != 1.0)
6078         [w setOpaque: NO];
6080       f->border_width = bwidth;
6081       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6082       if (FRAME_EXTERNAL_TOOL_BAR (f))
6083         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6085       [self windowWillExitFullScreen:nil];
6086       [fw setFrame: [w frame] display:YES animate:YES];
6087       [fw close];
6088       [w makeKeyAndOrderFront:NSApp];
6089       [self windowDidExitFullScreen:nil];
6090       [self updateFrameSize:YES];
6091     }
6094 - (void)handleFS
6096   if (fs_state != emacsframe->want_fullscreen)
6097     {
6098       if (fs_state == FULLSCREEN_BOTH)
6099         {
6100           [self toggleFullScreen:self];
6101         }
6103       switch (emacsframe->want_fullscreen)
6104         {
6105         case FULLSCREEN_BOTH:
6106           [self toggleFullScreen:self];
6107           break;
6108         case FULLSCREEN_WIDTH:
6109           next_maximized = FULLSCREEN_WIDTH;
6110           if (fs_state != FULLSCREEN_BOTH)
6111             [[self window] performZoom:self];
6112           break;
6113         case FULLSCREEN_HEIGHT:
6114           next_maximized = FULLSCREEN_HEIGHT;
6115           if (fs_state != FULLSCREEN_BOTH)
6116             [[self window] performZoom:self];
6117           break;
6118         case FULLSCREEN_MAXIMIZED:
6119           next_maximized = FULLSCREEN_MAXIMIZED;
6120           if (fs_state != FULLSCREEN_BOTH)
6121             [[self window] performZoom:self];
6122           break;
6123         case FULLSCREEN_NONE:
6124           if (fs_state != FULLSCREEN_BOTH)
6125             {
6126               next_maximized = FULLSCREEN_NONE;
6127               [[self window] performZoom:self];
6128             }
6129           break;
6130         }
6132       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6133     }
6137 - (void) setFSValue: (int)value
6139   Lisp_Object lval = Qnil;
6140   switch (value)
6141     {
6142     case FULLSCREEN_BOTH:
6143       lval = Qfullboth;
6144       break;
6145     case FULLSCREEN_WIDTH:
6146       lval = Qfullwidth;
6147       break;
6148     case FULLSCREEN_HEIGHT:
6149       lval = Qfullheight;
6150       break;
6151     case FULLSCREEN_MAXIMIZED:
6152       lval = Qmaximized;
6153       break;
6154     }
6155   store_frame_param (emacsframe, Qfullscreen, lval);
6156   fs_state = value;
6159 - (void)mouseEntered: (NSEvent *)theEvent
6161   NSTRACE (mouseEntered);
6162   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6166 - (void)mouseExited: (NSEvent *)theEvent
6168   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6170   NSTRACE (mouseExited);
6172   if (!hlinfo)
6173     return;
6175   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6177   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6178     {
6179       clear_mouse_face (hlinfo);
6180       hlinfo->mouse_face_mouse_frame = 0;
6181     }
6185 - menuDown: sender
6187   NSTRACE (menuDown);
6188   if (context_menu_value == -1)
6189     context_menu_value = [sender tag];
6190   else
6191     {
6192       NSInteger tag = [sender tag];
6193       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6194                                     emacsframe->menu_bar_vector,
6195                                     (void *)tag);
6196     }
6198   ns_send_appdefined (-1);
6199   return self;
6203 - (EmacsToolbar *)toolbar
6205   return toolbar;
6209 /* this gets called on toolbar button click */
6210 - toolbarClicked: (id)item
6212   NSEvent *theEvent;
6213   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6215   NSTRACE (toolbarClicked);
6217   if (!emacs_event)
6218     return self;
6220   /* send first event (for some reason two needed) */
6221   theEvent = [[self window] currentEvent];
6222   emacs_event->kind = TOOL_BAR_EVENT;
6223   XSETFRAME (emacs_event->arg, emacsframe);
6224   EV_TRAILER (theEvent);
6226   emacs_event->kind = TOOL_BAR_EVENT;
6227 /*   XSETINT (emacs_event->code, 0); */
6228   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6229                            idx + TOOL_BAR_ITEM_KEY);
6230   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6231   EV_TRAILER (theEvent);
6232   return self;
6236 - toggleToolbar: (id)sender
6238   if (!emacs_event)
6239     return self;
6241   emacs_event->kind = NS_NONKEY_EVENT;
6242   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6243   EV_TRAILER ((id)nil);
6244   return self;
6248 - (void)drawRect: (NSRect)rect
6250   int x = NSMinX (rect), y = NSMinY (rect);
6251   int width = NSWidth (rect), height = NSHeight (rect);
6253   NSTRACE (drawRect);
6255   if (!emacsframe || !emacsframe->output_data.ns)
6256     return;
6258   ns_clear_frame_area (emacsframe, x, y, width, height);
6259   expose_frame (emacsframe, x, y, width, height);
6261   /*
6262     drawRect: may be called (at least in OS X 10.5) for invisible
6263     views as well for some reason.  Thus, do not infer visibility
6264     here.
6266     emacsframe->async_visible = 1;
6267     emacsframe->async_iconified = 0;
6268   */
6272 /* NSDraggingDestination protocol methods.  Actually this is not really a
6273    protocol, but a category of Object.  O well...  */
6275 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6277   NSTRACE (draggingEntered);
6278   return NSDragOperationGeneric;
6282 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6284   return YES;
6288 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6290   id pb;
6291   int x, y;
6292   NSString *type;
6293   NSEvent *theEvent = [[self window] currentEvent];
6294   NSPoint position;
6296   NSTRACE (performDragOperation);
6298   if (!emacs_event)
6299     return NO;
6301   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6302   x = lrint (position.x);  y = lrint (position.y);
6304   pb = [sender draggingPasteboard];
6305   type = [pb availableTypeFromArray: ns_drag_types];
6306   if (type == 0)
6307     {
6308       return NO;
6309     }
6310   else if ([type isEqualToString: NSFilenamesPboardType])
6311     {
6312       NSArray *files;
6313       NSEnumerator *fenum;
6314       NSString *file;
6316       if (!(files = [pb propertyListForType: type]))
6317         return NO;
6319       fenum = [files objectEnumerator];
6320       while ( (file = [fenum nextObject]) )
6321         {
6322           emacs_event->kind = NS_NONKEY_EVENT;
6323           emacs_event->code = KEY_NS_DRAG_FILE;
6324           XSETINT (emacs_event->x, x);
6325           XSETINT (emacs_event->y, y);
6326           ns_input_file = append2 (ns_input_file,
6327                                    build_string ([file UTF8String]));
6328           emacs_event->modifiers = EV_MODIFIERS (theEvent);
6329           EV_TRAILER (theEvent);
6330         }
6331       return YES;
6332     }
6333   else if ([type isEqualToString: NSURLPboardType])
6334     {
6335       NSString *file;
6336       NSURL *fileURL;
6338       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6339           [fileURL isFileURL] == NO)
6340         return NO;
6342       file = [fileURL path];
6343       emacs_event->kind = NS_NONKEY_EVENT;
6344       emacs_event->code = KEY_NS_DRAG_FILE;
6345       XSETINT (emacs_event->x, x);
6346       XSETINT (emacs_event->y, y);
6347       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6348       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6349       EV_TRAILER (theEvent);
6350       return YES;
6351     }
6352   else if ([type isEqualToString: NSStringPboardType]
6353            || [type isEqualToString: NSTabularTextPboardType])
6354     {
6355       NSString *data;
6357       if (! (data = [pb stringForType: type]))
6358         return NO;
6360       emacs_event->kind = NS_NONKEY_EVENT;
6361       emacs_event->code = KEY_NS_DRAG_TEXT;
6362       XSETINT (emacs_event->x, x);
6363       XSETINT (emacs_event->y, y);
6364       ns_input_text = build_string ([data UTF8String]);
6365       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6366       EV_TRAILER (theEvent);
6367       return YES;
6368     }
6369   else if ([type isEqualToString: NSColorPboardType])
6370     {
6371       NSColor *c = [NSColor colorFromPasteboard: pb];
6372       emacs_event->kind = NS_NONKEY_EVENT;
6373       emacs_event->code = KEY_NS_DRAG_COLOR;
6374       XSETINT (emacs_event->x, x);
6375       XSETINT (emacs_event->y, y);
6376       ns_input_color = ns_color_to_lisp (c);
6377       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6378       EV_TRAILER (theEvent);
6379       return YES;
6380     }
6381   else if ([type isEqualToString: NSFontPboardType])
6382     {
6383       /* impl based on GNUstep NSTextView.m */
6384       NSData *data = [pb dataForType: NSFontPboardType];
6385       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6386       NSFont *font = [dict objectForKey: NSFontAttributeName];
6387       char fontSize[10];
6389       if (font == nil)
6390         return NO;
6392       emacs_event->kind = NS_NONKEY_EVENT;
6393       emacs_event->code = KEY_NS_CHANGE_FONT;
6394       XSETINT (emacs_event->x, x);
6395       XSETINT (emacs_event->y, y);
6396       ns_input_font = build_string ([[font fontName] UTF8String]);
6397       snprintf (fontSize, 10, "%f", [font pointSize]);
6398       ns_input_fontsize = build_string (fontSize);
6399       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6400       EV_TRAILER (theEvent);
6401       return YES;
6402     }
6403   else
6404     {
6405       error ("Invalid data type in dragging pasteboard.");
6406       return NO;
6407     }
6411 - (id) validRequestorForSendType: (NSString *)typeSent
6412                       returnType: (NSString *)typeReturned
6414   NSTRACE (validRequestorForSendType);
6415   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6416       && typeReturned == nil)
6417     {
6418       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6419         return self;
6420     }
6422   return [super validRequestorForSendType: typeSent
6423                                returnType: typeReturned];
6427 /* The next two methods are part of NSServicesRequests informal protocol,
6428    supposedly called when a services menu item is chosen from this app.
6429    But this should not happen because we override the services menu with our
6430    own entries which call ns-perform-service.
6431    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6432    So let's at least stub them out until further investigation can be done. */
6434 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6436   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6437      be written into the buffer in place of the existing selection..
6438      ordinary service calls go through functions defined in ns-win.el */
6439   return NO;
6442 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6444   NSArray *typesDeclared;
6445   Lisp_Object val;
6447   /* We only support NSStringPboardType */
6448   if ([types containsObject:NSStringPboardType] == NO) {
6449     return NO;
6450   }
6452   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6453   if (CONSP (val) && SYMBOLP (XCAR (val)))
6454     {
6455       val = XCDR (val);
6456       if (CONSP (val) && NILP (XCDR (val)))
6457         val = XCAR (val);
6458     }
6459   if (! STRINGP (val))
6460     return NO;
6462   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6463   [pb declareTypes:typesDeclared owner:nil];
6464   ns_string_to_pasteboard (pb, val);
6465   return YES;
6469 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6470    (gives a miniaturized version of the window); currently we use the latter for
6471    frames whose active buffer doesn't correspond to any file
6472    (e.g., '*scratch*') */
6473 - setMiniwindowImage: (BOOL) setMini
6475   id image = [[self window] miniwindowImage];
6476   NSTRACE (setMiniwindowImage);
6478   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6479      about "AppleDockIconEnabled" notwithstanding, however the set message
6480      below has its effect nonetheless. */
6481   if (image != emacsframe->output_data.ns->miniimage)
6482     {
6483       if (image && [image isKindOfClass: [EmacsImage class]])
6484         [image release];
6485       [[self window] setMiniwindowImage:
6486                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6487     }
6489   return self;
6493 - (void) setRows: (int) r andColumns: (int) c
6495   rows = r;
6496   cols = c;
6499 @end  /* EmacsView */
6503 /* ==========================================================================
6505     EmacsWindow implementation
6507    ========================================================================== */
6509 @implementation EmacsWindow
6511 #ifdef NS_IMPL_COCOA
6512 - (id)accessibilityAttributeValue:(NSString *)attribute
6514   Lisp_Object str = Qnil;
6515   struct frame *f = SELECTED_FRAME ();
6516   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->buffer);
6518   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6519     return NSAccessibilityTextFieldRole;
6521   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6522       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6523     {
6524       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6525     }
6526   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6527     {
6528       if (! NILP (BVAR (curbuf, mark_active)))
6529           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6531       if (NILP (str))
6532         {
6533           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6534           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6535           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6537           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6538             str = make_uninit_multibyte_string (range, byte_range);
6539           else
6540             str = make_uninit_string (range);
6541           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6542              Is this a problem?  */
6543           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6544         }
6545     }
6548   if (! NILP (str))
6549     {
6550       if (CONSP (str) && SYMBOLP (XCAR (str)))
6551         {
6552           str = XCDR (str);
6553           if (CONSP (str) && NILP (XCDR (str)))
6554             str = XCAR (str);
6555         }
6556       if (STRINGP (str))
6557         {
6558           const char *utfStr = SSDATA (str);
6559           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6560           return nsStr;
6561         }
6562     }
6564   return [super accessibilityAttributeValue:attribute];
6566 #endif /* NS_IMPL_COCOA */
6568 /* If we have multiple monitors, one above the other, we don't want to
6569    restrict the height to just one monitor.  So we override this.  */
6570 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6572   /* When making the frame visible for the first time or if there is just
6573      one screen, we want to constrain.  Other times not.  */
6574   NSUInteger nr_screens = [[NSScreen screens] count];
6575   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6576   NSTRACE (constrainFrameRect);
6578   if (nr_screens == 1)
6579     {
6580       NSRect r = [super constrainFrameRect:frameRect toScreen:screen];
6581       return r;
6582     }
6584   if (f->output_data.ns->dont_constrain
6585       || ns_menu_bar_should_be_hidden ())
6586     return frameRect;
6588   f->output_data.ns->dont_constrain = 1;
6589   return [super constrainFrameRect:frameRect toScreen:screen];
6592 @end /* EmacsWindow */
6595 @implementation EmacsFSWindow
6597 - (BOOL)canBecomeKeyWindow
6599   return YES;
6602 - (BOOL)canBecomeMainWindow
6604   return YES;
6607 @end
6609 /* ==========================================================================
6611     EmacsScroller implementation
6613    ========================================================================== */
6616 @implementation EmacsScroller
6618 /* for repeat button push */
6619 #define SCROLL_BAR_FIRST_DELAY 0.5
6620 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6622 + (CGFloat) scrollerWidth
6624   /* TODO: if we want to allow variable widths, this is the place to do it,
6625            however neither GNUstep nor Cocoa support it very well */
6626   return [NSScroller scrollerWidth];
6630 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6632   NSTRACE (EmacsScroller_initFrame);
6634   r.size.width = [EmacsScroller scrollerWidth];
6635   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6636   [self setContinuous: YES];
6637   [self setEnabled: YES];
6639   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6640      locked against the top and bottom edges, and right edge on OS X, where
6641      scrollers are on right. */
6642 #ifdef NS_IMPL_GNUSTEP
6643   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6644 #else
6645   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6646 #endif
6648   win = nwin;
6649   condemned = NO;
6650   pixel_height = NSHeight (r);
6651   if (pixel_height == 0) pixel_height = 1;
6652   min_portion = 20 / pixel_height;
6654   frame = XFRAME (XWINDOW (win)->frame);
6655   if (FRAME_LIVE_P (frame))
6656     {
6657       int i;
6658       EmacsView *view = FRAME_NS_VIEW (frame);
6659       NSView *sview = [[view window] contentView];
6660       NSArray *subs = [sview subviews];
6662       /* disable optimization stopping redraw of other scrollbars */
6663       view->scrollbarsNeedingUpdate = 0;
6664       for (i =[subs count]-1; i >= 0; i--)
6665         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6666           view->scrollbarsNeedingUpdate++;
6667       [sview addSubview: self];
6668     }
6670 /*  [self setFrame: r]; */
6672   return self;
6676 - (void)setFrame: (NSRect)newRect
6678   NSTRACE (EmacsScroller_setFrame);
6679 /*  block_input (); */
6680   pixel_height = NSHeight (newRect);
6681   if (pixel_height == 0) pixel_height = 1;
6682   min_portion = 20 / pixel_height;
6683   [super setFrame: newRect];
6684   [self display];
6685 /*  unblock_input (); */
6689 - (void)dealloc
6691   NSTRACE (EmacsScroller_dealloc);
6692   if (!NILP (win))
6693     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
6694   [super dealloc];
6698 - condemn
6700   NSTRACE (condemn);
6701   condemned =YES;
6702   return self;
6706 - reprieve
6708   NSTRACE (reprieve);
6709   condemned =NO;
6710   return self;
6714 - judge
6716   NSTRACE (judge);
6717   if (condemned)
6718     {
6719       EmacsView *view;
6720       block_input ();
6721       /* ensure other scrollbar updates after deletion */
6722       view = (EmacsView *)FRAME_NS_VIEW (frame);
6723       if (view != nil)
6724         view->scrollbarsNeedingUpdate++;
6725       [self removeFromSuperview];
6726       [self release];
6727       unblock_input ();
6728     }
6729   return self;
6733 - (void)resetCursorRects
6735   NSRect visible = [self visibleRect];
6736   NSTRACE (resetCursorRects);
6738   if (!NSIsEmptyRect (visible))
6739     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6740   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6744 - (int) checkSamePosition: (int) position portion: (int) portion
6745                     whole: (int) whole
6747   return em_position ==position && em_portion ==portion && em_whole ==whole
6748     && portion != whole; /* needed for resize empty buf */
6752 - setPosition: (int)position portion: (int)portion whole: (int)whole
6754   NSTRACE (setPosition);
6756   em_position = position;
6757   em_portion = portion;
6758   em_whole = whole;
6760   if (portion >= whole)
6761     {
6762 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6763       [self setKnobProportion: 1.0];
6764       [self setDoubleValue: 1.0];
6765 #else
6766       [self setFloatValue: 0.0 knobProportion: 1.0];
6767 #endif
6768     }
6769   else
6770     {
6771       float pos, por;
6772       portion = max ((float)whole*min_portion/pixel_height, portion);
6773       pos = (float)position / (whole - portion);
6774       por = (float)portion/whole;
6775 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6776       [self setKnobProportion: por];
6777       [self setDoubleValue: pos];
6778 #else
6779       [self setFloatValue: pos knobProportion: por];
6780 #endif
6781     }
6783   /* Events may come here even if the event loop is not running.
6784      If we don't enter the event loop, the scroll bar will not update.
6785      So send SIGIO to ourselves.  */
6786   if (apploopnr == 0) raise (SIGIO);
6788   return self;
6791 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6792      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6793 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6794                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6796   *part = last_hit_part;
6797   *window = win;
6798   XSETINT (*y, pixel_height);
6799   if ([self floatValue] > 0.999)
6800     XSETINT (*x, pixel_height);
6801   else
6802     XSETINT (*x, pixel_height * [self floatValue]);
6806 /* set up emacs_event */
6807 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6809   if (!emacs_event)
6810     return;
6812   emacs_event->part = last_hit_part;
6813   emacs_event->code = 0;
6814   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6815   emacs_event->frame_or_window = win;
6816   emacs_event->timestamp = EV_TIMESTAMP (e);
6817   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6818   emacs_event->arg = Qnil;
6819   XSETINT (emacs_event->x, loc * pixel_height);
6820   XSETINT (emacs_event->y, pixel_height-20);
6822   if (q_event_ptr)
6823     {
6824       n_emacs_events_pending++;
6825       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6826     }
6827   else
6828     hold_event (emacs_event);
6829   EVENT_INIT (*emacs_event);
6830   ns_send_appdefined (-1);
6834 /* called manually thru timer to implement repeated button action w/hold-down */
6835 - repeatScroll: (NSTimer *)scrollEntry
6837   NSEvent *e = [[self window] currentEvent];
6838   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6839   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6841   /* clear timer if need be */
6842   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6843     {
6844         [scroll_repeat_entry invalidate];
6845         [scroll_repeat_entry release];
6846         scroll_repeat_entry = nil;
6848         if (inKnob)
6849           return self;
6851         scroll_repeat_entry
6852           = [[NSTimer scheduledTimerWithTimeInterval:
6853                         SCROLL_BAR_CONTINUOUS_DELAY
6854                                             target: self
6855                                           selector: @selector (repeatScroll:)
6856                                           userInfo: 0
6857                                            repeats: YES]
6858               retain];
6859     }
6861   [self sendScrollEventAtLoc: 0 fromEvent: e];
6862   return self;
6866 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6867    mouseDragged events without going into a modal loop. */
6868 - (void)mouseDown: (NSEvent *)e
6870   NSRect sr, kr;
6871   /* hitPart is only updated AFTER event is passed on */
6872   NSScrollerPart part = [self testPart: [e locationInWindow]];
6873   double inc = 0.0, loc, kloc, pos;
6874   int edge = 0;
6876   NSTRACE (EmacsScroller_mouseDown);
6878   switch (part)
6879     {
6880     case NSScrollerDecrementPage:
6881         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6882     case NSScrollerIncrementPage:
6883         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6884     case NSScrollerDecrementLine:
6885       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6886     case NSScrollerIncrementLine:
6887       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6888     case NSScrollerKnob:
6889       last_hit_part = scroll_bar_handle; break;
6890     case NSScrollerKnobSlot:  /* GNUstep-only */
6891       last_hit_part = scroll_bar_move_ratio; break;
6892     default:  /* NSScrollerNoPart? */
6893       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6894                (long) part);
6895       return;
6896     }
6898   if (inc != 0.0)
6899     {
6900       pos = 0;      /* ignored */
6902       /* set a timer to repeat, as we can't let superclass do this modally */
6903       scroll_repeat_entry
6904         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6905                                             target: self
6906                                           selector: @selector (repeatScroll:)
6907                                           userInfo: 0
6908                                            repeats: YES]
6909             retain];
6910     }
6911   else
6912     {
6913       /* handle, or on GNUstep possibly slot */
6914       NSEvent *fake_event;
6916       /* compute float loc in slot and mouse offset on knob */
6917       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6918                       toView: nil];
6919       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6920       if (loc <= 0.0)
6921         {
6922           loc = 0.0;
6923           edge = -1;
6924         }
6925       else if (loc >= NSHeight (sr))
6926         {
6927           loc = NSHeight (sr);
6928           edge = 1;
6929         }
6931       if (edge)
6932         kloc = 0.5 * edge;
6933       else
6934         {
6935           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6936                           toView: nil];
6937           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6938         }
6939       last_mouse_offset = kloc;
6941       /* if knob, tell emacs a location offset by knob pos
6942          (to indicate top of handle) */
6943       if (part == NSScrollerKnob)
6944           pos = (loc - last_mouse_offset) / NSHeight (sr);
6945       else
6946         /* else this is a slot click on GNUstep: go straight there */
6947         pos = loc / NSHeight (sr);
6949       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6950       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6951                                       location: [e locationInWindow]
6952                                  modifierFlags: [e modifierFlags]
6953                                      timestamp: [e timestamp]
6954                                   windowNumber: [e windowNumber]
6955                                        context: [e context]
6956                                    eventNumber: [e eventNumber]
6957                                     clickCount: [e clickCount]
6958                                       pressure: [e pressure]];
6959       [super mouseUp: fake_event];
6960     }
6962   if (part != NSScrollerKnob)
6963     [self sendScrollEventAtLoc: pos fromEvent: e];
6967 /* Called as we manually track scroller drags, rather than superclass. */
6968 - (void)mouseDragged: (NSEvent *)e
6970     NSRect sr;
6971     double loc, pos;
6972     int edge = 0;
6974     NSTRACE (EmacsScroller_mouseDragged);
6976       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6977                       toView: nil];
6978       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6980       if (loc <= 0.0)
6981         {
6982           loc = 0.0;
6983           edge = -1;
6984         }
6985       else if (loc >= NSHeight (sr) + last_mouse_offset)
6986         {
6987           loc = NSHeight (sr) + last_mouse_offset;
6988           edge = 1;
6989         }
6991       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6992       [self sendScrollEventAtLoc: pos fromEvent: e];
6996 - (void)mouseUp: (NSEvent *)e
6998   if (scroll_repeat_entry)
6999     {
7000       [scroll_repeat_entry invalidate];
7001       [scroll_repeat_entry release];
7002       scroll_repeat_entry = nil;
7003     }
7004   last_hit_part = 0;
7008 /* treat scrollwheel events in the bar as though they were in the main window */
7009 - (void) scrollWheel: (NSEvent *)theEvent
7011   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7012   [view mouseDown: theEvent];
7015 @end  /* EmacsScroller */
7020 /* ==========================================================================
7022    Font-related functions; these used to be in nsfaces.m
7024    ========================================================================== */
7027 Lisp_Object
7028 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7030   struct font *font = XFONT_OBJECT (font_object);
7032   if (fontset < 0)
7033     fontset = fontset_from_font (font_object);
7034   FRAME_FONTSET (f) = fontset;
7036   if (FRAME_FONT (f) == font)
7037     /* This font is already set in frame F.  There's nothing more to
7038        do.  */
7039     return font_object;
7041   FRAME_FONT (f) = font;
7043   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7044   FRAME_COLUMN_WIDTH (f) = font->average_width;
7045   FRAME_LINE_HEIGHT (f) = font->height;
7047   compute_fringe_widths (f, 1);
7049   /* Compute the scroll bar width in character columns.  */
7050   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7051     {
7052       int wid = FRAME_COLUMN_WIDTH (f);
7053       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7054         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7055     }
7056   else
7057     {
7058       int wid = FRAME_COLUMN_WIDTH (f);
7059       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7060     }
7062   /* Now make the frame display the given font.  */
7063   if (FRAME_NS_WINDOW (f) != 0)
7064         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
7066   return font_object;
7070 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7071 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7072          in 1.43. */
7074 const char *
7075 ns_xlfd_to_fontname (const char *xlfd)
7076 /* --------------------------------------------------------------------------
7077     Convert an X font name (XLFD) to an NS font name.
7078     Only family is used.
7079     The string returned is temporarily allocated.
7080    -------------------------------------------------------------------------- */
7082   char *name = xmalloc (180);
7083   int i, len;
7084   const char *ret;
7086   if (!strncmp (xlfd, "--", 2))
7087     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7088   else
7089     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7091   /* stopgap for malformed XLFD input */
7092   if (strlen (name) == 0)
7093     strcpy (name, "Monaco");
7095   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7096      also uppercase after '-' or ' ' */
7097   name[0] = c_toupper (name[0]);
7098   for (len =strlen (name), i =0; i<len; i++)
7099     {
7100       if (name[i] == '$')
7101         {
7102           name[i] = '-';
7103           if (i+1<len)
7104             name[i+1] = c_toupper (name[i+1]);
7105         }
7106       else if (name[i] == '_')
7107         {
7108           name[i] = ' ';
7109           if (i+1<len)
7110             name[i+1] = c_toupper (name[i+1]);
7111         }
7112     }
7113 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7114   ret = [[NSString stringWithUTF8String: name] UTF8String];
7115   xfree (name);
7116   return ret;
7120 void
7121 syms_of_nsterm (void)
7123   NSTRACE (syms_of_nsterm);
7125   ns_antialias_threshold = 10.0;
7127   /* from 23+ we need to tell emacs what modifiers there are.. */
7128   DEFSYM (Qmodifier_value, "modifier-value");
7129   DEFSYM (Qalt, "alt");
7130   DEFSYM (Qhyper, "hyper");
7131   DEFSYM (Qmeta, "meta");
7132   DEFSYM (Qsuper, "super");
7133   DEFSYM (Qcontrol, "control");
7134   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7136   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7137   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7138   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7139   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7140   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7142   DEFVAR_LISP ("ns-input-file", ns_input_file,
7143               "The file specified in the last NS event.");
7144   ns_input_file =Qnil;
7146   DEFVAR_LISP ("ns-input-text", ns_input_text,
7147               "The data received in the last NS text drag event.");
7148   ns_input_text =Qnil;
7150   DEFVAR_LISP ("ns-working-text", ns_working_text,
7151               "String for visualizing working composition sequence.");
7152   ns_working_text =Qnil;
7154   DEFVAR_LISP ("ns-input-font", ns_input_font,
7155               "The font specified in the last NS event.");
7156   ns_input_font =Qnil;
7158   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7159               "The fontsize specified in the last NS event.");
7160   ns_input_fontsize =Qnil;
7162   DEFVAR_LISP ("ns-input-line", ns_input_line,
7163                "The line specified in the last NS event.");
7164   ns_input_line =Qnil;
7166   DEFVAR_LISP ("ns-input-color", ns_input_color,
7167                "The color specified in the last NS event.");
7168   ns_input_color =Qnil;
7170   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7171                "The service name specified in the last NS event.");
7172   ns_input_spi_name =Qnil;
7174   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7175                "The service argument specified in the last NS event.");
7176   ns_input_spi_arg =Qnil;
7178   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7179                "This variable describes the behavior of the alternate or option key.\n\
7180 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7181 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7182 at all, allowing it to be used at a lower level for accented character entry.");
7183   ns_alternate_modifier = Qmeta;
7185   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7186                "This variable describes the behavior of the right alternate or option key.\n\
7187 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7188 Set to left means be the same key as `ns-alternate-modifier'.\n\
7189 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7190 at all, allowing it to be used at a lower level for accented character entry.");
7191   ns_right_alternate_modifier = Qleft;
7193   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7194                "This variable describes the behavior of the command key.\n\
7195 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7196   ns_command_modifier = Qsuper;
7198   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7199                "This variable describes the behavior of the right command key.\n\
7200 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7201 Set to left means be the same key as `ns-command-modifier'.\n\
7202 Set to none means that the command / option key is not interpreted by Emacs\n\
7203 at all, allowing it to be used at a lower level for accented character entry.");
7204   ns_right_command_modifier = Qleft;
7206   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7207                "This variable describes the behavior of the control key.\n\
7208 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7209   ns_control_modifier = Qcontrol;
7211   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7212                "This variable describes the behavior of the right control key.\n\
7213 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7214 Set to left means be the same key as `ns-control-modifier'.\n\
7215 Set to none means that the control / option key is not interpreted by Emacs\n\
7216 at all, allowing it to be used at a lower level for accented character entry.");
7217   ns_right_control_modifier = Qleft;
7219   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7220                "This variable describes the behavior of the function key (on laptops).\n\
7221 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7222 Set to none means that the function key is not interpreted by Emacs at all,\n\
7223 allowing it to be used at a lower level for accented character entry.");
7224   ns_function_modifier = Qnone;
7226   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7227                "Non-nil (the default) means to render text antialiased.");
7228   ns_antialias_text = Qt;
7230   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7231                "Whether to confirm application quit using dialog.");
7232   ns_confirm_quit = Qnil;
7234   staticpro (&ns_display_name_list);
7235   ns_display_name_list = Qnil;
7237   staticpro (&last_mouse_motion_frame);
7238   last_mouse_motion_frame = Qnil;
7240   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7241                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7242 Only works on OSX 10.6 or later.  */);
7243   ns_auto_hide_menu_bar = Qnil;
7245   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7246      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7247 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7248 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7249 Default is t for OSX >= 10.7, nil otherwise. */);
7250 #ifdef HAVE_NATIVE_FS
7251   ns_use_native_fullscreen = YES;
7252 #else
7253   ns_use_native_fullscreen = NO;
7254 #endif
7255   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7257   /* TODO: move to common code */
7258   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7259                doc: /* Which toolkit scroll bars Emacs uses, if any.
7260 A value of nil means Emacs doesn't use toolkit scroll bars.
7261 With the X Window system, the value is a symbol describing the
7262 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7263 With MS Windows or Nextstep, the value is t.  */);
7264   Vx_toolkit_scroll_bars = Qt;
7266   DEFVAR_BOOL ("x-use-underline-position-properties",
7267                x_use_underline_position_properties,
7268      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7269 A value of nil means ignore them.  If you encounter fonts with bogus
7270 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7271 to 4.1, set this to nil. */);
7272   x_use_underline_position_properties = 0;
7274   DEFVAR_BOOL ("x-underline-at-descent-line",
7275                x_underline_at_descent_line,
7276      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7277 A value of nil means to draw the underline according to the value of the
7278 variable `x-use-underline-position-properties', which is usually at the
7279 baseline level.  The default value is nil.  */);
7280   x_underline_at_descent_line = 0;
7282   /* Tell emacs about this window system. */
7283   Fprovide (intern ("ns"), Qnil);