* lisp/emacs-lisp/pcase.el (pcase--expand): Warn for unused pattern.
[emacs.git] / src / nsterm.m
blobdd4969a1e2e358768a2f2d89491d44932a52fade
1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2012
4   Free Software Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30    interpretation of even the system includes. */
31 #include <config.h>
33 #include <math.h>
34 #include <sys/types.h>
35 #include <time.h>
36 #include <signal.h>
37 #include <unistd.h>
38 #include <setjmp.h>
40 #include "lisp.h"
41 #include "blockinput.h"
42 #include "sysselect.h"
43 #include "nsterm.h"
44 #include "systime.h"
45 #include "character.h"
46 #include "fontset.h"
47 #include "composite.h"
48 #include "ccl.h"
50 #include "termhooks.h"
51 #include "termopts.h"
52 #include "termchar.h"
54 #include "window.h"
55 #include "keyboard.h"
57 #include "font.h"
59 /* call tracing */
60 #if 0
61 int term_trace_num = 0;
62 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
63                                 __FILE__, __LINE__, ++term_trace_num)
64 #else
65 #define NSTRACE(x)
66 #endif
68 extern NSString *NSMenuDidBeginTrackingNotification;
70 /* ==========================================================================
72     Local declarations
74    ========================================================================== */
76 /* Convert a symbol indexed with an NSxxx value to a value as defined
77    in keyboard.c (lispy_function_key). I hope this is a correct way
78    of doing things... */
79 static unsigned convert_ns_to_X_keysym[] =
81   NSHomeFunctionKey,            0x50,
82   NSLeftArrowFunctionKey,       0x51,
83   NSUpArrowFunctionKey,         0x52,
84   NSRightArrowFunctionKey,      0x53,
85   NSDownArrowFunctionKey,       0x54,
86   NSPageUpFunctionKey,          0x55,
87   NSPageDownFunctionKey,        0x56,
88   NSEndFunctionKey,             0x57,
89   NSBeginFunctionKey,           0x58,
90   NSSelectFunctionKey,          0x60,
91   NSPrintFunctionKey,           0x61,
92   NSExecuteFunctionKey,         0x62,
93   NSInsertFunctionKey,          0x63,
94   NSUndoFunctionKey,            0x65,
95   NSRedoFunctionKey,            0x66,
96   NSMenuFunctionKey,            0x67,
97   NSFindFunctionKey,            0x68,
98   NSHelpFunctionKey,            0x6A,
99   NSBreakFunctionKey,           0x6B,
101   NSF1FunctionKey,              0xBE,
102   NSF2FunctionKey,              0xBF,
103   NSF3FunctionKey,              0xC0,
104   NSF4FunctionKey,              0xC1,
105   NSF5FunctionKey,              0xC2,
106   NSF6FunctionKey,              0xC3,
107   NSF7FunctionKey,              0xC4,
108   NSF8FunctionKey,              0xC5,
109   NSF9FunctionKey,              0xC6,
110   NSF10FunctionKey,             0xC7,
111   NSF11FunctionKey,             0xC8,
112   NSF12FunctionKey,             0xC9,
113   NSF13FunctionKey,             0xCA,
114   NSF14FunctionKey,             0xCB,
115   NSF15FunctionKey,             0xCC,
116   NSF16FunctionKey,             0xCD,
117   NSF17FunctionKey,             0xCE,
118   NSF18FunctionKey,             0xCF,
119   NSF19FunctionKey,             0xD0,
120   NSF20FunctionKey,             0xD1,
121   NSF21FunctionKey,             0xD2,
122   NSF22FunctionKey,             0xD3,
123   NSF23FunctionKey,             0xD4,
124   NSF24FunctionKey,             0xD5,
126   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
127   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
128   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
130   NSTabCharacter,               0x09,
131   0x19,                         0x09,  /* left tab->regular since pass shift */
132   NSCarriageReturnCharacter,    0x0D,
133   NSNewlineCharacter,           0x0D,
134   NSEnterCharacter,             0x8D,
136   0x1B,                         0x1B   /* escape */
139 static Lisp_Object Qmodifier_value;
140 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper, Qnone;
141 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
143 static Lisp_Object QUTF8_STRING;
145 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
146    the maximum font size to NOT antialias.  On GNUstep there is currently
147    no way to control this behavior. */
148 float ns_antialias_threshold;
150 /* Used to pick up AppleHighlightColor on OS X */
151 NSString *ns_selection_color;
153 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
154 NSString *ns_app_name = @"Emacs";  /* default changed later */
156 /* Display variables */
157 struct ns_display_info *x_display_list; /* Chain of existing displays */
158 Lisp_Object ns_display_name_list;
159 long context_menu_value = 0;
161 /* display update */
162 NSPoint last_mouse_motion_position;
163 static NSRect last_mouse_glyph;
164 static Time last_mouse_movement_time = 0;
165 static Lisp_Object last_mouse_motion_frame;
166 static EmacsScroller *last_mouse_scroll_bar = nil;
167 static struct frame *ns_updating_frame;
168 static NSView *focus_view = NULL;
169 static int ns_window_num = 0;
170 static NSRect uRect;
171 static BOOL gsaved = NO;
172 BOOL ns_in_resize = NO;
173 static BOOL ns_fake_keydown = NO;
174 int ns_tmp_flags; /* FIXME */
175 struct nsfont_info *ns_tmp_font; /* FIXME */
176 static BOOL ns_menu_bar_is_hidden = NO;
177 /*static int debug_lock = 0; */
179 /* event loop */
180 static BOOL send_appdefined = YES;
181 static NSEvent *last_appdefined_event = 0;
182 static NSTimer *timed_entry = 0;
183 static NSTimer *fd_entry = nil;
184 static NSTimer *scroll_repeat_entry = nil;
185 static fd_set select_readfds, t_readfds;
186 static struct timeval select_timeout;
187 static int select_nfds;
188 static NSAutoreleasePool *outerpool;
189 static struct input_event *emacs_event = NULL;
190 static struct input_event *q_event_ptr = NULL;
191 static int n_emacs_events_pending = 0;
192 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
193   *ns_pending_service_args;
194 static BOOL inNsSelect = 0;
196 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
197 #define NS_FUNCTION_KEY_MASK 0x800000
198 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
199 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
200 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
201 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
202 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
203 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
204 #define EV_MODIFIERS(e)                               \
205     ((([e modifierFlags] & NSHelpKeyMask) ?           \
206            hyper_modifier : 0)                        \
207      | (!EQ (ns_right_alternate_modifier, Qleft) && \
208         (([e modifierFlags] & NSRightAlternateKeyMask) \
209          == NSRightAlternateKeyMask) ? \
210            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
211      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
212            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
213      | (([e modifierFlags] & NSShiftKeyMask) ?     \
214            shift_modifier : 0)                        \
215      | (!EQ (ns_right_control_modifier, Qleft) && \
216         (([e modifierFlags] & NSRightControlKeyMask) \
217          == NSRightControlKeyMask) ? \
218            parse_solitary_modifier (ns_right_control_modifier) : 0) \
219      | (([e modifierFlags] & NSControlKeyMask) ?      \
220            parse_solitary_modifier (ns_control_modifier) : 0)     \
221      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
222            parse_solitary_modifier (ns_function_modifier) : 0)    \
223      | (!EQ (ns_right_command_modifier, Qleft) && \
224         (([e modifierFlags] & NSRightCommandKeyMask) \
225          == NSRightCommandKeyMask) ? \
226            parse_solitary_modifier (ns_right_command_modifier) : 0) \
227      | (([e modifierFlags] & NSCommandKeyMask) ?      \
228            parse_solitary_modifier (ns_command_modifier):0))
230 #define EV_UDMODIFIERS(e)                                      \
231     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
232      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
233      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
234      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
235      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
236      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
237      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
238      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
239      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
241 #define EV_BUTTON(e)                                                         \
242     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
243       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
244      [e buttonNumber] - 1)
246 /* Convert the time field to a timestamp in milliseconds. */
247 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
249 /* This is a piece of code which is common to all the event handling
250    methods.  Maybe it should even be a function.  */
251 #define EV_TRAILER(e)                                         \
252   {                                                           \
253   XSETFRAME (emacs_event->frame_or_window, emacsframe);       \
254   if (e) emacs_event->timestamp = EV_TIMESTAMP (e);           \
255   n_emacs_events_pending++;                                   \
256   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);     \
257   EVENT_INIT (*emacs_event);                                  \
258   ns_send_appdefined (-1);                                    \
259   }
261 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
263 /* TODO: get rid of need for these forward declarations */
264 static void ns_condemn_scroll_bars (struct frame *f);
265 static void ns_judge_scroll_bars (struct frame *f);
266 void x_set_frame_alpha (struct frame *f);
269 /* ==========================================================================
271     Utilities
273    ========================================================================== */
276 static Lisp_Object
277 append2 (Lisp_Object list, Lisp_Object item)
278 /* --------------------------------------------------------------------------
279    Utility to append to a list
280    -------------------------------------------------------------------------- */
282   Lisp_Object array[2];
283   array[0] = list;
284   array[1] = Fcons (item, Qnil);
285   return Fnconc (2, &array[0]);
289 void
290 ns_init_paths (void)
291 /* --------------------------------------------------------------------------
292    Used to allow emacs to find its resources under Emacs.app
293    Called from emacs.c at startup.
294    -------------------------------------------------------------------------- */
296   NSBundle *bundle = [NSBundle mainBundle];
297   NSString *binDir = [bundle bundlePath], *resourceDir = [bundle resourcePath];
298   NSString *resourcePath, *resourcePaths;
299   NSRange range;
300   BOOL onWindows = NO; /* how do I determine this? */
301   NSString *pathSeparator = onWindows ? @";" : @":";
302   NSFileManager *fileManager = [NSFileManager defaultManager];
303   BOOL isDir;
304 /*NSLog (@"ns_init_paths: '%@'\n%@\n", [[NSBundle mainBundle] bundlePath], [[NSBundle mainBundle] resourcePath]); */
306   /* get bindir from base */
307   range = [resourceDir rangeOfString: @"Contents"];
308   if (range.location != NSNotFound)
309     {
310       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
311 #ifdef NS_IMPL_COCOA
312       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
313 #endif
314     }
316   /* the following based on Andrew Choi's init_mac_osx_environment () */
317   if (!getenv ("EMACSLOADPATH"))
318     {
319       NSArray *paths = [resourceDir stringsByAppendingPaths:
320                                   [NSArray arrayWithObjects:
321                                          @"site-lisp", @"lisp", @"leim", nil]];
322       NSEnumerator *pathEnum = [paths objectEnumerator];
323       resourcePaths = @"";
324       while (resourcePath = [pathEnum nextObject])
325         {
326           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
327             if (isDir)
328               {
329                 if ([resourcePaths length] > 0)
330                   resourcePaths
331                     = [resourcePaths stringByAppendingString: pathSeparator];
332                 resourcePaths
333                   = [resourcePaths stringByAppendingString: resourcePath];
334               }
335         }
336       if ([resourcePaths length] > 0)
337         setenv ("EMACSLOADPATH", [resourcePaths UTF8String], 1);
338 /*NSLog (@"loadPath: '%@'\n", resourcePaths); */
339     }
341   /* Normally, Emacs does not add its own bin/ directory to the PATH.
342      However, a self-contained NS build has a different layout, with
343      bin/ and libexec/ subdirectories in the directory that contains
344      Emacs.app itself.
345      We put libexec first, because init_callproc_1 uses the first
346      element to initialize exec-directory.  An alternative would be
347      for init_callproc to check for invocation-directory/libexec.  */
348   if (!getenv ("EMACSPATH"))
349     {
350       NSArray *paths = [binDir stringsByAppendingPaths:
351                                   [NSArray arrayWithObjects: @"libexec",
352                                                              @"bin", nil]];
353       NSEnumerator *pathEnum = [paths objectEnumerator];
354       resourcePaths = @"";
355       while (resourcePath = [pathEnum nextObject])
356         {
357           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
358             if (isDir)
359               {
360                 if ([resourcePaths length] > 0)
361                   resourcePaths
362                     = [resourcePaths stringByAppendingString: pathSeparator];
363                 resourcePaths
364                   = [resourcePaths stringByAppendingString: resourcePath];
365               }
366         }
367       if ([resourcePaths length] > 0)
368         setenv ("EMACSPATH", [resourcePaths UTF8String], 1);
369     }
371   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
372   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
373     {
374       if (isDir)
375         {
376           if (!getenv ("EMACSDATA"))
377             setenv ("EMACSDATA", [resourcePath UTF8String], 1);
378           if (!getenv ("EMACSDOC"))
379             setenv ("EMACSDOC", [resourcePath UTF8String], 1);
380         }
381     }
385 static int
386 timeval_subtract (struct timeval *result, struct timeval x, struct timeval y)
387 /* --------------------------------------------------------------------------
388    Subtract the `struct timeval' values X and Y, storing the result in RESULT.
389    Return 1 if the difference is negative, otherwise 0.
390    -------------------------------------------------------------------------- */
392   /* Perform the carry for the later subtraction by updating y.
393      This is safer because on some systems
394      the tv_sec member is unsigned.  */
395   if (x.tv_usec < y.tv_usec)
396     {
397       int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
398       y.tv_usec -= 1000000 * nsec;
399       y.tv_sec += nsec;
400     }
401   if (x.tv_usec - y.tv_usec > 1000000)
402     {
403       int nsec = (y.tv_usec - x.tv_usec) / 1000000;
404       y.tv_usec += 1000000 * nsec;
405       y.tv_sec -= nsec;
406     }
408   /* Compute the time remaining to wait.  tv_usec is certainly positive.  */
409   result->tv_sec = x.tv_sec - y.tv_sec;
410   result->tv_usec = x.tv_usec - y.tv_usec;
412   /* Return indication of whether the result should be considered negative.  */
413   return x.tv_sec < y.tv_sec;
416 static void
417 ns_timeout (int usecs)
418 /* --------------------------------------------------------------------------
419      Blocking timer utility used by ns_ring_bell
420    -------------------------------------------------------------------------- */
422   struct timeval wakeup;
424   EMACS_GET_TIME (wakeup);
426   /* Compute time to wait until, propagating carry from usecs.  */
427   wakeup.tv_usec += usecs;
428   wakeup.tv_sec += (wakeup.tv_usec / 1000000);
429   wakeup.tv_usec %= 1000000;
431   /* Keep waiting until past the time wakeup.  */
432   while (1)
433     {
434       struct timeval timeout;
436       EMACS_GET_TIME (timeout);
438       /* In effect, timeout = wakeup - timeout.
439          Break if result would be negative.  */
440       if (timeval_subtract (&timeout, wakeup, timeout))
441         break;
443       /* Try to wait that long--but we might wake up sooner.  */
444       select (0, NULL, NULL, NULL, &timeout);
445     }
449 void
450 ns_release_object (void *obj)
451 /* --------------------------------------------------------------------------
452     Release an object (callable from C)
453    -------------------------------------------------------------------------- */
455     [(id)obj release];
459 void
460 ns_retain_object (void *obj)
461 /* --------------------------------------------------------------------------
462     Retain an object (callable from C)
463    -------------------------------------------------------------------------- */
465     [(id)obj retain];
469 void *
470 ns_alloc_autorelease_pool (void)
471 /* --------------------------------------------------------------------------
472      Allocate a pool for temporary objects (callable from C)
473    -------------------------------------------------------------------------- */
475   return [[NSAutoreleasePool alloc] init];
479 void
480 ns_release_autorelease_pool (void *pool)
481 /* --------------------------------------------------------------------------
482      Free a pool and temporary objects it refers to (callable from C)
483    -------------------------------------------------------------------------- */
485   ns_release_object (pool);
490 /* ==========================================================================
492     Focus (clipping) and screen update
494    ========================================================================== */
496 static NSRect
497 ns_resize_handle_rect (NSWindow *window)
499   NSRect r = [window frame];
500   r.origin.x = r.size.width - RESIZE_HANDLE_SIZE;
501   r.origin.y = 0;
502   r.size.width = r.size.height = RESIZE_HANDLE_SIZE;
503   return r;
508 // Window constraining
509 // -------------------
511 // To ensure that the windows are not placed under the menu bar, they
512 // are typically moved by the call-back constrainFrameRect. However,
513 // by overriding it, it's possible to inhibit this, leaving the window
514 // in it's original position.
516 // It's possible to hide the menu bar. However, technically, it's only
517 // possible to hide it when the application is active. To ensure that
518 // this work properly, the menu bar and window constraining are
519 // deferred until the application becomes active.
521 // Even though it's not possible to manually move a window above the
522 // top of the screen, it is allowed if it's done programmatically,
523 // when the menu is hidden. This allows the editable area to cover the
524 // full screen height.
526 // Test cases
527 // ----------
529 // Use the following extra files:
531 //    init.el:
532 //       ;; Hide menu and place frame slightly above the top of the screen.
533 //       (setq ns-auto-hide-menu-bar t)
534 //       (set-frame-position (selected-frame) 0 -20)
536 // Test 1:
538 //    emacs -Q -l init.el
540 //    Result: No menu bar, and the title bar should be above the screen.
542 // Test 2:
544 //    emacs -Q
546 //    Result: Menu bar visible, frame placed immediately below the menu.
549 static void
550 ns_constrain_all_frames (void)
552   Lisp_Object tail, frame;
554   FOR_EACH_FRAME (tail, frame)
555     {
556       struct frame *f = XFRAME (frame);
557       if (FRAME_NS_P (f))
558         {
559           NSView *view = FRAME_NS_VIEW (f);
560           /* This no-op will trigger the default window placing
561            * constraint system. */
562           f->output_data.ns->dont_constrain = 0;
563           [[view window] setFrameOrigin:[[view window] frame].origin];
564         }
565     }
569 /* True, if the menu bar should be hidden.  */
571 static BOOL
572 ns_menu_bar_should_be_hidden (void)
574   return !NILP (ns_auto_hide_menu_bar)
575     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
579 /* Show or hide the menu bar, based on user setting.  */
581 static void
582 ns_update_auto_hide_menu_bar (void)
584 #ifndef MAC_OS_X_VERSION_10_6
585 #define MAC_OS_X_VERSION_10_6 1060
586 #endif
587 #ifdef NS_IMPL_COCOA
588 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
589   BLOCK_INPUT;
591   NSTRACE (ns_update_auto_hide_menu_bar);
593   if (NSApp != nil
594       && [NSApp isActive]
595       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
596     {
597       // Note, "setPresentationOptions" triggers an error unless the
598       // application is active.
599       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
601       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
602         {
603           NSApplicationPresentationOptions options
604             = NSApplicationPresentationAutoHideDock;
606           if (menu_bar_should_be_hidden)
607             options |= NSApplicationPresentationAutoHideMenuBar;
609           [NSApp setPresentationOptions: options];
611           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
613           if (!ns_menu_bar_is_hidden)
614             {
615               ns_constrain_all_frames ();
616             }
617         }
618     }
620   UNBLOCK_INPUT;
621 #endif
622 #endif
626 static void
627 ns_update_begin (struct frame *f)
628 /* --------------------------------------------------------------------------
629    Prepare for a grouped sequence of drawing calls
630    external (RIF) call; whole frame, called before update_window_begin
631    -------------------------------------------------------------------------- */
633   NSView *view = FRAME_NS_VIEW (f);
634   NSTRACE (ns_update_begin);
636   ns_update_auto_hide_menu_bar ();
638   ns_updating_frame = f;
639   [view lockFocus];
641 #ifdef NS_IMPL_GNUSTEP
642   uRect = NSMakeRect (0, 0, 0, 0);
643 #endif
647 static void
648 ns_update_window_begin (struct window *w)
649 /* --------------------------------------------------------------------------
650    Prepare for a grouped sequence of drawing calls
651    external (RIF) call; for one window, called after update_begin
652    -------------------------------------------------------------------------- */
654   struct frame *f = XFRAME (WINDOW_FRAME (w));
655  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
656   NSTRACE (ns_update_window_begin);
658   updated_window = w;
659   set_output_cursor (&w->cursor);
661   BLOCK_INPUT;
663   if (f == hlinfo->mouse_face_mouse_frame)
664     {
665       /* Don't do highlighting for mouse motion during the update.  */
666       hlinfo->mouse_face_defer = 1;
668         /* If the frame needs to be redrawn,
669            simply forget about any prior mouse highlighting.  */
670       if (FRAME_GARBAGED_P (f))
671         hlinfo->mouse_face_window = Qnil;
673       /* (further code for mouse faces ifdef'd out in other terms elided) */
674     }
676   UNBLOCK_INPUT;
680 static void
681 ns_update_window_end (struct window *w, int cursor_on_p,
682                       int mouse_face_overwritten_p)
683 /* --------------------------------------------------------------------------
684    Finished a grouped sequence of drawing calls
685    external (RIF) call; for one window called before update_end
686    -------------------------------------------------------------------------- */
688   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
690   /* note: this fn is nearly identical in all terms */
691   if (!w->pseudo_window_p)
692     {
693       BLOCK_INPUT;
695       if (cursor_on_p)
696         display_and_set_cursor (w, 1,
697                                 output_cursor.hpos, output_cursor.vpos,
698                                 output_cursor.x, output_cursor.y);
700       if (draw_window_fringes (w, 1))
701         x_draw_vertical_border (w);
703       UNBLOCK_INPUT;
704     }
706   /* If a row with mouse-face was overwritten, arrange for
707      frame_up_to_date to redisplay the mouse highlight.  */
708   if (mouse_face_overwritten_p)
709     {
710       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
711       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
712       hlinfo->mouse_face_window = Qnil;
713     }
715   updated_window = NULL;
716   NSTRACE (update_window_end);
720 static void
721 ns_update_end (struct frame *f)
722 /* --------------------------------------------------------------------------
723    Finished a grouped sequence of drawing calls
724    external (RIF) call; for whole frame, called after update_window_end
725    -------------------------------------------------------------------------- */
727   NSView *view = FRAME_NS_VIEW (f);
729 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
730     MOUSE_HL_INFO (f)->mouse_face_defer = 0;
732   BLOCK_INPUT;
734 #ifdef NS_IMPL_GNUSTEP
735   /* trigger flush only in the rectangle we tracked as being drawn */
736   [view unlockFocusNeedsFlush: NO];
737 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
738   [view lockFocusInRect: uRect];
739 #endif
741   [view unlockFocus];
742   [[view window] flushWindow];
744   UNBLOCK_INPUT;
745   ns_updating_frame = NULL;
746   NSTRACE (ns_update_end);
750 static void
751 ns_flush (struct frame *f)
752 /* --------------------------------------------------------------------------
753    external (RIF) call
754    NS impl is no-op since currently we flush in ns_update_end and elsewhere
755    -------------------------------------------------------------------------- */
757     NSTRACE (ns_flush);
761 static void
762 ns_focus (struct frame *f, NSRect *r, int n)
763 /* --------------------------------------------------------------------------
764    Internal: Focus on given frame.  During small local updates this is used to
765      draw, however during large updates, ns_update_begin and ns_update_end are
766      called to wrap the whole thing, in which case these calls are stubbed out.
767      Except, on GNUstep, we accumulate the rectangle being drawn into, because
768      the back end won't do this automatically, and will just end up flushing
769      the entire window.
770    -------------------------------------------------------------------------- */
772 //  NSTRACE (ns_focus);
773 #ifdef NS_IMPL_GNUSTEP
774   NSRect u;
775     if (n == 2)
776       u = NSUnionRect (r[0], r[1]);
777     else if (r)
778       u = *r;
779 #endif
780 /* static int c =0;
781    fprintf (stderr, "focus: %d", c++);
782    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
783    fprintf (stderr, "\n"); */
785   if (f != ns_updating_frame)
786     {
787       NSView *view = FRAME_NS_VIEW (f);
788       if (view != focus_view)
789         {
790           if (focus_view != NULL)
791             {
792               [focus_view unlockFocus];
793               [[focus_view window] flushWindow];
794 /*debug_lock--; */
795             }
797           if (view)
798 #ifdef NS_IMPL_GNUSTEP
799             r ? [view lockFocusInRect: u] : [view lockFocus];
800 #else
801             [view lockFocus];
802 #endif
803           focus_view = view;
804 /*if (view) debug_lock++; */
805         }
806 #ifdef NS_IMPL_GNUSTEP
807       else
808         {
809           /* more than one rect being drawn into */
810           if (view && r)
811             {
812               [view unlockFocus]; /* add prev rect to redraw list */
813               [view lockFocusInRect: u]; /* focus for draw in new rect */
814             }
815         }
816 #endif
817     }
818 #ifdef NS_IMPL_GNUSTEP
819   else
820     {
821       /* in batch mode, but in GNUstep must still track rectangles explicitly */
822       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
823     }
824 #endif
826   /* clipping */
827   if (r)
828     {
829       [[NSGraphicsContext currentContext] saveGraphicsState];
830       if (n == 2)
831         NSRectClipList (r, 2);
832       else
833         NSRectClip (*r);
834       gsaved = YES;
835     }
839 static void
840 ns_unfocus (struct frame *f)
841 /* --------------------------------------------------------------------------
842      Internal: Remove focus on given frame
843    -------------------------------------------------------------------------- */
845 //  NSTRACE (ns_unfocus);
847   if (gsaved)
848     {
849       [[NSGraphicsContext currentContext] restoreGraphicsState];
850       gsaved = NO;
851     }
853   if (f != ns_updating_frame)
854     {
855       if (focus_view != NULL)
856         {
857           [focus_view unlockFocus];
858           [[focus_view window] flushWindow];
859           focus_view = NULL;
860 /*debug_lock--; */
861         }
862     }
866 static void
867 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
868 /* --------------------------------------------------------------------------
869      Internal (but parallels other terms): Focus drawing on given row
870    -------------------------------------------------------------------------- */
872   struct frame *f = XFRAME (WINDOW_FRAME (w));
873   NSRect clip_rect;
874   int window_x, window_y, window_width;
876   window_box (w, area, &window_x, &window_y, &window_width, 0);
878   clip_rect.origin.x = window_x - FRAME_INTERNAL_BORDER_WIDTH (f);
879   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
880   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
881   clip_rect.size.width = window_width + 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
882   clip_rect.size.height = row->visible_height;
884   /* allow a full-height row at the top when requested
885      (used to draw fringe all the way through internal border area) */
886   if (gc && clip_rect.origin.y < 5)
887     {
888       clip_rect.origin.y -= FRAME_INTERNAL_BORDER_WIDTH (f);
889       clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
890     }
892   /* likewise at bottom */
893   if (gc &&
894       FRAME_PIXEL_HEIGHT (f) - (clip_rect.origin.y + clip_rect.size.height) < 5)
895     clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
897   ns_focus (f, &clip_rect, 1);
901 static void
902 ns_ring_bell (struct frame *f)
903 /* --------------------------------------------------------------------------
904      "Beep" routine
905    -------------------------------------------------------------------------- */
907   NSTRACE (ns_ring_bell);
908   if (visible_bell)
909     {
910       NSAutoreleasePool *pool;
911       struct frame *frame = SELECTED_FRAME ();
912       NSView *view;
914       BLOCK_INPUT;
915       pool = [[NSAutoreleasePool alloc] init];
917       view = FRAME_NS_VIEW (frame);
918       if (view != nil)
919         {
920           NSRect r, surr;
921           NSPoint dim = NSMakePoint (128, 128);
923           r = [view bounds];
924           r.origin.x += (r.size.width - dim.x) / 2;
925           r.origin.y += (r.size.height - dim.y) / 2;
926           r.size.width = dim.x;
927           r.size.height = dim.y;
928           surr = NSInsetRect (r, -2, -2);
929           ns_focus (frame, &surr, 1);
930           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
931           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
932                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
933           NSRectFill (r);
934           [[view window] flushWindow];
935           ns_timeout (150000);
936           [[view window] restoreCachedImage];
937           [[view window] flushWindow];
938           ns_unfocus (frame);
939         }
940       [pool release];
941       UNBLOCK_INPUT;
942     }
943   else
944     {
945       NSBeep ();
946     }
950 static void
951 ns_reset_terminal_modes (struct terminal *terminal)
952 /*  Externally called as hook */
954   NSTRACE (ns_reset_terminal_modes);
958 static void
959 ns_set_terminal_modes (struct terminal *terminal)
960 /*  Externally called as hook */
962   NSTRACE (ns_set_terminal_modes);
967 /* ==========================================================================
969     Frame / window manager related functions
971    ========================================================================== */
974 static void
975 ns_raise_frame (struct frame *f)
976 /* --------------------------------------------------------------------------
977      Bring window to foreground and make it active
978    -------------------------------------------------------------------------- */
980   NSView *view = FRAME_NS_VIEW (f);
981   check_ns ();
982   BLOCK_INPUT;
983   FRAME_SAMPLE_VISIBILITY (f);
984   if (FRAME_VISIBLE_P (f))
985     {
986       [[view window] makeKeyAndOrderFront: NSApp];
987     }
988   UNBLOCK_INPUT;
992 static void
993 ns_lower_frame (struct frame *f)
994 /* --------------------------------------------------------------------------
995      Send window to back
996    -------------------------------------------------------------------------- */
998   NSView *view = FRAME_NS_VIEW (f);
999   check_ns ();
1000   BLOCK_INPUT;
1001   [[view window] orderBack: NSApp];
1002   UNBLOCK_INPUT;
1006 static void
1007 ns_frame_raise_lower (struct frame *f, int raise)
1008 /* --------------------------------------------------------------------------
1009      External (hook)
1010    -------------------------------------------------------------------------- */
1012   NSTRACE (ns_frame_raise_lower);
1014   if (raise)
1015     ns_raise_frame (f);
1016   else
1017     ns_lower_frame (f);
1021 static void
1022 ns_frame_rehighlight (struct frame *frame)
1023 /* --------------------------------------------------------------------------
1024      External (hook): called on things like window switching within frame
1025    -------------------------------------------------------------------------- */
1027   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1028   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1030   NSTRACE (ns_frame_rehighlight);
1031   if (dpyinfo->x_focus_frame)
1032     {
1033       dpyinfo->x_highlight_frame
1034         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1035            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1036            : dpyinfo->x_focus_frame);
1037       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1038         {
1039           FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
1040           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1041         }
1042     }
1043   else
1044       dpyinfo->x_highlight_frame = 0;
1046   if (dpyinfo->x_highlight_frame &&
1047          dpyinfo->x_highlight_frame != old_highlight)
1048     {
1049       if (old_highlight)
1050         {
1051           x_update_cursor (old_highlight, 1);
1052           x_set_frame_alpha (old_highlight);
1053         }
1054       if (dpyinfo->x_highlight_frame)
1055         {
1056           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1057           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1058         }
1059     }
1063 void
1064 x_make_frame_visible (struct frame *f)
1065 /* --------------------------------------------------------------------------
1066      External: Show the window (X11 semantics)
1067    -------------------------------------------------------------------------- */
1069   NSTRACE (x_make_frame_visible);
1070   /* XXX: at some points in past this was not needed, as the only place that
1071      called this (frame.c:Fraise_frame ()) also called raise_lower;
1072      if this ends up the case again, comment this out again. */
1073   if (!FRAME_VISIBLE_P (f))
1074     {
1075       f->async_visible = 1;
1076       ns_raise_frame (f);
1077     }
1081 void
1082 x_make_frame_invisible (struct frame *f)
1083 /* --------------------------------------------------------------------------
1084      External: Hide the window (X11 semantics)
1085    -------------------------------------------------------------------------- */
1087   NSView * view = FRAME_NS_VIEW (f);
1088   NSTRACE (x_make_frame_invisible);
1089   check_ns ();
1090   [[view window] orderOut: NSApp];
1091   f->async_visible = 0;
1092   f->async_iconified = 0;
1096 void
1097 x_iconify_frame (struct frame *f)
1098 /* --------------------------------------------------------------------------
1099      External: Iconify window
1100    -------------------------------------------------------------------------- */
1102   NSView * view = FRAME_NS_VIEW (f);
1103   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1104   NSTRACE (x_iconify_frame);
1105   check_ns ();
1107   if (dpyinfo->x_highlight_frame == f)
1108     dpyinfo->x_highlight_frame = 0;
1110   if ([[view window] windowNumber] <= 0)
1111     {
1112       /* the window is still deferred.  Make it very small, bring it
1113          on screen and order it out. */
1114       NSRect s = { { 100, 100}, {0, 0} };
1115       NSRect t;
1116       t = [[view window] frame];
1117       [[view window] setFrame: s display: NO];
1118       [[view window] orderBack: NSApp];
1119       [[view window] orderOut: NSApp];
1120       [[view window] setFrame: t display: NO];
1121     }
1122   [[view window] miniaturize: NSApp];
1125 /* Free X resources of frame F.  */
1127 void
1128 x_free_frame_resources (struct frame *f)
1130   NSView *view = FRAME_NS_VIEW (f);
1131   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1132   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1133   NSTRACE (x_destroy_window);
1134   check_ns ();
1136   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1138   BLOCK_INPUT;
1140   free_frame_menubar (f);
1142   if (FRAME_FACE_CACHE (f))
1143     free_frame_faces (f);
1145   if (f == dpyinfo->x_focus_frame)
1146     dpyinfo->x_focus_frame = 0;
1147   if (f == dpyinfo->x_highlight_frame)
1148     dpyinfo->x_highlight_frame = 0;
1149   if (f == hlinfo->mouse_face_mouse_frame)
1150     {
1151       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1152       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1153       hlinfo->mouse_face_window = Qnil;
1154       hlinfo->mouse_face_deferred_gc = 0;
1155       hlinfo->mouse_face_mouse_frame = 0;
1156     }
1158   if (f->output_data.ns->miniimage != nil)
1159     [f->output_data.ns->miniimage release];
1161   [[view window] close];
1162   [view release];
1164   xfree (f->output_data.ns);
1166   UNBLOCK_INPUT;
1169 void
1170 x_destroy_window (struct frame *f)
1171 /* --------------------------------------------------------------------------
1172      External: Delete the window
1173    -------------------------------------------------------------------------- */
1175   NSTRACE (x_destroy_window);
1176   check_ns ();
1177   x_free_frame_resources (f);
1178   ns_window_num--;
1182 void
1183 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1184 /* --------------------------------------------------------------------------
1185      External: Position the window
1186    -------------------------------------------------------------------------- */
1188   NSView *view = FRAME_NS_VIEW (f);
1189   NSArray *screens = [NSScreen screens];
1190   NSScreen *fscreen = [screens objectAtIndex: 0];
1191   NSScreen *screen = [[view window] screen];
1193   NSTRACE (x_set_offset);
1195   BLOCK_INPUT;
1197   f->left_pos = xoff;
1198   f->top_pos = yoff;
1200   if (view != nil && screen && fscreen)
1201     {
1202       f->left_pos = f->size_hint_flags & XNegative
1203         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1204         : f->left_pos;
1205       /* We use visibleFrame here to take menu bar into account.
1206          Ideally we should also adjust left/top with visibleFrame.origin.  */
1208       f->top_pos = f->size_hint_flags & YNegative
1209         ? ([screen visibleFrame].size.height + f->top_pos
1210            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1211            - FRAME_TOOLBAR_HEIGHT (f))
1212         : f->top_pos;
1213 #ifdef NS_IMPL_GNUSTEP
1214       if (f->left_pos < 100)
1215         f->left_pos = 100;  /* don't overlap menu */
1216 #endif
1217       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1218          menu bar.  */
1219       f->output_data.ns->dont_constrain = 0;
1220       [[view window] setFrameTopLeftPoint:
1221                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1222                                     SCREENMAXBOUND ([fscreen frame].size.height
1223                                                     - NS_TOP_POS (f)))];
1224       f->size_hint_flags &= ~(XNegative|YNegative);
1225     }
1227   UNBLOCK_INPUT;
1231 void
1232 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1233 /* --------------------------------------------------------------------------
1234      Adjust window pixel size based on given character grid size
1235      Impl is a bit more complex than other terms, need to do some
1236      internal clipping.
1237    -------------------------------------------------------------------------- */
1239   EmacsView *view = FRAME_NS_VIEW (f);
1240   EmacsToolbar *toolbar = [view toolbar];
1241   NSWindow *window = [view window];
1242   NSRect wr = [window frame];
1243   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1244   int pixelwidth, pixelheight;
1245   static int oldRows, oldCols, oldFontWidth, oldFontHeight;
1246   static int oldTB;
1247   static struct frame *oldF;
1249   NSTRACE (x_set_window_size);
1251   if (view == nil ||
1252       (f == oldF
1253        && rows == oldRows && cols == oldCols
1254        && oldFontWidth == FRAME_COLUMN_WIDTH (f)
1255        && oldFontHeight == FRAME_LINE_HEIGHT (f)
1256        && oldTB == tb))
1257     return;
1259 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1261   BLOCK_INPUT;
1263   check_frame_size (f, &rows, &cols);
1264   oldF = f;
1265   oldRows = rows;
1266   oldCols = cols;
1267   oldFontWidth = FRAME_COLUMN_WIDTH (f);
1268   oldFontHeight = FRAME_LINE_HEIGHT (f);
1269   oldTB = tb;
1271   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1272   compute_fringe_widths (f, 0);
1274   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1275   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1277   /* If we have a toolbar, take its height into account. */
1278   if (tb)
1279     /* NOTE: previously this would generate wrong result if toolbar not
1280              yet displayed and fixing toolbar_height=32 helped, but
1281              now (200903) seems no longer needed */
1282     FRAME_TOOLBAR_HEIGHT (f) =
1283       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1284         - FRAME_NS_TITLEBAR_HEIGHT (f);
1285   else
1286     FRAME_TOOLBAR_HEIGHT (f) = 0;
1288   wr.size.width = pixelwidth + f->border_width;
1289   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f)
1290                   + FRAME_TOOLBAR_HEIGHT (f);
1292   /* Do not try to constrain to this screen.  We may have multiple
1293      screens, and want Emacs to span those.  Constraining to screen
1294      prevents that, and that is not nice to the user.  */
1295  if (f->output_data.ns->zooming)
1296    f->output_data.ns->zooming = 0;
1297  else
1298    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1300   [view setRows: rows andColumns: cols];
1301   [window setFrame: wr display: YES];
1303 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1305   /* This is a trick to compensate for Emacs' managing the scrollbar area
1306      as a fixed number of standard character columns.  Instead of leaving
1307      blank space for the extra, we chopped it off above.  Now for
1308      left-hand scrollbars, we shift all rendering to the left by the
1309      difference between the real width and Emacs' imagined one.  For
1310      right-hand bars, don't worry about it since the extra is never used.
1311      (Obviously doesn't work for vertically split windows tho..) */
1312   {
1313     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1314       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1315                      - NS_SCROLL_BAR_WIDTH (f), 0)
1316       : NSMakePoint (0, 0);
1317     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1318     [view setBoundsOrigin: origin];
1319   }
1321   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1322   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1323   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1324 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1326   mark_window_cursors_off (XWINDOW (f->root_window));
1327   cancel_mouse_face (f);
1329   UNBLOCK_INPUT;
1334 /* ==========================================================================
1336     Color management
1338    ========================================================================== */
1341 NSColor *
1342 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1344   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1345   if (idx < 1 || idx >= color_table->avail)
1346     return nil;
1347   return color_table->colors[idx];
1351 unsigned long
1352 ns_index_color (NSColor *color, struct frame *f)
1354   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1355   ptrdiff_t idx;
1356   ptrdiff_t i;
1358   if (!color_table->colors)
1359     {
1360       color_table->size = NS_COLOR_CAPACITY;
1361       color_table->avail = 1; /* skip idx=0 as marker */
1362       color_table->colors
1363         = (NSColor **)xmalloc (color_table->size * sizeof (NSColor *));
1364       color_table->colors[0] = nil;
1365       color_table->empty_indices = [[NSMutableSet alloc] init];
1366     }
1368   /* do we already have this color ? */
1369   for (i = 1; i < color_table->avail; i++)
1370     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1371       return i;
1373   if ([color_table->empty_indices count] > 0)
1374     {
1375       NSNumber *index = [color_table->empty_indices anyObject];
1376       [color_table->empty_indices removeObject: index];
1377       idx = [index unsignedLongValue];
1378     }
1379   else
1380     {
1381       if (color_table->avail == color_table->size)
1382         color_table->colors =
1383           xpalloc (color_table->colors, &color_table->size, 1,
1384                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1385       idx = color_table->avail++;
1386     }
1388   color_table->colors[idx] = color;
1389   [color retain];
1390 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1391   return idx;
1395 void
1396 ns_free_indexed_color (unsigned long idx, struct frame *f)
1398   struct ns_color_table *color_table;
1399   NSColor *color;
1400   NSNumber *index;
1402   if (!f)
1403     return;
1405   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1407   if (idx <= 0 || idx >= color_table->size) {
1408     message1 ("ns_free_indexed_color: Color index out of range.\n");
1409     return;
1410   }
1412   index = [NSNumber numberWithUnsignedInt: idx];
1413   if ([color_table->empty_indices containsObject: index]) {
1414     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1415     return;
1416   }
1418   color = color_table->colors[idx];
1419   [color release];
1420   color_table->colors[idx] = nil;
1421   [color_table->empty_indices addObject: index];
1422 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1426 static int
1427 ns_get_color (const char *name, NSColor **col)
1428 /* --------------------------------------------------------------------------
1429      Parse a color name
1430    -------------------------------------------------------------------------- */
1431 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1432    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1433    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1435   NSColor *new = nil;
1436   static char hex[20];
1437   int scaling;
1438   float r = -1.0, g, b;
1439   NSString *nsname = [NSString stringWithUTF8String: name];
1441 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1442   BLOCK_INPUT;
1444   if ([nsname isEqualToString: @"ns_selection_color"])
1445     {
1446       nsname = ns_selection_color;
1447       name = [ns_selection_color UTF8String];
1448     }
1450   /* First, check for some sort of numeric specification. */
1451   hex[0] = '\0';
1453   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1454     {
1455       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1456       [scanner scanFloat: &r];
1457       [scanner scanFloat: &g];
1458       [scanner scanFloat: &b];
1459     }
1460   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1461     {
1462       strncpy (hex, name + 4, 19);
1463       hex[19] = '\0';
1464       scaling = (strlen(hex) - 2) / 3;
1465     }
1466   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1467     {
1468       int len = (strlen(name) - 1);
1469       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1470       int i;
1471       scaling = strlen(name+start) / 3;
1472       for (i=0; i<3; i++) {
1473         strncpy(hex + i * (scaling + 1), name + start + i * scaling, scaling);
1474         hex[(i+1) * (scaling + 1) - 1] = '/';
1475       }
1476       hex[3 * (scaling + 1) - 1] = '\0';
1477     }
1479   if (hex[0])
1480     {
1481       int rr, gg, bb;
1482       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1483       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1484         {
1485           r = rr / fscale;
1486           g = gg / fscale;
1487           b = bb / fscale;
1488         }
1489     }
1491   if (r >= 0.0)
1492     {
1493       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1494       UNBLOCK_INPUT;
1495       return 0;
1496     }
1498   /* Otherwise, color is expected to be from a list */
1499   {
1500     NSEnumerator *lenum, *cenum;
1501     NSString *name;
1502     NSColorList *clist;
1504 #ifdef NS_IMPL_GNUSTEP
1505     /* XXX: who is wrong, the requestor or the implementation? */
1506     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1507         == NSOrderedSame)
1508       nsname = @"highlightColor";
1509 #endif
1511     lenum = [[NSColorList availableColorLists] objectEnumerator];
1512     while ( (clist = [lenum nextObject]) && new == nil)
1513       {
1514         cenum = [[clist allKeys] objectEnumerator];
1515         while ( (name = [cenum nextObject]) && new == nil )
1516           {
1517             if ([name compare: nsname
1518                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1519               new = [clist colorWithKey: name];
1520           }
1521       }
1522   }
1524   if (new)
1525     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1526   UNBLOCK_INPUT;
1527   return new ? 0 : 1;
1531 static NSColor *
1532 ns_get_color_default (const char *name, NSColor *dflt)
1533 /* --------------------------------------------------------------------------
1534      Parse a color or use a default value
1535    -------------------------------------------------------------------------- */
1537   NSColor * col;
1539   if (ns_get_color (name, &col))
1540     return dflt;
1541   else
1542     return col;
1547 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1548 /* --------------------------------------------------------------------------
1549      Convert a Lisp string object to a NS color
1550    -------------------------------------------------------------------------- */
1552   NSTRACE (ns_lisp_to_color);
1553   if (STRINGP (color))
1554     return ns_get_color (SDATA (color), col);
1555   else if (SYMBOLP (color))
1556     return ns_get_color (SDATA (SYMBOL_NAME (color)), col);
1557   return 1;
1561 Lisp_Object
1562 ns_color_to_lisp (NSColor *col)
1563 /* --------------------------------------------------------------------------
1564      Convert a color to a lisp string with the RGB equivalent
1565    -------------------------------------------------------------------------- */
1567   CGFloat red, green, blue, alpha, gray;
1568   char buf[1024];
1569   const char *str;
1570   NSTRACE (ns_color_to_lisp);
1572   BLOCK_INPUT;
1573   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1575       if ((str =[[col colorNameComponent] UTF8String]))
1576         {
1577           UNBLOCK_INPUT;
1578           return build_string ((char *)str);
1579         }
1581     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1582         getRed: &red green: &green blue: &blue alpha: &alpha];
1583   if (red ==green && red ==blue)
1584     {
1585       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1586             getWhite: &gray alpha: &alpha];
1587       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1588                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1589       UNBLOCK_INPUT;
1590       return build_string (buf);
1591     }
1593   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1594             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1596   UNBLOCK_INPUT;
1597   return build_string (buf);
1601 void
1602 ns_query_color(void *col, XColor *color_def, int setPixel)
1603 /* --------------------------------------------------------------------------
1604          Get ARGB values out of NSColor col and put them into color_def.
1605          If setPixel, set the pixel to a concatenated version.
1606          and set color_def pixel to the resulting index.
1607    -------------------------------------------------------------------------- */
1609   CGFloat r, g, b, a;
1611   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1612   color_def->red   = r * 65535;
1613   color_def->green = g * 65535;
1614   color_def->blue  = b * 65535;
1616   if (setPixel == YES)
1617     color_def->pixel
1618       = ARGB_TO_ULONG((int)(a*255),
1619                       (int)(r*255), (int)(g*255), (int)(b*255));
1624 ns_defined_color (struct frame *f,
1625                   const char *name,
1626                   XColor *color_def,
1627                   int alloc,
1628                   char makeIndex)
1629 /* --------------------------------------------------------------------------
1630          Return 1 if named color found, and set color_def rgb accordingly.
1631          If makeIndex and alloc are nonzero put the color in the color_table,
1632          and set color_def pixel to the resulting index.
1633          If makeIndex is zero, set color_def pixel to ARGB.
1634          Return 0 if not found
1635    -------------------------------------------------------------------------- */
1637   NSColor *col;
1638   NSTRACE (ns_defined_color);
1640   BLOCK_INPUT;
1641   if (ns_get_color (name, &col) != 0) /* Color not found  */
1642     {
1643       UNBLOCK_INPUT;
1644       return 0;
1645     }
1646   if (makeIndex && alloc)
1647     color_def->pixel = ns_index_color (col, f);
1648   ns_query_color (col, color_def, !makeIndex);
1649   UNBLOCK_INPUT;
1650   return 1;
1654 unsigned long
1655 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1656 /* --------------------------------------------------------------------------
1657     return an autoreleased RGB color
1658    -------------------------------------------------------------------------- */
1660 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1661   if (r < 0.0) r = 0.0;
1662   else if (r > 1.0) r = 1.0;
1663   if (g < 0.0) g = 0.0;
1664   else if (g > 1.0) g = 1.0;
1665   if (b < 0.0) b = 0.0;
1666   else if (b > 1.0) b = 1.0;
1667   if (a < 0.0) a = 0.0;
1668   else if (a > 1.0) a = 1.0;
1669   return (unsigned long) ns_index_color(
1670     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1674 void
1675 x_set_frame_alpha (struct frame *f)
1676 /* --------------------------------------------------------------------------
1677      change the entire-frame transparency
1678    -------------------------------------------------------------------------- */
1680   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1681   EmacsView *view = FRAME_NS_VIEW (f);
1682   double alpha = 1.0;
1683   double alpha_min = 1.0;
1685   if (dpyinfo->x_highlight_frame == f)
1686     alpha = f->alpha[0];
1687   else
1688     alpha = f->alpha[1];
1690   if (FLOATP (Vframe_alpha_lower_limit))
1691     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1692   else if (INTEGERP (Vframe_alpha_lower_limit))
1693     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1695   if (alpha < 0.0)
1696     return;
1697   else if (1.0 < alpha)
1698     alpha = 1.0;
1699   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1700     alpha = alpha_min;
1702 #ifdef NS_IMPL_COCOA
1703   [[view window] setAlphaValue: alpha];
1704 #endif
1708 /* ==========================================================================
1710     Mouse handling
1712    ========================================================================== */
1715 void
1716 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1717 /* --------------------------------------------------------------------------
1718      Programmatically reposition mouse pointer in pixel coordinates
1719    -------------------------------------------------------------------------- */
1721   NSTRACE (x_set_mouse_pixel_position);
1722   ns_raise_frame (f);
1723 #if 0
1724   /* FIXME: this does not work, and what about GNUstep? */
1725 #ifdef NS_IMPL_COCOA
1726   [FRAME_NS_VIEW (f) lockFocus];
1727   PSsetmouse ((float)pix_x, (float)pix_y);
1728   [FRAME_NS_VIEW (f) unlockFocus];
1729 #endif
1730 #endif
1734 void
1735 x_set_mouse_position (struct frame *f, int h, int v)
1736 /* --------------------------------------------------------------------------
1737      Programmatically reposition mouse pointer in character coordinates
1738    -------------------------------------------------------------------------- */
1740   int pix_x, pix_y;
1742   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1743   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1745   if (pix_x < 0) pix_x = 0;
1746   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1748   if (pix_y < 0) pix_y = 0;
1749   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1751   x_set_mouse_pixel_position (f, pix_x, pix_y);
1755 static int
1756 note_mouse_movement (struct frame *frame, float x, float y)
1757 /*   ------------------------------------------------------------------------
1758      Called by EmacsView on mouseMovement events.  Passes on
1759      to emacs mainstream code if we moved off of a rect of interest
1760      known as last_mouse_glyph.
1761      ------------------------------------------------------------------------ */
1763 //  NSTRACE (note_mouse_movement);
1765   XSETFRAME (last_mouse_motion_frame, frame);
1767   /* Note, this doesn't get called for enter/leave, since we don't have a
1768      position.  Those are taken care of in the corresponding NSView methods. */
1770   /* has movement gone beyond last rect we were tracking? */
1771   if (x < last_mouse_glyph.origin.x ||
1772       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1773       y < last_mouse_glyph.origin.y ||
1774       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1775     {
1776       ns_update_begin(frame);
1777       frame->mouse_moved = 1;
1778       note_mouse_highlight (frame, x, y);
1779       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1780       ns_update_end(frame);
1781       return 1;
1782     }
1784   return 0;
1788 static void
1789 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1790                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1791                    Time *time)
1792 /* --------------------------------------------------------------------------
1793     External (hook): inform emacs about mouse position and hit parts.
1794     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1795     x & y should be position in the scrollbar (the whole bar, not the handle)
1796     and length of scrollbar respectively
1797    -------------------------------------------------------------------------- */
1799   id view;
1800   NSPoint position;
1801   int xchar, ychar;
1802   Lisp_Object frame, tail;
1803   struct frame *f;
1804   struct ns_display_info *dpyinfo;
1806   NSTRACE (ns_mouse_position);
1808   if (*fp == NULL)
1809     {
1810       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1811       return;
1812     }
1814   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1816   BLOCK_INPUT;
1818   if (last_mouse_scroll_bar != nil && insist == 0)
1819     {
1820       /* TODO: we do not use this path at the moment because drag events will
1821            go directly to the EmacsScroller.  Leaving code in for now. */
1822       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1823                                               x: x y: y];
1824       if (time) *time = last_mouse_movement_time;
1825       last_mouse_scroll_bar = nil;
1826     }
1827   else
1828     {
1829       /* Clear the mouse-moved flag for every frame on this display.  */
1830       FOR_EACH_FRAME (tail, frame)
1831         if (FRAME_NS_P (XFRAME (frame))
1832             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1833           XFRAME (frame)->mouse_moved = 0;
1835       last_mouse_scroll_bar = nil;
1836       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1837         f = last_mouse_frame;
1838       else
1839         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1840                                     : SELECTED_FRAME ();
1842       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1843         {
1844           view = FRAME_NS_VIEW (*fp);
1846           position = [[view window] mouseLocationOutsideOfEventStream];
1847           position = [view convertPoint: position fromView: nil];
1848           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1849 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1851           if (bar_window) *bar_window = Qnil;
1852           if (part) *part = 0; /*scroll_bar_handle; */
1854           if (x) XSETINT (*x, lrint (position.x));
1855           if (y) XSETINT (*y, lrint (position.y));
1856           if (time) *time = last_mouse_movement_time;
1857           *fp = f;
1858         }
1859     }
1861   UNBLOCK_INPUT;
1865 static void
1866 ns_frame_up_to_date (struct frame *f)
1867 /* --------------------------------------------------------------------------
1868     External (hook): Fix up mouse highlighting right after a full update.
1869     Some highlighting was deferred if GC was happening during
1870     note_mouse_highlight (), while other highlighting was deferred for update.
1871    -------------------------------------------------------------------------- */
1873   NSTRACE (ns_frame_up_to_date);
1875   if (FRAME_NS_P (f))
1876     {
1877       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1878       if ((hlinfo->mouse_face_deferred_gc || f ==hlinfo->mouse_face_mouse_frame)
1879       /*&& hlinfo->mouse_face_mouse_frame*/)
1880         {
1881           BLOCK_INPUT;
1882           ns_update_begin(f);
1883           if (hlinfo->mouse_face_mouse_frame)
1884             note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1885                                   hlinfo->mouse_face_mouse_x,
1886                                   hlinfo->mouse_face_mouse_y);
1887           hlinfo->mouse_face_deferred_gc = 0;
1888           ns_update_end(f);
1889           UNBLOCK_INPUT;
1890         }
1891     }
1895 void
1896 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1897 /* --------------------------------------------------------------------------
1898     External (RIF): set frame mouse pointer type.
1899    -------------------------------------------------------------------------- */
1901   NSTRACE (ns_define_frame_cursor);
1902   if (FRAME_POINTER_TYPE (f) != cursor)
1903     {
1904       EmacsView *view = FRAME_NS_VIEW (f);
1905       FRAME_POINTER_TYPE (f) = cursor;
1906       [[view window] invalidateCursorRectsForView: view];
1907       /* Redisplay assumes this function also draws the changed frame
1908          cursor, but this function doesn't, so do it explicitly.  */
1909       x_update_cursor (f, 1);
1910     }
1915 /* ==========================================================================
1917     Keyboard handling
1919    ========================================================================== */
1922 static unsigned
1923 ns_convert_key (unsigned code)
1924 /* --------------------------------------------------------------------------
1925     Internal call used by NSView-keyDown.
1926    -------------------------------------------------------------------------- */
1928   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1929                                 / sizeof (convert_ns_to_X_keysym[0]));
1930   unsigned keysym;
1931   /* An array would be faster, but less easy to read. */
1932   for (keysym = 0; keysym < last_keysym; keysym += 2)
1933     if (code == convert_ns_to_X_keysym[keysym])
1934       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1935   return 0;
1936 /* if decide to use keyCode and Carbon table, use this line:
1937      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1941 char *
1942 x_get_keysym_name (int keysym)
1943 /* --------------------------------------------------------------------------
1944     Called by keyboard.c.  Not sure if the return val is important, except
1945     that it be unique.
1946    -------------------------------------------------------------------------- */
1948   static char value[16];
1949   NSTRACE (x_get_keysym_name);
1950   sprintf (value, "%d", keysym);
1951   return value;
1956 /* ==========================================================================
1958     Block drawing operations
1960    ========================================================================== */
1963 static void
1964 ns_redraw_scroll_bars (struct frame *f)
1966   int i;
1967   id view;
1968   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1969   NSTRACE (ns_judge_scroll_bars);
1970   for (i =[subviews count]-1; i >= 0; i--)
1971     {
1972       view = [subviews objectAtIndex: i];
1973       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1974       [view display];
1975     }
1979 void
1980 ns_clear_frame (struct frame *f)
1981 /* --------------------------------------------------------------------------
1982       External (hook): Erase the entire frame
1983    -------------------------------------------------------------------------- */
1985   NSView *view = FRAME_NS_VIEW (f);
1986   NSRect r;
1988   NSTRACE (ns_clear_frame);
1989   if (ns_in_resize)
1990     return;
1992  /* comes on initial frame because we have
1993     after-make-frame-functions = select-frame */
1994  if (!FRAME_DEFAULT_FACE (f))
1995    return;
1997   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1999   output_cursor.hpos = output_cursor.vpos = 0;
2000   output_cursor.x = -1;
2002   r = [view bounds];
2004   BLOCK_INPUT;
2005   ns_focus (f, &r, 1);
2006   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2007   NSRectFill (r);
2008   ns_unfocus (f);
2010 #ifdef NS_IMPL_COCOA
2011   [[view window] display];  /* redraw resize handle */
2012 #endif
2014   /* as of 2006/11 or so this is now needed */
2015   ns_redraw_scroll_bars (f);
2016   UNBLOCK_INPUT;
2020 void
2021 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2022 /* --------------------------------------------------------------------------
2023     External (RIF):  Clear section of frame
2024    -------------------------------------------------------------------------- */
2026   NSRect r = NSMakeRect (x, y, width, height);
2027   NSView *view = FRAME_NS_VIEW (f);
2028   struct face *face = FRAME_DEFAULT_FACE (f);
2030   if (!view || !face)
2031     return;
2033   NSTRACE (ns_clear_frame_area);
2035   r = NSIntersectionRect (r, [view frame]);
2036   ns_focus (f, &r, 1);
2037   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2039 #ifdef NS_IMPL_COCOA
2040   {
2041     /* clip out the resize handle */
2042     NSWindow *window = [FRAME_NS_VIEW (f) window];
2043     NSRect ir
2044       = [view convertRect: ns_resize_handle_rect (window) fromView: nil];
2046     ir = NSIntersectionRect (r, ir);
2047     if (NSIsEmptyRect (ir))
2048       {
2049 #endif
2051   NSRectFill (r);
2053 #ifdef NS_IMPL_COCOA
2054       }
2055     else
2056       {
2057         NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
2058         r1.size.height -= ir.size.height;
2059         r2.origin.y += r1.size.height;
2060         r2.size.width -= ir.size.width;
2061         r2.size.height = ir.size.height;
2062         NSRectFill (r1);
2063         NSRectFill (r2);
2064       }
2065   }
2066 #endif
2068   ns_unfocus (f);
2069   return;
2073 static void
2074 ns_scroll_run (struct window *w, struct run *run)
2075 /* --------------------------------------------------------------------------
2076     External (RIF):  Insert or delete n lines at line vpos
2077    -------------------------------------------------------------------------- */
2079   struct frame *f = XFRAME (w->frame);
2080   int x, y, width, height, from_y, to_y, bottom_y;
2082   NSTRACE (ns_scroll_run);
2084   /* begin copy from other terms */
2085   /* Get frame-relative bounding box of the text display area of W,
2086      without mode lines.  Include in this box the left and right
2087      fringe of W.  */
2088   window_box (w, -1, &x, &y, &width, &height);
2090   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2091   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2092   bottom_y = y + height;
2094   if (to_y < from_y)
2095     {
2096       /* Scrolling up.  Make sure we don't copy part of the mode
2097          line at the bottom.  */
2098       if (from_y + run->height > bottom_y)
2099         height = bottom_y - from_y;
2100       else
2101         height = run->height;
2102     }
2103   else
2104     {
2105       /* Scrolling down.  Make sure we don't copy over the mode line.
2106          at the bottom.  */
2107       if (to_y + run->height > bottom_y)
2108         height = bottom_y - to_y;
2109       else
2110         height = run->height;
2111     }
2112   /* end copy from other terms */
2114   if (height == 0)
2115       return;
2117   BLOCK_INPUT;
2119   updated_window = w;
2120   x_clear_cursor (w);
2122   {
2123     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2124     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2125     NSPoint dstOrigin = NSMakePoint (x, to_y);
2127     ns_focus (f, &dstRect, 1);
2128     NSCopyBits (0, srcRect , dstOrigin);
2129     ns_unfocus (f);
2130   }
2132   UNBLOCK_INPUT;
2136 static void
2137 ns_after_update_window_line (struct glyph_row *desired_row)
2138 /* --------------------------------------------------------------------------
2139     External (RIF): preparatory to fringe update after text was updated
2140    -------------------------------------------------------------------------- */
2142   struct window *w = updated_window;
2143   struct frame *f;
2144   int width, height;
2146   NSTRACE (ns_after_update_window_line);
2148   /* begin copy from other terms */
2149   xassert (w);
2151   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2152     desired_row->redraw_fringe_bitmaps_p = 1;
2154   /* When a window has disappeared, make sure that no rest of
2155      full-width rows stays visible in the internal border.
2156      Under NS this is drawn inside the fringes. */
2157   if (windows_or_buffers_changed
2158       && (f = XFRAME (w->frame),
2159           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2160           width != 0)
2161       && (height = desired_row->visible_height,
2162           height > 0))
2163     {
2164       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2166       /* Internal border is drawn below the tool bar.  */
2167       if (WINDOWP (f->tool_bar_window)
2168           && w == XWINDOW (f->tool_bar_window))
2169         y -= width;
2170       /* end copy from other terms */
2172       BLOCK_INPUT;
2173       if (!desired_row->full_width_p)
2174         {
2175           int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2176             + WINDOW_LEFT_FRINGE_WIDTH (w);
2177           int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2178             + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
2179             - WINDOW_RIGHT_FRINGE_WIDTH (w)
2180             - FRAME_INTERNAL_BORDER_WIDTH (f);
2181           ns_clear_frame_area (f, x1, y, width, height);
2182           ns_clear_frame_area (f, x2, y, width, height);
2183         }
2184       UNBLOCK_INPUT;
2185     }
2189 static void
2190 ns_shift_glyphs_for_insert (struct frame *f,
2191                            int x, int y, int width, int height,
2192                            int shift_by)
2193 /* --------------------------------------------------------------------------
2194     External (RIF): copy an area horizontally, don't worry about clearing src
2195    -------------------------------------------------------------------------- */
2197   NSRect srcRect = NSMakeRect (x, y, width, height);
2198   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2199   NSPoint dstOrigin = dstRect.origin;
2201   NSTRACE (ns_shift_glyphs_for_insert);
2203   ns_focus (f, &dstRect, 1);
2204   NSCopyBits (0, srcRect, dstOrigin);
2205   ns_unfocus (f);
2210 /* ==========================================================================
2212     Character encoding and metrics
2214    ========================================================================== */
2217 static inline void
2218 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2219 /* --------------------------------------------------------------------------
2220      External (RIF); compute left/right overhang of whole string and set in s
2221    -------------------------------------------------------------------------- */
2223   struct face *face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2224   struct font *font = s->font; /*face->font; */
2226   if (s->char2b)
2227     {
2228       struct font_metrics metrics;
2229       unsigned int codes[2];
2230       codes[0] = *(s->char2b);
2231       codes[1] = *(s->char2b + s->nchars - 1);
2233       font->driver->text_extents (font, codes, 2, &metrics);
2234       s->left_overhang = -metrics.lbearing;
2235       s->right_overhang
2236         = metrics.rbearing > metrics.width
2237         ? metrics.rbearing - metrics.width : 0;
2238     }
2239   else
2240     {
2241       s->left_overhang = 0;
2242       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2243         FONT_HEIGHT (font) * 0.2 : 0;
2244     }
2249 /* ==========================================================================
2251     Fringe and cursor drawing
2253    ========================================================================== */
2256 extern int max_used_fringe_bitmap;
2257 static void
2258 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2259                       struct draw_fringe_bitmap_params *p)
2260 /* --------------------------------------------------------------------------
2261     External (RIF); fringe-related
2262    -------------------------------------------------------------------------- */
2264   struct frame *f = XFRAME (WINDOW_FRAME (w));
2265   struct face *face = p->face;
2266   int rowY;
2267   static EmacsImage **bimgs = NULL;
2268   static int nBimgs = 0;
2269   /* NS-specific: move internal border inside fringe */
2270   int x = p->bx < 0 ? p->x : p->bx;
2271   int wd = p->bx < 0 ? p->wd : p->nx;
2272   BOOL fringeOnVeryLeft
2273     = x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
2274       - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
2275   BOOL fringeOnVeryRight
2276     = FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
2277       - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
2278   int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
2279     (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
2281   /* grow bimgs if needed */
2282   if (nBimgs < max_used_fringe_bitmap)
2283     {
2284       EmacsImage **newBimgs
2285         = xmalloc (max_used_fringe_bitmap * sizeof (EmacsImage *));
2286       memset (newBimgs, 0, max_used_fringe_bitmap * sizeof (EmacsImage *));
2288       if (nBimgs)
2289         {
2290           memcpy (newBimgs, bimgs, nBimgs * sizeof (EmacsImage *));
2291           xfree (bimgs);
2292         }
2294       bimgs = newBimgs;
2295       nBimgs = max_used_fringe_bitmap;
2296     }
2298   /* Must clip because of partially visible lines.  */
2299   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2300   ns_clip_to_row (w, row, -1, YES);
2302   if (p->bx >= 0 && !p->overlay_p)
2303     {
2304       int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
2305         -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2306       int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
2307         FRAME_INTERNAL_BORDER_WIDTH (f) : 0
2308         + (yAdjust ? FRAME_INTERNAL_BORDER_WIDTH (f) : 0);
2309       NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
2310       NSRectClip (r);
2311       [ns_lookup_indexed_color(face->background, f) set];
2312       NSRectFill (r);
2313     }
2315   if (p->which)
2316     {
2317       NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
2318       NSPoint pt = r.origin;
2319       EmacsImage *img = bimgs[p->which - 1];
2321       if (!img)
2322         {
2323           unsigned short *bits = p->bits + p->dh;
2324           int len = p->h;
2325           int i;
2326           unsigned char *cbits = xmalloc (len);
2328           for (i =0; i<len; i++)
2329             cbits[i] = ~(bits[i] & 0xff);
2330           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2331                                            flip: NO];
2332           bimgs[p->which - 1] = img;
2333           xfree (cbits);
2334         }
2336       NSRectClip (r);
2337       /* Since we composite the bitmap instead of just blitting it, we need
2338          to erase the whole background. */
2339       [ns_lookup_indexed_color(face->background, f) set];
2340       NSRectFill (r);
2341       pt.y += p->h;
2342       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2343       [img compositeToPoint: pt operation: NSCompositeSourceOver];
2344     }
2345   ns_unfocus (f);
2349 void
2350 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2351                        int x, int y, int cursor_type, int cursor_width,
2352                        int on_p, int active_p)
2353 /* --------------------------------------------------------------------------
2354      External call (RIF): draw cursor.
2355      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2356    -------------------------------------------------------------------------- */
2358   NSRect r, s;
2359   int fx, fy, h, cursor_height;
2360   struct frame *f = WINDOW_XFRAME (w);
2361   struct glyph *phys_cursor_glyph;
2362   int overspill;
2363   struct glyph *cursor_glyph;
2364   struct face *face;
2365   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2367   /* If cursor is out of bounds, don't draw garbage.  This can happen
2368      in mini-buffer windows when switching between echo area glyphs
2369      and mini-buffer.  */
2371   NSTRACE (dumpcursor);
2373   if (!on_p)
2374     return;
2376   w->phys_cursor_type = cursor_type;
2377   w->phys_cursor_on_p = on_p;
2379   if (cursor_type == NO_CURSOR)
2380     {
2381       w->phys_cursor_width = 0;
2382       return;
2383     }
2385   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2386     {
2387       if (glyph_row->exact_window_width_line_p
2388           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2389         {
2390           glyph_row->cursor_in_fringe_p = 1;
2391           draw_fringe_bitmap (w, glyph_row, 0);
2392         }
2393       return;
2394     }
2396   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2397      (other terminals do it the other way round).  We must set
2398      w->phys_cursor_width to the cursor width.  For bar cursors, that
2399      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2400   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2402   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2403      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2404   if (cursor_type == BAR_CURSOR)
2405     {
2406       if (cursor_width < 1)
2407         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2408       w->phys_cursor_width = cursor_width;
2409     }
2410   /* If we have an HBAR, "cursor_width" MAY specify height. */
2411   else if (cursor_type == HBAR_CURSOR)
2412     {
2413       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2414       fy += h - cursor_height;
2415       h = cursor_height;
2416     }
2418   r.origin.x = fx, r.origin.y = fy;
2419   r.size.height = h;
2420   r.size.width = w->phys_cursor_width;
2422   /* FIXME: if we overwrite the internal border area, it does not get erased;
2423      fix by truncating cursor, but better would be to erase properly */
2424   overspill = r.origin.x + r.size.width -
2425     WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w)
2426       - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
2427   if (overspill > 0)
2428     r.size.width -= overspill;
2430   /* TODO: only needed in rare cases with last-resort font in HELLO..
2431      should we do this more efficiently? */
2432   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2435   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2436   if (face && NS_FACE_BACKGROUND (face)
2437       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2438     {
2439       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2440       hollow_color = FRAME_CURSOR_COLOR (f);
2441     }
2442   else
2443     [FRAME_CURSOR_COLOR (f) set];
2445 #ifdef NS_IMPL_COCOA
2446   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2447            atomic.  Cleaner ways of doing this should be investigated.
2448            One way would be to set a global variable DRAWING_CURSOR
2449            when making the call to draw_phys..(), don't focus in that
2450            case, then move the ns_unfocus() here after that call. */
2451   NSDisableScreenUpdates ();
2452 #endif
2454   switch (cursor_type)
2455     {
2456     case NO_CURSOR:
2457       break;
2458     case FILLED_BOX_CURSOR:
2459       NSRectFill (r);
2460       break;
2461     case HOLLOW_BOX_CURSOR:
2462       NSRectFill (r);
2463       [hollow_color set];
2464       NSRectFill (NSInsetRect (r, 1, 1));
2465       [FRAME_CURSOR_COLOR (f) set];
2466       break;
2467     case HBAR_CURSOR:
2468       NSRectFill (r);
2469       break;
2470     case BAR_CURSOR:
2471       s = r;
2472       /* If the character under cursor is R2L, draw the bar cursor
2473          on the right of its glyph, rather than on the left.  */
2474       cursor_glyph = get_phys_cursor_glyph (w);
2475       if ((cursor_glyph->resolved_level & 1) != 0)
2476         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2478       NSRectFill (s);
2479       break;
2480     }
2481   ns_unfocus (f);
2483   /* draw the character under the cursor */
2484   if (cursor_type != NO_CURSOR)
2485     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2487 #ifdef NS_IMPL_COCOA
2488   NSEnableScreenUpdates ();
2489 #endif
2494 static void
2495 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2496 /* --------------------------------------------------------------------------
2497      External (RIF): Draw a vertical line.
2498    -------------------------------------------------------------------------- */
2500   struct frame *f = XFRAME (WINDOW_FRAME (w));
2501   struct face *face;
2502   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2504   NSTRACE (ns_draw_vertical_window_border);
2506   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2507   if (face)
2508       [ns_lookup_indexed_color(face->foreground, f) set];
2510   ns_focus (f, &r, 1);
2511   NSRectFill(r);
2512   ns_unfocus (f);
2516 void
2517 show_hourglass (struct atimer *timer)
2519   if (hourglass_shown_p)
2520     return;
2522   BLOCK_INPUT;
2524   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2526   hourglass_shown_p = 1;
2527   UNBLOCK_INPUT;
2531 void
2532 hide_hourglass (void)
2534   if (!hourglass_shown_p)
2535     return;
2537   BLOCK_INPUT;
2539   /* TODO: remove NSProgressIndicator from all frames */
2541   hourglass_shown_p = 0;
2542   UNBLOCK_INPUT;
2547 /* ==========================================================================
2549     Glyph drawing operations
2551    ========================================================================== */
2554 static inline NSRect
2555 ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
2556 /* --------------------------------------------------------------------------
2557     Under NS we draw internal borders inside fringes, and want full-width
2558     rendering to go all the way to edge.  This function makes that correction.
2559    -------------------------------------------------------------------------- */
2561   if (r.origin.y <= fibw+1)
2562     {
2563       r.size.height += r.origin.y;
2564       r.origin.y = 0;
2565     }
2566   if (r.origin.x <= fibw+1)
2567     {
2568       r.size.width += r.origin.x;
2569       r.origin.x = 0;
2570     }
2571   if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
2572     r.size.width += fibw;
2574   return r;
2578 static int
2579 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2580 /* --------------------------------------------------------------------------
2581     Wrapper utility to account for internal border width on full-width lines,
2582     and allow top full-width rows to hit the frame top.  nr should be pointer
2583     to two successive NSRects.  Number of rects actually used is returned.
2584    -------------------------------------------------------------------------- */
2586   int n = get_glyph_string_clip_rects (s, nr, 2);
2587   if (s->row->full_width_p)
2588     {
2589       *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2590                             FRAME_PIXEL_WIDTH (s->f));
2591       if (n == 2)
2592         *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
2593                               FRAME_PIXEL_WIDTH (s->f));
2594     }
2595   return n;
2598 /* --------------------------------------------------------------------
2599    Draw a wavy line under glyph string s. The wave fills wave_height
2600    pixels from y.
2602                     x          wave_length = 3
2603                                  --
2604                 y    *   *   *   *   *
2605                      |* * * * * * * * *
2606     wave_height = 3  | *   *   *   *
2607   --------------------------------------------------------------------- */
2609 static void
2610 ns_draw_underwave (struct glyph_string *s, CGFloat width, CGFloat x)
2612   int wave_height = 3, wave_length = 3;
2613   int y, dx, dy, odd, xmax;
2614   NSPoint a, b;
2615   NSRect waveClip;
2617   dx = wave_length;
2618   dy = wave_height - 1;
2619   y =  s->ybase + 1;
2620   xmax = x + width;
2622   /* Find and set clipping rectangle */
2623   waveClip = NSMakeRect (x, y, width, wave_height);
2624   [[NSGraphicsContext currentContext] saveGraphicsState];
2625   NSRectClip (waveClip);
2627   /* Draw the waves */
2628   a.x = x - ((int)(x) % dx);
2629   b.x = a.x + dx;
2630   odd = (int)(a.x/dx) % 2;
2631   a.y = b.y = y;
2633   if (odd)
2634     a.y += dy;
2635   else
2636     b.y += dy;
2638   while (a.x <= xmax)
2639     {
2640       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2641       a.x = b.x, a.y = b.y;
2642       b.x += dx, b.y = y + odd*dy;
2643       odd = !odd;
2644     }
2646   /* Restore previous clipping rectangle(s) */
2647   [[NSGraphicsContext currentContext] restoreGraphicsState];
2652 void
2653 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2654                          NSColor *defaultCol, CGFloat width, CGFloat x)
2655 /* --------------------------------------------------------------------------
2656    Draw underline, overline, and strike-through on glyph string s.
2657    -------------------------------------------------------------------------- */
2659   if (s->for_overlaps)
2660     return;
2662   /* Do underline. */
2663   if (face->underline_p)
2664     {
2665       if (s->face->underline_type == FACE_UNDER_WAVE)
2666         {
2667           if (face->underline_defaulted_p)
2668             [defaultCol set];
2669           else
2670             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2672           ns_draw_underwave (s, width, x);
2673         }
2674       else if (s->face->underline_type == FACE_UNDER_LINE)
2675         {
2677           NSRect r;
2678           unsigned long thickness, position;
2680           /* If the prev was underlined, match its appearance. */
2681           if (s->prev && s->prev->face->underline_p
2682               && s->prev->underline_thickness > 0)
2683             {
2684               thickness = s->prev->underline_thickness;
2685               position = s->prev->underline_position;
2686             }
2687           else
2688             {
2689               struct font *font;
2690               unsigned long descent;
2692               font=s->font;
2693               descent = s->y + s->height - s->ybase;
2695               /* Use underline thickness of font, defaulting to 1. */
2696               thickness = (font && font->underline_thickness > 0)
2697                 ? font->underline_thickness : 1;
2699               /* Determine the offset of underlining from the baseline. */
2700               if (x_underline_at_descent_line)
2701                 position = descent - thickness;
2702               else if (x_use_underline_position_properties
2703                        && font && font->underline_position >= 0)
2704                 position = font->underline_position;
2705               else if (font)
2706                 position = lround (font->descent / 2);
2707               else
2708                 position = underline_minimum_offset;
2710               position = max (position, underline_minimum_offset);
2712               /* Ensure underlining is not cropped. */
2713               if (descent <= position)
2714                 {
2715                   position = descent - 1;
2716                   thickness = 1;
2717                 }
2718               else if (descent < position + thickness)
2719                 thickness = 1;
2720             }
2722           s->underline_thickness = thickness;
2723           s->underline_position = position;
2725           r = NSMakeRect (x, s->ybase + position, width, thickness);
2727           if (face->underline_defaulted_p)
2728             [defaultCol set];
2729           else
2730             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2731           NSRectFill (r);
2732         }
2733     }
2734   /* Do overline. We follow other terms in using a thickness of 1
2735      and ignoring overline_margin. */
2736   if (face->overline_p)
2737     {
2738       NSRect r;
2739       r = NSMakeRect (x, s->y, width, 1);
2741       if (face->overline_color_defaulted_p)
2742         [defaultCol set];
2743       else
2744         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2745       NSRectFill (r);
2746     }
2748   /* Do strike-through.  We follow other terms for thickness and
2749      vertical position.*/
2750   if (face->strike_through_p)
2751     {
2752       NSRect r;
2753       unsigned long dy;
2755       dy = lrint ((s->height - 1) / 2);
2756       r = NSMakeRect (x, s->y + dy, width, 1);
2758       if (face->strike_through_color_defaulted_p)
2759         [defaultCol set];
2760       else
2761         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2762       NSRectFill (r);
2763     }
2766 static void
2767 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2768 /* --------------------------------------------------------------------------
2769     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2770     Note we can't just use an NSDrawRect command, because of the possibility
2771     of some sides not being drawn, and because the rect will be filled.
2772    -------------------------------------------------------------------------- */
2774   NSRect s = r;
2775   [col set];
2777   /* top, bottom */
2778   s.size.height = thickness;
2779   NSRectFill (s);
2780   s.origin.y += r.size.height - thickness;
2781   NSRectFill (s);
2783   s.size.height = r.size.height;
2784   s.origin.y = r.origin.y;
2786   /* left, right (optional) */
2787   s.size.width = thickness;
2788   if (left_p)
2789     NSRectFill (s);
2790   if (right_p)
2791     {
2792       s.origin.x += r.size.width - thickness;
2793       NSRectFill (s);
2794     }
2798 static void
2799 ns_draw_relief (NSRect r, int thickness, char raised_p,
2800                char top_p, char bottom_p, char left_p, char right_p,
2801                struct glyph_string *s)
2802 /* --------------------------------------------------------------------------
2803     Draw a relief rect inside r, optionally leaving some sides open.
2804     Note we can't just use an NSDrawBezel command, because of the possibility
2805     of some sides not being drawn, and because the rect will be filled.
2806    -------------------------------------------------------------------------- */
2808   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2809   NSColor *newBaseCol = nil;
2810   NSRect sr = r;
2812   NSTRACE (ns_draw_relief);
2814   /* set up colors */
2816   if (s->face->use_box_color_for_shadows_p)
2817     {
2818       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2819     }
2820 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2821            && s->img->pixmap
2822            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2823        {
2824          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2825        } */
2826   else
2827     {
2828       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2829     }
2831   if (newBaseCol == nil)
2832     newBaseCol = [NSColor grayColor];
2834   if (newBaseCol != baseCol)  /* TODO: better check */
2835     {
2836       [baseCol release];
2837       baseCol = [newBaseCol retain];
2838       [lightCol release];
2839       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2840       [darkCol release];
2841       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2842     }
2844   [(raised_p ? lightCol : darkCol) set];
2846   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2848   /* top */
2849   sr.size.height = thickness;
2850   if (top_p) NSRectFill (sr);
2852   /* left */
2853   sr.size.height = r.size.height;
2854   sr.size.width = thickness;
2855   if (left_p) NSRectFill (sr);
2857   [(raised_p ? darkCol : lightCol) set];
2859   /* bottom */
2860   sr.size.width = r.size.width;
2861   sr.size.height = thickness;
2862   sr.origin.y += r.size.height - thickness;
2863   if (bottom_p) NSRectFill (sr);
2865   /* right */
2866   sr.size.height = r.size.height;
2867   sr.origin.y = r.origin.y;
2868   sr.size.width = thickness;
2869   sr.origin.x += r.size.width - thickness;
2870   if (right_p) NSRectFill (sr);
2874 static void
2875 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2876 /* --------------------------------------------------------------------------
2877       Function modeled after x_draw_glyph_string_box ().
2878       Sets up parameters for drawing.
2879    -------------------------------------------------------------------------- */
2881   int right_x, last_x;
2882   char left_p, right_p;
2883   struct glyph *last_glyph;
2884   NSRect r;
2885   int thickness;
2886   struct face *face;
2888   if (s->hl == DRAW_MOUSE_FACE)
2889     {
2890       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2891       if (!face)
2892         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2893     }
2894   else
2895     face = s->face;
2897   thickness = face->box_line_width;
2899   NSTRACE (ns_dumpglyphs_box_or_relief);
2901   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2902             ? WINDOW_RIGHT_EDGE_X (s->w)
2903             : window_box_right (s->w, s->area));
2904   last_glyph = (s->cmp || s->img
2905                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2907   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2908               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2910   left_p = (s->first_glyph->left_box_line_p
2911             || (s->hl == DRAW_MOUSE_FACE
2912                 && (s->prev == NULL || s->prev->hl != s->hl)));
2913   right_p = (last_glyph->right_box_line_p
2914              || (s->hl == DRAW_MOUSE_FACE
2915                  && (s->next == NULL || s->next->hl != s->hl)));
2917   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2919   /* expand full-width row over internal borders */
2920   if (s->row->full_width_p)
2921     r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2922                         FRAME_PIXEL_WIDTH (s->f));
2924   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2925   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2926     {
2927       ns_draw_box (r, abs (thickness),
2928                    ns_lookup_indexed_color (face->box_color, s->f),
2929                   left_p, right_p);
2930     }
2931   else
2932     {
2933       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2934                      1, 1, left_p, right_p, s);
2935     }
2939 static void
2940 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2941 /* --------------------------------------------------------------------------
2942       Modeled after x_draw_glyph_string_background, which draws BG in
2943       certain cases.  Others are left to the text rendering routine.
2944    -------------------------------------------------------------------------- */
2946   NSTRACE (ns_maybe_dumpglyphs_background);
2948   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2949     {
2950       int box_line_width = max (s->face->box_line_width, 0);
2951       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2952           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2953         {
2954           struct face *face;
2955           if (s->hl == DRAW_MOUSE_FACE)
2956             {
2957               face = FACE_FROM_ID (s->f,
2958                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2959               if (!face)
2960                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2961             }
2962           else
2963             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2964           if (!face->stipple)
2965             [(NS_FACE_BACKGROUND (face) != 0
2966               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2967               : FRAME_BACKGROUND_COLOR (s->f)) set];
2968           else
2969             {
2970               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2971               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2972             }
2974           if (s->hl != DRAW_CURSOR)
2975             {
2976               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2977                                     s->background_width,
2978                                     s->height-2*box_line_width);
2980               /* expand full-width row over internal borders */
2981               if (s->row->full_width_p)
2982                 {
2983                   int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2984                   if (r.origin.y <= fibw+1 + box_line_width)
2985                     {
2986                       r.size.height += r.origin.y;
2987                       r.origin.y = 0;
2988                     }
2989                   if (r.origin.x <= fibw+1)
2990                     {
2991                       r.size.width += 2*r.origin.x;
2992                       r.origin.x = 0;
2993                     }
2994                   if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2995                       <= fibw+1)
2996                     r.size.width += fibw;
2997                 }
2999               NSRectFill (r);
3000             }
3002           s->background_filled_p = 1;
3003         }
3004     }
3008 static void
3009 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3010 /* --------------------------------------------------------------------------
3011       Renders an image and associated borders.
3012    -------------------------------------------------------------------------- */
3014   EmacsImage *img = s->img->pixmap;
3015   int box_line_vwidth = max (s->face->box_line_width, 0);
3016   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3017   int bg_x, bg_y, bg_height;
3018   int th;
3019   char raised_p;
3020   NSRect br;
3021   struct face *face;
3022   NSColor *tdCol;
3024   NSTRACE (ns_dumpglyphs_image);
3026   if (s->face->box != FACE_NO_BOX
3027       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3028     x += abs (s->face->box_line_width);
3030   bg_x = x;
3031   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3032   bg_height = s->height;
3033   /* other terms have this, but was causing problems w/tabbar mode */
3034   /* - 2 * box_line_vwidth; */
3036   if (s->slice.x == 0) x += s->img->hmargin;
3037   if (s->slice.y == 0) y += s->img->vmargin;
3039   /* Draw BG: if we need larger area than image itself cleared, do that,
3040      otherwise, since we composite the image under NS (instead of mucking
3041      with its background color), we must clear just the image area. */
3042   if (s->hl == DRAW_MOUSE_FACE)
3043     {
3044       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3045       if (!face)
3046        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3047     }
3048   else
3049     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3051   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3053   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3054       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3055     {
3056       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3057       s->background_filled_p = 1;
3058     }
3059   else
3060     {
3061       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3062     }
3064   /* expand full-width row over internal borders */
3065   if (s->row->full_width_p)
3066     {
3067       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
3068       if (br.origin.y <= fibw+1 + box_line_vwidth)
3069         {
3070           br.size.height += br.origin.y;
3071           br.origin.y = 0;
3072         }
3073       if (br.origin.x <= fibw+1 + box_line_vwidth)
3074         {
3075           br.size.width += br.origin.x;
3076           br.origin.x = 0;
3077         }
3078       if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
3079         br.size.width += fibw;
3080     }
3082   NSRectFill (br);
3084   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3085   if (img != nil)
3086     [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3087                 operation: NSCompositeSourceOver];
3089   if (s->hl == DRAW_CURSOR)
3090     {
3091     [FRAME_CURSOR_COLOR (s->f) set];
3092     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3093       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3094     else
3095       /* Currently on NS img->mask is always 0. Since
3096          get_window_cursor_type specifies a hollow box cursor when on
3097          a non-masked image we never reach this clause. But we put it
3098          in in anticipation of better support for image masks on
3099          NS. */
3100       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3101     }
3102   else
3103     {
3104       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3105     }
3107   /* Draw underline, overline, strike-through. */
3108   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3110   /* Draw relief, if requested */
3111   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3112     {
3113       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3114         {
3115           th = tool_bar_button_relief >= 0 ?
3116             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3117           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3118         }
3119       else
3120         {
3121           th = abs (s->img->relief);
3122           raised_p = (s->img->relief > 0);
3123         }
3125       r.origin.x = x - th;
3126       r.origin.y = y - th;
3127       r.size.width = s->slice.width + 2*th-1;
3128       r.size.height = s->slice.height + 2*th-1;
3129       ns_draw_relief (r, th, raised_p,
3130                       s->slice.y == 0,
3131                       s->slice.y + s->slice.height == s->img->height,
3132                       s->slice.x == 0,
3133                       s->slice.x + s->slice.width == s->img->width, s);
3134     }
3136   /* If there is no mask, the background won't be seen,
3137      so draw a rectangle on the image for the cursor.
3138      Do this for all images, getting transparency right is not reliable.  */
3139   if (s->hl == DRAW_CURSOR)
3140     {
3141       int thickness = abs (s->img->relief);
3142       if (thickness == 0) thickness = 1;
3143       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3144     }
3148 static void
3149 ns_dumpglyphs_stretch (struct glyph_string *s)
3151   NSRect r[2];
3152   int n, i;
3153   struct face *face;
3154   NSColor *fgCol, *bgCol;
3156   if (!s->background_filled_p)
3157     {
3158       n = ns_get_glyph_string_clip_rect (s, r);
3159       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3161       ns_focus (s->f, r, n);
3163       if (s->hl == DRAW_MOUSE_FACE)
3164        {
3165          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3166          if (!face)
3167            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3168        }
3169       else
3170        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3172       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3173       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3175       for (i=0; i<n; i++)
3176         {
3177           if (!s->row->full_width_p)
3178             {
3179               int overrun, leftoverrun;
3181               /* truncate to avoid overwriting fringe and/or scrollbar */
3182               overrun = max (0, (s->x + s->background_width)
3183                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3184                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3185               r[i].size.width -= overrun;
3187               /* truncate to avoid overwriting to left of the window box */
3188               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3189                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3191               if (leftoverrun > 0)
3192                 {
3193                   r[i].origin.x += leftoverrun;
3194                   r[i].size.width -= leftoverrun;
3195                 }
3197               /* XXX: Try to work between problem where a stretch glyph on
3198                  a partially-visible bottom row will clear part of the
3199                  modeline, and another where list-buffers headers and similar
3200                  rows erroneously have visible_height set to 0.  Not sure
3201                  where this is coming from as other terms seem not to show. */
3202               r[i].size.height = min (s->height, s->row->visible_height);
3203             }
3205           /* expand full-width rows over internal borders */
3206           else
3207             {
3208               r[i] = ns_fix_rect_ibw (r[i], FRAME_INTERNAL_BORDER_WIDTH (s->f),
3209                                       FRAME_PIXEL_WIDTH (s->f));
3210             }
3212           [bgCol set];
3214           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3215              overwriting cursor (usually when cursor on a tab) */
3216           if (s->hl == DRAW_CURSOR)
3217             {
3218               CGFloat x, width;
3220               x = r[i].origin.x;
3221               width = s->w->phys_cursor_width;
3222               r[i].size.width -= width;
3223               r[i].origin.x += width;
3225               NSRectFill (r[i]);
3227               /* Draw overlining, etc. on the cursor. */
3228               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3229                 ns_draw_text_decoration (s, face, bgCol, width, x);
3230               else
3231                 ns_draw_text_decoration (s, face, fgCol, width, x);
3232             }
3233           else
3234             {
3235               NSRectFill (r[i]);
3236             }
3238           /* Draw overlining, etc. on the stretch glyph (or the part
3239              of the stretch glyph after the cursor). */
3240           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3241                                    r[i].origin.x);
3242         }
3243       ns_unfocus (s->f);
3244       s->background_filled_p = 1;
3245     }
3249 static void
3250 ns_draw_glyph_string (struct glyph_string *s)
3251 /* --------------------------------------------------------------------------
3252       External (RIF): Main draw-text call.
3253    -------------------------------------------------------------------------- */
3255   /* TODO (optimize): focus for box and contents draw */
3256   NSRect r[2];
3257   int n;
3258   char box_drawn_p = 0;
3260   NSTRACE (ns_draw_glyph_string);
3262   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3263     {
3264       int width;
3265       struct glyph_string *next;
3267       for (width = 0, next = s->next;
3268            next && width < s->right_overhang;
3269            width += next->width, next = next->next)
3270         if (next->first_glyph->type != IMAGE_GLYPH)
3271           {
3272             if (next->first_glyph->type != STRETCH_GLYPH)
3273               {
3274                 n = ns_get_glyph_string_clip_rect (s->next, r);
3275                 ns_focus (s->f, r, n);
3276                 ns_maybe_dumpglyphs_background (s->next, 1);
3277                 ns_unfocus (s->f);
3278               }
3279             else
3280               {
3281                 ns_dumpglyphs_stretch (s->next);
3282               }
3283             next->num_clips = 0;
3284           }
3285     }
3287   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3288         && (s->first_glyph->type == CHAR_GLYPH
3289             || s->first_glyph->type == COMPOSITE_GLYPH))
3290     {
3291       n = ns_get_glyph_string_clip_rect (s, r);
3292       ns_focus (s->f, r, n);
3293       ns_maybe_dumpglyphs_background (s, 1);
3294       ns_dumpglyphs_box_or_relief (s);
3295       ns_unfocus (s->f);
3296       box_drawn_p = 1;
3297     }
3299   switch (s->first_glyph->type)
3300     {
3302     case IMAGE_GLYPH:
3303       n = ns_get_glyph_string_clip_rect (s, r);
3304       ns_focus (s->f, r, n);
3305       ns_dumpglyphs_image (s, r[0]);
3306       ns_unfocus (s->f);
3307       break;
3309     case STRETCH_GLYPH:
3310       ns_dumpglyphs_stretch (s);
3311       break;
3313     case CHAR_GLYPH:
3314     case COMPOSITE_GLYPH:
3315       n = ns_get_glyph_string_clip_rect (s, r);
3316       ns_focus (s->f, r, n);
3318       if (s->for_overlaps || (s->cmp_from > 0
3319                               && ! s->first_glyph->u.cmp.automatic))
3320         s->background_filled_p = 1;
3321       else
3322         ns_maybe_dumpglyphs_background
3323           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3325       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3326                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3327                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3328                       NS_DUMPGLYPH_NORMAL));
3329       ns_tmp_font = (struct nsfont_info *)s->face->font;
3330       if (ns_tmp_font == NULL)
3331           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3333       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3334         {
3335           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3336           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3337           NS_FACE_FOREGROUND (s->face) = tmp;
3338         }
3340       ns_tmp_font->font.driver->draw
3341         (s, 0, s->nchars, s->x, s->y,
3342          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3343          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3345       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3346         {
3347           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3348           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3349           NS_FACE_FOREGROUND (s->face) = tmp;
3350         }
3352       ns_unfocus (s->f);
3353       break;
3355     case GLYPHLESS_GLYPH:
3356       n = ns_get_glyph_string_clip_rect (s, r);
3357       ns_focus (s->f, r, n);
3359       if (s->for_overlaps || (s->cmp_from > 0
3360                               && ! s->first_glyph->u.cmp.automatic))
3361         s->background_filled_p = 1;
3362       else
3363         ns_maybe_dumpglyphs_background
3364           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3365       /* ... */
3366       /* Not yet implemented.  */
3367       /* ... */
3368       ns_unfocus (s->f);
3369       break;
3371     default:
3372       abort ();
3373     }
3375   /* Draw box if not done already. */
3376   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3377     {
3378       n = ns_get_glyph_string_clip_rect (s, r);
3379       ns_focus (s->f, r, n);
3380       ns_dumpglyphs_box_or_relief (s);
3381       ns_unfocus (s->f);
3382     }
3384   s->num_clips = 0;
3389 /* ==========================================================================
3391     Event loop
3393    ========================================================================== */
3396 static void
3397 ns_send_appdefined (int value)
3398 /* --------------------------------------------------------------------------
3399     Internal: post an appdefined event which EmacsApp-sendEvent will
3400               recognize and take as a command to halt the event loop.
3401    -------------------------------------------------------------------------- */
3403   /*NSTRACE (ns_send_appdefined); */
3405   /* Only post this event if we haven't already posted one.  This will end
3406        the [NXApp run] main loop after having processed all events queued at
3407        this moment.  */
3408   if (send_appdefined)
3409     {
3410       NSEvent *nxev;
3412       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3413       send_appdefined = NO;
3415       /* Don't need wakeup timer any more */
3416       if (timed_entry)
3417         {
3418           [timed_entry invalidate];
3419           [timed_entry release];
3420           timed_entry = nil;
3421         }
3423       /* Ditto for file descriptor poller */
3424       if (fd_entry)
3425         {
3426           [fd_entry invalidate];
3427           [fd_entry release];
3428           fd_entry = nil;
3429         }
3431       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3432                                 location: NSMakePoint (0, 0)
3433                            modifierFlags: 0
3434                                timestamp: 0
3435                             windowNumber: [[NSApp mainWindow] windowNumber]
3436                                  context: [NSApp context]
3437                                  subtype: 0
3438                                    data1: value
3439                                    data2: 0];
3441       /* Post an application defined event on the event queue.  When this is
3442          received the [NXApp run] will return, thus having processed all
3443          events which are currently queued.  */
3444       [NSApp postEvent: nxev atStart: NO];
3445     }
3449 static int
3450 ns_read_socket (struct terminal *terminal, int expected,
3451                 struct input_event *hold_quit)
3452 /* --------------------------------------------------------------------------
3453      External (hook): Post an event to ourself and keep reading events until
3454      we read it back again.  In effect process all events which were waiting.
3455      From 21+ we have to manage the event buffer ourselves.
3456    -------------------------------------------------------------------------- */
3458   struct input_event ev;
3459   int nevents;
3461 /* NSTRACE (ns_read_socket); */
3463   if (interrupt_input_blocked)
3464     {
3465       interrupt_input_pending = 1;
3466 #ifdef SYNC_INPUT
3467       pending_signals = 1;
3468 #endif
3469       return -1;
3470     }
3472   interrupt_input_pending = 0;
3473 #ifdef SYNC_INPUT
3474   pending_signals = pending_atimers;
3475 #endif
3477   BLOCK_INPUT;
3478   n_emacs_events_pending = 0;
3479   EVENT_INIT (ev);
3480   emacs_event = &ev;
3481   q_event_ptr = hold_quit;
3483   /* we manage autorelease pools by allocate/reallocate each time around
3484      the loop; strict nesting is occasionally violated but seems not to
3485      matter.. earlier methods using full nesting caused major memory leaks */
3486   [outerpool release];
3487   outerpool = [[NSAutoreleasePool alloc] init];
3489   /* If have pending open-file requests, attend to the next one of those. */
3490   if (ns_pending_files && [ns_pending_files count] != 0
3491       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3492     {
3493       [ns_pending_files removeObjectAtIndex: 0];
3494     }
3495   /* Deal with pending service requests. */
3496   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3497     && [(EmacsApp *)
3498          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3499                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3500     {
3501       [ns_pending_service_names removeObjectAtIndex: 0];
3502       [ns_pending_service_args removeObjectAtIndex: 0];
3503     }
3504   else
3505     {
3506       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3507          to ourself, otherwise [NXApp run] will never exit.  */
3508       send_appdefined = YES;
3510       /* If called via ns_select, this is called once with expected=1,
3511          because we expect either the timeout or file descriptor activity.
3512          In this case the first event through will either be real input or
3513          one of these.  read_avail_input() then calls once more with expected=0
3514          and in that case we need to return quickly if there is nothing.
3515          If we're being called outside of that, it's also OK to return quickly
3516          after one iteration through the event loop, since other terms do
3517          this and emacs expects it. */
3518       if (!(inNsSelect && expected))
3519         {
3520           /* Post an application defined event on the event queue.  When this is
3521              received the [NXApp run] will return, thus having processed all
3522              events which are currently queued, if any.  */
3523           ns_send_appdefined (-1);
3524         }
3526       [NSApp run];
3527     }
3529   nevents = n_emacs_events_pending;
3530   n_emacs_events_pending = 0;
3531   emacs_event = q_event_ptr = NULL;
3532   UNBLOCK_INPUT;
3534   return nevents;
3539 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3540            fd_set *exceptfds, struct timeval *timeout)
3541 /* --------------------------------------------------------------------------
3542      Replacement for select, checking for events
3543    -------------------------------------------------------------------------- */
3545   int result;
3546   double time;
3547   NSEvent *ev;
3548 /*  NSTRACE (ns_select); */
3550   if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO &&
3551                       [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
3552  inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
3553     return select (nfds, readfds, writefds, exceptfds, timeout);
3555   /* Save file descriptor set, which gets overwritten in calls to select ()
3556      Note, this is called from process.c, and only readfds is ever set */
3557   if (readfds)
3558     {
3559       memcpy (&select_readfds, readfds, sizeof (fd_set));
3560       select_nfds = nfds;
3561     }
3562   else
3563     select_nfds = 0;
3565     /* Try an initial select for pending data on input files */
3566   select_timeout.tv_sec = select_timeout.tv_usec = 0;
3567   result = select (nfds, readfds, writefds, exceptfds, &select_timeout);
3568   if (result)
3569     return result;
3571   /* if (!timeout || timed_entry || fd_entry)
3572        fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
3574     /* set a timeout and run the main AppKit event loop while continuing
3575        to monitor the files */
3576   time = ((double) timeout->tv_sec) + ((double) timeout->tv_usec)/1000000.0;
3577   timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3578                                            target: NSApp
3579                                          selector: @selector (timeout_handler:)
3580                                          userInfo: 0
3581                                           repeats: YES] /* for safe removal */
3582                                                          retain];
3584   /* set a periodic task to try the select () again */
3585   fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
3586                                                target: NSApp
3587                                              selector: @selector (fd_handler:)
3588                                              userInfo: 0
3589                                               repeats: YES]
3590                retain];
3592   /* Let Application dispatch events until it receives an event of the type
3593      NX_APPDEFINED, which should only be sent by timeout_handler.
3594      We tell read_avail_input() that input is "expected" because we do expect
3595      either the timeout or fd handler to fire, and if they don't, the original
3596      call from process.c that got us here expects us to wait until some input
3597      comes. */
3598   inNsSelect = 1;
3599   gobble_input (1);
3600   ev = last_appdefined_event;
3601   inNsSelect = 0;
3603   if (ev)
3604     {
3605       int t;
3606       if ([ev type] != NSApplicationDefined)
3607         abort ();
3609       t = [ev data1];
3610       last_appdefined_event = 0;
3612       if (t == -2)
3613         {
3614           /* The NX_APPDEFINED event we received was a timeout. */
3615           return 0;
3616         }
3617       else if (t == -1)
3618         {
3619           /* The NX_APPDEFINED event we received was the result of
3620              at least one real input event arriving.  */
3621           errno = EINTR;
3622           return -1;
3623         }
3624       else
3625         {
3626           /* Received back from select () in fd_handler; copy the results */
3627           if (readfds)
3628             memcpy (readfds, &select_readfds, sizeof (fd_set));
3629           return t;
3630         }
3631     }
3632   /* never reached, shut compiler up */
3633   return 0;
3638 /* ==========================================================================
3640     Scrollbar handling
3642    ========================================================================== */
3645 static void
3646 ns_set_vertical_scroll_bar (struct window *window,
3647                            int portion, int whole, int position)
3648 /* --------------------------------------------------------------------------
3649       External (hook): Update or add scrollbar
3650    -------------------------------------------------------------------------- */
3652   Lisp_Object win;
3653   NSRect r, v;
3654   struct frame *f = XFRAME (WINDOW_FRAME (window));
3655   EmacsView *view = FRAME_NS_VIEW (f);
3656   int window_y, window_height;
3657   BOOL barOnVeryLeft, barOnVeryRight;
3658   int top, left, height, width, sb_width, sb_left;
3659   EmacsScroller *bar;
3660 static int count = 0;
3662   /* optimization; display engine sends WAY too many of these.. */
3663   if (!NILP (window->vertical_scroll_bar))
3664     {
3665       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3666       if ([bar checkSamePosition: position portion: portion whole: whole])
3667         {
3668           if (view->scrollbarsNeedingUpdate == 0)
3669             {
3670               if (!windows_or_buffers_changed)
3671                   return;
3672             }
3673           else
3674             view->scrollbarsNeedingUpdate--;
3675         }
3676     }
3678   NSTRACE (ns_set_vertical_scroll_bar);
3680   /* Get dimensions.  */
3681   window_box (window, -1, 0, &window_y, 0, &window_height);
3682   top = window_y;
3683   height = window_height;
3684   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3685   left = WINDOW_SCROLL_BAR_AREA_X (window);
3687   if (top < 5) /* top scrollbar adjustment */
3688     {
3689       top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3690       height += FRAME_INTERNAL_BORDER_WIDTH (f);
3691     }
3693   /* allow for displaying a skinnier scrollbar than char area allotted */
3694   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3695     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3697   barOnVeryLeft = left < 5;
3698   barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3699   sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3700       * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3702   r = NSMakeRect (sb_left, top, sb_width, height);
3703   /* the parent view is flipped, so we need to flip y value */
3704   v = [view frame];
3705   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3707   XSETWINDOW (win, window);
3708   BLOCK_INPUT;
3710   /* we want at least 5 lines to display a scrollbar */
3711   if (WINDOW_TOTAL_LINES (window) < 5)
3712     {
3713       if (!NILP (window->vertical_scroll_bar))
3714         {
3715           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3716           [bar removeFromSuperview];
3717           window->vertical_scroll_bar = Qnil;
3718         }
3719       ns_clear_frame_area (f, sb_left, top, width, height);
3720       UNBLOCK_INPUT;
3721       return;
3722     }
3724   if (NILP (window->vertical_scroll_bar))
3725     {
3726       ns_clear_frame_area (f, sb_left, top, width, height);
3727       bar = [[EmacsScroller alloc] initFrame: r window: win];
3728       window->vertical_scroll_bar = make_save_value (bar, 0);
3729     }
3730   else
3731     {
3732       NSRect oldRect;
3733       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3734       oldRect = [bar frame];
3735       r.size.width = oldRect.size.width;
3736       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3737         {
3738           if (oldRect.origin.x != r.origin.x)
3739               ns_clear_frame_area (f, sb_left, top, width, height);
3740           [bar setFrame: r];
3741         }
3742     }
3744   [bar setPosition: position portion: portion whole: whole];
3745   UNBLOCK_INPUT;
3749 static void
3750 ns_condemn_scroll_bars (struct frame *f)
3751 /* --------------------------------------------------------------------------
3752      External (hook): arrange for all frame's scrollbars to be removed
3753      at next call to judge_scroll_bars, except for those redeemed.
3754    -------------------------------------------------------------------------- */
3756   int i;
3757   id view;
3758   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3760   NSTRACE (ns_condemn_scroll_bars);
3762   for (i =[subviews count]-1; i >= 0; i--)
3763     {
3764       view = [subviews objectAtIndex: i];
3765       if ([view isKindOfClass: [EmacsScroller class]])
3766         [view condemn];
3767     }
3771 static void
3772 ns_redeem_scroll_bar (struct window *window)
3773 /* --------------------------------------------------------------------------
3774      External (hook): arrange to spare this window's scrollbar
3775      at next call to judge_scroll_bars.
3776    -------------------------------------------------------------------------- */
3778   id bar;
3779   NSTRACE (ns_redeem_scroll_bar);
3780   if (!NILP (window->vertical_scroll_bar))
3781     {
3782       bar =XNS_SCROLL_BAR (window->vertical_scroll_bar);
3783       [bar reprieve];
3784     }
3788 static void
3789 ns_judge_scroll_bars (struct frame *f)
3790 /* --------------------------------------------------------------------------
3791      External (hook): destroy all scrollbars on frame that weren't
3792      redeemed after call to condemn_scroll_bars.
3793    -------------------------------------------------------------------------- */
3795   int i;
3796   id view;
3797   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3798   NSTRACE (ns_judge_scroll_bars);
3799   for (i =[subviews count]-1; i >= 0; i--)
3800     {
3801       view = [subviews objectAtIndex: i];
3802       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3803       [view judge];
3804     }
3808 void
3809 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3811   /* XXX irrelevant under NS */
3816 /* ==========================================================================
3818     Initialization
3820    ========================================================================== */
3823 x_display_pixel_height (struct ns_display_info *dpyinfo)
3825   NSScreen *screen = [NSScreen mainScreen];
3826   return [screen frame].size.height;
3830 x_display_pixel_width (struct ns_display_info *dpyinfo)
3832   NSScreen *screen = [NSScreen mainScreen];
3833   return [screen frame].size.width;
3837 static Lisp_Object ns_string_to_lispmod (const char *s)
3838 /* --------------------------------------------------------------------------
3839      Convert modifier name to lisp symbol
3840    -------------------------------------------------------------------------- */
3842   if (!strncmp (SDATA (SYMBOL_NAME (Qmeta)), s, 10))
3843     return Qmeta;
3844   else if (!strncmp (SDATA (SYMBOL_NAME (Qsuper)), s, 10))
3845     return Qsuper;
3846   else if (!strncmp (SDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3847     return Qcontrol;
3848   else if (!strncmp (SDATA (SYMBOL_NAME (Qalt)), s, 10))
3849     return Qalt;
3850   else if (!strncmp (SDATA (SYMBOL_NAME (Qhyper)), s, 10))
3851     return Qhyper;
3852   else if (!strncmp (SDATA (SYMBOL_NAME (Qnone)), s, 10))
3853     return Qnone;
3854   else
3855     return Qnil;
3859 static Lisp_Object ns_mod_to_lisp (int m)
3860 /* --------------------------------------------------------------------------
3861      Convert modifier code (see lisp.h) to lisp symbol
3862    -------------------------------------------------------------------------- */
3864   if (m == CHAR_META)
3865     return Qmeta;
3866   else if (m == CHAR_SUPER)
3867     return Qsuper;
3868   else if (m == CHAR_CTL)
3869     return Qcontrol;
3870   else if (m == CHAR_ALT)
3871     return Qalt;
3872   else if (m == CHAR_HYPER)
3873     return Qhyper;
3874   else /* if (m == 0) */
3875     return Qnone;
3879 static void
3880 ns_default (const char *parameter, Lisp_Object *result,
3881            Lisp_Object yesval, Lisp_Object noval,
3882            BOOL is_float, BOOL is_modstring)
3883 /* --------------------------------------------------------------------------
3884       Check a parameter value in user's preferences
3885    -------------------------------------------------------------------------- */
3887   const char *value = ns_get_defaults_value (parameter);
3889   if (value)
3890     {
3891       double f;
3892       char *pos;
3893       if (strcasecmp (value, "YES") == 0)
3894         *result = yesval;
3895       else if (strcasecmp (value, "NO") == 0)
3896         *result = noval;
3897       else if (is_float && (f = strtod (value, &pos), pos != value))
3898         *result = make_float (f);
3899       else if (is_modstring && value)
3900         *result = ns_string_to_lispmod (value);
3901       else fprintf (stderr,
3902                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3903     }
3907 void
3908 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3909 /* --------------------------------------------------------------------------
3910       Initialize global info and storage for display.
3911    -------------------------------------------------------------------------- */
3913     NSScreen *screen = [NSScreen mainScreen];
3914     NSWindowDepth depth = [screen depth];
3915     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3917     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3918     dpyinfo->resy = 72.27;
3919     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3920                                                   NSColorSpaceFromDepth (depth)]
3921                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3922                                                  NSColorSpaceFromDepth (depth)];
3923     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3924     dpyinfo->image_cache = make_image_cache ();
3925     dpyinfo->color_table
3926       = (struct ns_color_table *)xmalloc (sizeof (struct ns_color_table));
3927     dpyinfo->color_table->colors = NULL;
3928     dpyinfo->root_window = 42; /* a placeholder.. */
3930     hlinfo->mouse_face_mouse_frame = NULL;
3931     hlinfo->mouse_face_deferred_gc = 0;
3932     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3933     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3934     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3935     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3936     hlinfo->mouse_face_hidden = 0;
3938     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3939     hlinfo->mouse_face_defer = 0;
3941     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3943     dpyinfo->n_fonts = 0;
3944     dpyinfo->smallest_font_height = 1;
3945     dpyinfo->smallest_char_width = 1;
3949 /* This and next define (many of the) public functions in this file. */
3950 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3951          with using despite presence in the "system dependent" redisplay
3952          interface.  In addition, many of the ns_ methods have code that is
3953          shared with all terms, indicating need for further refactoring. */
3954 extern frame_parm_handler ns_frame_parm_handlers[];
3955 static struct redisplay_interface ns_redisplay_interface =
3957   ns_frame_parm_handlers,
3958   x_produce_glyphs,
3959   x_write_glyphs,
3960   x_insert_glyphs,
3961   x_clear_end_of_line,
3962   ns_scroll_run,
3963   ns_after_update_window_line,
3964   ns_update_window_begin,
3965   ns_update_window_end,
3966   x_cursor_to,
3967   ns_flush,
3968   0, /* flush_display_optional */
3969   x_clear_window_mouse_face,
3970   x_get_glyph_overhangs,
3971   x_fix_overlapping_area,
3972   ns_draw_fringe_bitmap,
3973   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3974   0, /* destroy_fringe_bitmap */
3975   ns_compute_glyph_string_overhangs,
3976   ns_draw_glyph_string, /* interface to nsfont.m */
3977   ns_define_frame_cursor,
3978   ns_clear_frame_area,
3979   ns_draw_window_cursor,
3980   ns_draw_vertical_window_border,
3981   ns_shift_glyphs_for_insert
3985 static void
3986 ns_delete_display (struct ns_display_info *dpyinfo)
3988   /* TODO... */
3992 /* This function is called when the last frame on a display is deleted. */
3993 static void
3994 ns_delete_terminal (struct terminal *terminal)
3996   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3997   int i;
3999   /* Protect against recursive calls.  delete_frame in
4000      delete_terminal calls us back when it deletes our last frame.  */
4001   if (!terminal->name)
4002     return;
4004   BLOCK_INPUT;
4006   x_destroy_all_bitmaps (dpyinfo);
4007   ns_delete_display (dpyinfo);
4008   UNBLOCK_INPUT;
4012 static struct terminal *
4013 ns_create_terminal (struct ns_display_info *dpyinfo)
4014 /* --------------------------------------------------------------------------
4015       Set up use of NS before we make the first connection.
4016    -------------------------------------------------------------------------- */
4018   struct terminal *terminal;
4020   NSTRACE (ns_create_terminal);
4022   terminal = create_terminal ();
4024   terminal->type = output_ns;
4025   terminal->display_info.ns = dpyinfo;
4026   dpyinfo->terminal = terminal;
4028   terminal->rif = &ns_redisplay_interface;
4030   terminal->clear_frame_hook = ns_clear_frame;
4031   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4032   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
4033   terminal->ring_bell_hook = ns_ring_bell;
4034   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
4035   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
4036   terminal->update_begin_hook = ns_update_begin;
4037   terminal->update_end_hook = ns_update_end;
4038   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4039   terminal->read_socket_hook = ns_read_socket;
4040   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4041   terminal->mouse_position_hook = ns_mouse_position;
4042   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4043   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4045   terminal->fullscreen_hook = 0; /* see XTfullscreen_hook */
4047   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4048   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4049   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4050   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4052   terminal->delete_frame_hook = x_destroy_window;
4053   terminal->delete_terminal_hook = ns_delete_terminal;
4055   terminal->scroll_region_ok = 1;
4056   terminal->char_ins_del_ok = 1;
4057   terminal->line_ins_del_ok = 1;
4058   terminal->fast_clear_end_of_line = 1;
4059   terminal->memory_below_frame = 0;
4061   return terminal;
4065 struct ns_display_info *
4066 ns_term_init (Lisp_Object display_name)
4067 /* --------------------------------------------------------------------------
4068      Start the Application and get things rolling.
4069    -------------------------------------------------------------------------- */
4071   struct terminal *terminal;
4072   struct ns_display_info *dpyinfo;
4073   static int ns_initialized = 0;
4074   Lisp_Object tmp;
4076   NSTRACE (ns_term_init);
4078   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4079   /*GSDebugAllocationActive (YES); */
4080   BLOCK_INPUT;
4081   handling_signal = 0;
4083   if (!ns_initialized)
4084     {
4085       baud_rate = 38400;
4086       Fset_input_interrupt_mode (Qnil);
4087       ns_initialized = 1;
4088     }
4090   ns_pending_files = [[NSMutableArray alloc] init];
4091   ns_pending_service_names = [[NSMutableArray alloc] init];
4092   ns_pending_service_args = [[NSMutableArray alloc] init];
4094   /* Start app and create the main menu, window, view.
4095      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4096      The view will then ask the NSApp to stop and return to Emacs. */
4097   [EmacsApp sharedApplication];
4098   if (NSApp == nil)
4099     return NULL;
4100   [NSApp setDelegate: NSApp];
4102   /* debugging: log all notifications */
4103   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4104                                          selector: @selector (logNotification:)
4105                                              name: nil object: nil]; */
4107   dpyinfo = (struct ns_display_info *)xmalloc (sizeof (struct ns_display_info));
4108   memset (dpyinfo, 0, sizeof (struct ns_display_info));
4110   ns_initialize_display_info (dpyinfo);
4111   terminal = ns_create_terminal (dpyinfo);
4113   terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
4114   init_kboard (terminal->kboard);
4115   KVAR (terminal->kboard, Vwindow_system) = Qns;
4116   terminal->kboard->next_kboard = all_kboards;
4117   all_kboards = terminal->kboard;
4118   /* Don't let the initial kboard remain current longer than necessary.
4119      That would cause problems if a file loaded on startup tries to
4120      prompt in the mini-buffer.  */
4121   if (current_kboard == initial_kboard)
4122     current_kboard = terminal->kboard;
4123   terminal->kboard->reference_count++;
4125   dpyinfo->next = x_display_list;
4126   x_display_list = dpyinfo;
4128   /* Put it on ns_display_name_list */
4129   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4130                                 ns_display_name_list);
4131   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4133   /* Set the name of the terminal. */
4134   terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
4135   strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
4136   terminal->name[SBYTES (display_name)] = 0;
4138   UNBLOCK_INPUT;
4140   if (!inhibit_x_resources)
4141     {
4142       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4143                  Qt, Qnil, NO, NO);
4144       tmp = Qnil;
4145       /* this is a standard variable */
4146       ns_default ("AppleAntiAliasingThreshold", &tmp,
4147                  make_float (10.0), make_float (6.0), YES, NO);
4148       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4149     }
4151   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4152                          stringForKey: @"AppleHighlightColor"];
4153   if (ns_selection_color == nil)
4154     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4156   {
4157     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4159     if ( cl == nil )
4160       {
4161         Lisp_Object color_file, color_map, color;
4162         int r,g,b;
4163         unsigned long c;
4164         char *name;
4166         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4167                          Fsymbol_value (intern ("data-directory")));
4168         if (NILP (Ffile_readable_p (color_file)))
4169           fatal ("Could not find %s.\n", SDATA (color_file));
4171         color_map = Fx_load_color_file (color_file);
4172         if (NILP (color_map))
4173           fatal ("Could not read %s.\n", SDATA (color_file));
4175         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4176         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4177           {
4178             color = XCAR (color_map);
4179             name = SDATA (XCAR (color));
4180             c = XINT (XCDR (color));
4181             [cl setColor:
4182                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4183                                             green: GREEN_FROM_ULONG (c) / 255.0
4184                                              blue: BLUE_FROM_ULONG (c) / 255.0
4185                                             alpha: 1.0]
4186                   forKey: [NSString stringWithUTF8String: name]];
4187           }
4188         [cl writeToFile: nil];
4189       }
4190   }
4192   {
4193     char c[128];
4194 #ifdef NS_IMPL_GNUSTEP
4195     strncpy (c, gnustep_base_version, sizeof (c));
4196 #else
4197     /*PSnextrelease (128, c); */
4198     snprintf (c, sizeof (c), "%g", NSAppKitVersionNumber);
4199 #endif
4200     Vwindow_system_version = build_string (c);
4201   }
4203   delete_keyboard_wait_descriptor (0);
4205   ns_app_name = [[NSProcessInfo processInfo] processName];
4207 /* Set up OS X app menu */
4208 #ifdef NS_IMPL_COCOA
4209   {
4210     NSMenu *appMenu;
4211     NSMenuItem *item;
4212     /* set up the application menu */
4213     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4214     [svcsMenu setAutoenablesItems: NO];
4215     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4216     [appMenu setAutoenablesItems: NO];
4217     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4218     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4220     [appMenu insertItemWithTitle: @"About Emacs"
4221                           action: @selector (orderFrontStandardAboutPanel:)
4222                    keyEquivalent: @""
4223                          atIndex: 0];
4224     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4225     [appMenu insertItemWithTitle: @"Preferences..."
4226                           action: @selector (showPreferencesWindow:)
4227                    keyEquivalent: @","
4228                          atIndex: 2];
4229     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4230     item = [appMenu insertItemWithTitle: @"Services"
4231                                  action: @selector (menuDown:)
4232                           keyEquivalent: @""
4233                                 atIndex: 4];
4234     [appMenu setSubmenu: svcsMenu forItem: item];
4235     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4236     [appMenu insertItemWithTitle: @"Hide Emacs"
4237                           action: @selector (hide:)
4238                    keyEquivalent: @"h"
4239                          atIndex: 6];
4240     item =  [appMenu insertItemWithTitle: @"Hide Others"
4241                           action: @selector (hideOtherApplications:)
4242                    keyEquivalent: @"h"
4243                          atIndex: 7];
4244     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4245     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4246     [appMenu insertItemWithTitle: @"Quit Emacs"
4247                           action: @selector (terminate:)
4248                    keyEquivalent: @"q"
4249                          atIndex: 9];
4251     item = [mainMenu insertItemWithTitle: ns_app_name
4252                                   action: @selector (menuDown:)
4253                            keyEquivalent: @""
4254                                  atIndex: 0];
4255     [mainMenu setSubmenu: appMenu forItem: item];
4256     [dockMenu insertItemWithTitle: @"New Frame"
4257                            action: @selector (newFrame:)
4258                     keyEquivalent: @""
4259                           atIndex: 0];
4261     [NSApp setMainMenu: mainMenu];
4262     [NSApp setAppleMenu: appMenu];
4263     [NSApp setServicesMenu: svcsMenu];
4264     /* Needed at least on Cocoa, to get dock menu to show windows */
4265     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4267     [[NSNotificationCenter defaultCenter]
4268       addObserver: mainMenu
4269          selector: @selector (trackingNotification:)
4270              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4271     [[NSNotificationCenter defaultCenter]
4272       addObserver: mainMenu
4273          selector: @selector (trackingNotification:)
4274              name: NSMenuDidEndTrackingNotification object: mainMenu];
4275   }
4276 #endif /* MAC OS X menu setup */
4278   [NSApp run];
4280   return dpyinfo;
4284 void
4285 ns_term_shutdown (int sig)
4287   [[NSUserDefaults standardUserDefaults] synchronize];
4289   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4290   if (STRINGP (Vauto_save_list_file_name))
4291     unlink (SDATA (Vauto_save_list_file_name));
4293   if (sig == 0 || sig == SIGTERM)
4294     {
4295       [NSApp terminate: NSApp];
4296     }
4297   else // force a stack trace to happen
4298     {
4299       abort();
4300     }
4304 /* ==========================================================================
4306     EmacsApp implementation
4308    ========================================================================== */
4311 @implementation EmacsApp
4313 - (void)logNotification: (NSNotification *)notification
4315   const char *name = [[notification name] UTF8String];
4316   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4317       && !strstr (name, "WindowNumber"))
4318     NSLog (@"notification: '%@'", [notification name]);
4322 - (void)sendEvent: (NSEvent *)theEvent
4323 /* --------------------------------------------------------------------------
4324      Called when NSApp is running for each event received.  Used to stop
4325      the loop when we choose, since there's no way to just run one iteration.
4326    -------------------------------------------------------------------------- */
4328   int type = [theEvent type];
4329   NSWindow *window = [theEvent window];
4330 /*  NSTRACE (sendEvent); */
4331 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4333 #ifdef NS_IMPL_COCOA
4334   if (type == NSApplicationDefined
4335       && [theEvent data2] == NSAPP_DATA2_RUNASSCRIPT)
4336     {
4337       ns_run_ascript ();
4338       [self stop: self];
4339       return;
4340     }
4341 #endif
4343   if (type == NSCursorUpdate && window == nil)
4344     {
4345       fprintf (stderr, "Dropping external cursor update event.\n");
4346       return;
4347     }
4349 #ifdef NS_IMPL_COCOA
4350   /* pass mouse down in resize handle and subsequent drags directly to
4351      EmacsWindow so we can generate continuous redisplays */
4352   if (ns_in_resize)
4353     {
4354       if (type == NSLeftMouseDragged)
4355         {
4356           [window mouseDragged: theEvent];
4357           return;
4358         }
4359       else if (type == NSLeftMouseUp)
4360         {
4361           [window mouseUp: theEvent];
4362           return;
4363         }
4364     }
4365   else if (type == NSLeftMouseDown)
4366     {
4367       NSRect r = ns_resize_handle_rect (window);
4368       if (NSPointInRect ([theEvent locationInWindow], r))
4369         {
4370           ns_in_resize = YES;
4371           [window mouseDown: theEvent];
4372           return;
4373         }
4374     }
4375 #endif
4377   if (type == NSApplicationDefined)
4378     {
4379       /* Events posted by ns_send_appdefined interrupt the run loop here.
4380          But, if a modal window is up, an appdefined can still come through,
4381          (e.g., from a makeKeyWindow event) but stopping self also stops the
4382          modal loop. Just defer it until later. */
4383       if ([NSApp modalWindow] == nil)
4384         {
4385           last_appdefined_event = theEvent;
4386           [self stop: self];
4387         }
4388       else
4389         {
4390           send_appdefined = YES;
4391         }
4392     }
4394   [super sendEvent: theEvent];
4398 - (void)showPreferencesWindow: (id)sender
4400   struct frame *emacsframe = SELECTED_FRAME ();
4401   NSEvent *theEvent = [NSApp currentEvent];
4403   if (!emacs_event)
4404     return;
4405   emacs_event->kind = NS_NONKEY_EVENT;
4406   emacs_event->code = KEY_NS_SHOW_PREFS;
4407   emacs_event->modifiers = 0;
4408   EV_TRAILER (theEvent);
4412 - (void)newFrame: (id)sender
4414   struct frame *emacsframe = SELECTED_FRAME ();
4415   NSEvent *theEvent = [NSApp currentEvent];
4417   if (!emacs_event)
4418     return;
4419   emacs_event->kind = NS_NONKEY_EVENT;
4420   emacs_event->code = KEY_NS_NEW_FRAME;
4421   emacs_event->modifiers = 0;
4422   EV_TRAILER (theEvent);
4426 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4427 - (BOOL) openFile: (NSString *)fileName
4429   struct frame *emacsframe = SELECTED_FRAME ();
4430   NSEvent *theEvent = [NSApp currentEvent];
4432   if (!emacs_event)
4433     return NO;
4435   emacs_event->kind = NS_NONKEY_EVENT;
4436   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4437   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4438   ns_input_line = Qnil; /* can be start or cons start,end */
4439   emacs_event->modifiers =0;
4440   EV_TRAILER (theEvent);
4442   return YES;
4446 /* **************************************************************************
4448       EmacsApp delegate implementation
4450    ************************************************************************** */
4452 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4453 /* --------------------------------------------------------------------------
4454      When application is loaded, terminate event loop in ns_term_init
4455    -------------------------------------------------------------------------- */
4457   NSTRACE (applicationDidFinishLaunching);
4458   [NSApp setServicesProvider: NSApp];
4459   ns_send_appdefined (-2);
4463 /* Termination sequences:
4464     C-x C-c:
4465     Cmd-Q:
4466     MenuBar | File | Exit:
4467     Select Quit from App menubar:
4468         -terminate
4469         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4470         ns_term_shutdown()
4472     Select Quit from Dock menu:
4473     Logout attempt:
4474         -appShouldTerminate
4475           Cancel -> Nothing else
4476           Accept ->
4478           -terminate
4479           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4480           ns_term_shutdown()
4484 - (void) terminate: (id)sender
4486   struct frame *emacsframe = SELECTED_FRAME ();
4488   if (!emacs_event)
4489     return;
4491   emacs_event->kind = NS_NONKEY_EVENT;
4492   emacs_event->code = KEY_NS_POWER_OFF;
4493   emacs_event->arg = Qt; /* mark as non-key event */
4494   EV_TRAILER ((id)nil);
4498 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4500   int ret;
4502   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4503     return NSTerminateNow;
4505     ret = NSRunAlertPanel(ns_app_name,
4506                           [NSString stringWithUTF8String:"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?"],
4507                           @"Save Buffers and Exit", @"Cancel", nil);
4509     if (ret == NSAlertDefaultReturn)
4510         return NSTerminateNow;
4511     else if (ret == NSAlertAlternateReturn)
4512         return NSTerminateCancel;
4513     return NSTerminateNow;  /* just in case */
4517 /*   Notification from the Workspace to open a file */
4518 - (BOOL)application: sender openFile: (NSString *)file
4520   [ns_pending_files addObject: file];
4521   return YES;
4525 /*   Open a file as a temporary file */
4526 - (BOOL)application: sender openTempFile: (NSString *)file
4528   [ns_pending_files addObject: file];
4529   return YES;
4533 /*   Notification from the Workspace to open a file noninteractively (?) */
4534 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4536   [ns_pending_files addObject: file];
4537   return YES;
4541 /*   Notification from the Workspace to open multiple files */
4542 - (void)application: sender openFiles: (NSArray *)fileList
4544   NSEnumerator *files = [fileList objectEnumerator];
4545   NSString *file;
4546   while ((file = [files nextObject]) != nil)
4547     [ns_pending_files addObject: file];
4549   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4554 /* Handle dock menu requests.  */
4555 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4557   return dockMenu;
4561 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4562 - (void)applicationWillBecomeActive: (NSNotification *)notification
4564   //ns_app_active=YES;
4566 - (void)applicationDidBecomeActive: (NSNotification *)notification
4568   NSTRACE (applicationDidBecomeActive);
4570   //ns_app_active=YES;
4572   ns_update_auto_hide_menu_bar ();
4573   // No constraining takes place when the application is not active.
4574   ns_constrain_all_frames ();
4576 - (void)applicationDidResignActive: (NSNotification *)notification
4578   //ns_app_active=NO;
4579   ns_send_appdefined (-1);
4584 /* ==========================================================================
4586     EmacsApp aux handlers for managing event loop
4588    ========================================================================== */
4591 - (void)timeout_handler: (NSTimer *)timedEntry
4592 /* --------------------------------------------------------------------------
4593      The timeout specified to ns_select has passed.
4594    -------------------------------------------------------------------------- */
4596   /*NSTRACE (timeout_handler); */
4597   ns_send_appdefined (-2);
4600 - (void)fd_handler: (NSTimer *) fdEntry
4601 /* --------------------------------------------------------------------------
4602      Check data waiting on file descriptors and terminate if so
4603    -------------------------------------------------------------------------- */
4605   int result;
4606   /* NSTRACE (fd_handler); */
4608   if (select_nfds == 0)
4609     return;
4611   memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4613   select_timeout.tv_sec = select_timeout.tv_usec = 0;
4614   result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
4615                   &select_timeout);
4616   if (result)
4617     {
4618       memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4619       ns_send_appdefined (result);
4620     }
4625 /* ==========================================================================
4627     Service provision
4629    ========================================================================== */
4631 /* called from system: queue for next pass through event loop */
4632 - (void)requestService: (NSPasteboard *)pboard
4633               userData: (NSString *)userData
4634                  error: (NSString **)error
4636   [ns_pending_service_names addObject: userData];
4637   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4638       SDATA (ns_string_from_pasteboard (pboard))]];
4642 /* called from ns_read_socket to clear queue */
4643 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4645   struct frame *emacsframe = SELECTED_FRAME ();
4646   NSEvent *theEvent = [NSApp currentEvent];
4648   if (!emacs_event)
4649     return NO;
4651   emacs_event->kind = NS_NONKEY_EVENT;
4652   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4653   ns_input_spi_name = build_string ([name UTF8String]);
4654   ns_input_spi_arg = build_string ([arg UTF8String]);
4655   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4656   EV_TRAILER (theEvent);
4658   return YES;
4662 @end  /* EmacsApp */
4666 /* ==========================================================================
4668     EmacsView implementation
4670    ========================================================================== */
4673 @implementation EmacsView
4675 /* needed to inform when window closed from LISP */
4676 - (void) setWindowClosing: (BOOL)closing
4678   windowClosing = closing;
4682 - (void)dealloc
4684   NSTRACE (EmacsView_dealloc);
4685   [toolbar release];
4686   [super dealloc];
4690 /* called on font panel selection */
4691 - (void)changeFont: (id)sender
4693   NSEvent *e =[[self window] currentEvent];
4694   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4695   id newFont;
4696   float size;
4698   NSTRACE (changeFont);
4699   if (!emacs_event)
4700     return;
4702   if (newFont = [sender convertFont:
4703                            ((struct nsfont_info *)face->font)->nsfont])
4704     {
4705       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4707       emacs_event->kind = NS_NONKEY_EVENT;
4708       emacs_event->modifiers = 0;
4709       emacs_event->code = KEY_NS_CHANGE_FONT;
4711       size = [newFont pointSize];
4712       ns_input_fontsize = make_number (lrint (size));
4713       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4714       EV_TRAILER (e);
4715     }
4719 - (BOOL)acceptsFirstResponder
4721   NSTRACE (acceptsFirstResponder);
4722   return YES;
4726 - (void)resetCursorRects
4728   NSRect visible = [self visibleRect];
4729   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4730   NSTRACE (resetCursorRects);
4732   if (currentCursor == nil)
4733     currentCursor = [NSCursor arrowCursor];
4735   if (!NSIsEmptyRect (visible))
4736     [self addCursorRect: visible cursor: currentCursor];
4737   [currentCursor setOnMouseEntered: YES];
4742 /*****************************************************************************/
4743 /* Keyboard handling. */
4744 #define NS_KEYLOG 0
4746 - (void)keyDown: (NSEvent *)theEvent
4748   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4749   int code;
4750   unsigned fnKeysym = 0;
4751   int flags;
4752   static NSMutableArray *nsEvArray;
4753 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4754   static BOOL firstTime = YES;
4755 #endif
4756   int left_is_none;
4758   NSTRACE (keyDown);
4760   /* Rhapsody and OS X give up and down events for the arrow keys */
4761   if (ns_fake_keydown == YES)
4762     ns_fake_keydown = NO;
4763   else if ([theEvent type] != NSKeyDown)
4764     return;
4766   if (!emacs_event)
4767     return;
4769  if (![[self window] isKeyWindow]
4770      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4771      /* we must avoid an infinite loop here. */
4772      && (EmacsView *)[[theEvent window] delegate] != self)
4773    {
4774      /* XXX: There is an occasional condition in which, when Emacs display
4775          updates a different frame from the current one, and temporarily
4776          selects it, then processes some interrupt-driven input
4777          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4778          for some reason that window has its first responder set to the NSView
4779          most recently updated (I guess), which is not the correct one. */
4780      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4781      return;
4782    }
4784   if (nsEvArray == nil)
4785     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4787   [NSCursor setHiddenUntilMouseMoves: YES];
4789   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4790     {
4791       clear_mouse_face (hlinfo);
4792       hlinfo->mouse_face_hidden = 1;
4793     }
4795   if (!processingCompose)
4796     {
4797       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4798         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4799       /* (Carbon way: [theEvent keyCode]) */
4801       /* is it a "function key"? */
4802       fnKeysym = ns_convert_key (code);
4803       if (fnKeysym)
4804         {
4805           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4806              because Emacs treats Delete and KP-Delete same (in simple.el). */
4807           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4808             code = 0xFF08; /* backspace */
4809           else
4810             code = fnKeysym;
4811         }
4813       /* are there modifiers? */
4814       emacs_event->modifiers = 0;
4815       flags = [theEvent modifierFlags];
4817       if (flags & NSHelpKeyMask)
4818           emacs_event->modifiers |= hyper_modifier;
4820       if (flags & NSShiftKeyMask)
4821         emacs_event->modifiers |= shift_modifier;
4823       if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask)
4824         emacs_event->modifiers |= parse_solitary_modifier
4825           (EQ (ns_right_command_modifier, Qleft)
4826            ? ns_command_modifier
4827            : ns_right_command_modifier);
4829       if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask)
4830         {
4831           emacs_event->modifiers |= parse_solitary_modifier
4832             (ns_command_modifier);
4834           /* if super (default), take input manager's word so things like
4835              dvorak / qwerty layout work */
4836           if (EQ (ns_command_modifier, Qsuper)
4837               && !fnKeysym
4838               && [[theEvent characters] length] != 0)
4839             {
4840               /* XXX: the code we get will be unshifted, so if we have
4841                  a shift modifier, must convert ourselves */
4842               if (!(flags & NSShiftKeyMask))
4843                 code = [[theEvent characters] characterAtIndex: 0];
4844 #if 0
4845               /* this is ugly and also requires linking w/Carbon framework
4846                  (for LMGetKbdType) so for now leave this rare (?) case
4847                  undealt with.. in future look into CGEvent methods */
4848               else
4849                 {
4850                   long smv = GetScriptManagerVariable (smKeyScript);
4851                   Handle uchrHandle = GetResource
4852                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4853                   UInt32 dummy = 0;
4854                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4855                                  [[theEvent characters] characterAtIndex: 0],
4856                                  kUCKeyActionDisplay,
4857                                  (flags & ~NSCommandKeyMask) >> 8,
4858                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4859                                  &dummy, 1, &dummy, &code);
4860                   code &= 0xFF;
4861                 }
4862 #endif
4863             }
4864         }
4866       if ((flags & NSRightControlKeyMask) == NSRightControlKeyMask)
4867           emacs_event->modifiers |= parse_solitary_modifier
4868               (EQ (ns_right_control_modifier, Qleft)
4869                ? ns_control_modifier
4870                : ns_right_control_modifier);
4872       if ((flags & NSLeftControlKeyMask) == NSLeftControlKeyMask)
4873         emacs_event->modifiers |= parse_solitary_modifier
4874           (ns_control_modifier);
4876       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4877           emacs_event->modifiers |=
4878             parse_solitary_modifier (ns_function_modifier);
4880       left_is_none = NILP (ns_alternate_modifier)
4881         || EQ (ns_alternate_modifier, Qnone);
4883       if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask)
4884         {
4885           if ((NILP (ns_right_alternate_modifier)
4886                || EQ (ns_right_alternate_modifier, Qnone)
4887                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4888               && !fnKeysym)
4889             {   /* accept pre-interp alt comb */
4890               if ([[theEvent characters] length] > 0)
4891                 code = [[theEvent characters] characterAtIndex: 0];
4892               /*HACK: clear lone shift modifier to stop next if from firing */
4893               if (emacs_event->modifiers == shift_modifier)
4894                 emacs_event->modifiers = 0;
4895             }
4896           else
4897             emacs_event->modifiers |= parse_solitary_modifier
4898               (EQ (ns_right_alternate_modifier, Qleft)
4899                ? ns_alternate_modifier
4900                : ns_right_alternate_modifier);
4901         }
4903       if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask) /* default = meta */
4904         {
4905           if (left_is_none && !fnKeysym)
4906             {   /* accept pre-interp alt comb */
4907               if ([[theEvent characters] length] > 0)
4908                 code = [[theEvent characters] characterAtIndex: 0];
4909               /*HACK: clear lone shift modifier to stop next if from firing */
4910               if (emacs_event->modifiers == shift_modifier)
4911                 emacs_event->modifiers = 0;
4912             }
4913           else
4914               emacs_event->modifiers |=
4915                 parse_solitary_modifier (ns_alternate_modifier);
4916         }
4918   if (NS_KEYLOG)
4919     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4920              code, fnKeysym, flags, emacs_event->modifiers);
4922       /* if it was a function key or had modifiers, pass it directly to emacs */
4923       if (fnKeysym || (emacs_event->modifiers
4924                        && (emacs_event->modifiers != shift_modifier)
4925                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4926 /*[[theEvent characters] length] */
4927         {
4928           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4929           if (code < 0x20)
4930             code |= (1<<28)|(3<<16);
4931           else if (code == 0x7f)
4932             code |= (1<<28)|(3<<16);
4933           else if (!fnKeysym)
4934             emacs_event->kind = code > 0xFF
4935               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4937           emacs_event->code = code;
4938           EV_TRAILER (theEvent);
4939           return;
4940         }
4941     }
4944 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4945   /* if we get here we should send the key for input manager processing */
4946   if (firstTime && [[NSInputManager currentInputManager]
4947                      wantsToDelayTextChangeNotifications] == NO)
4948     fprintf (stderr,
4949           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4950   firstTime = NO;
4951 #endif
4952   if (NS_KEYLOG && !processingCompose)
4953     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4955   processingCompose = YES;
4956   [nsEvArray addObject: theEvent];
4957   [self interpretKeyEvents: nsEvArray];
4958   [nsEvArray removeObject: theEvent];
4962 #ifdef NS_IMPL_COCOA
4963 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4964    decided not to send key-down for.
4965    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4966    This only applies on Tiger and earlier.
4967    If it matches one of these, send it on to keyDown. */
4968 -(void)keyUp: (NSEvent *)theEvent
4970   int flags = [theEvent modifierFlags];
4971   int code = [theEvent keyCode];
4972   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
4973       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4974     {
4975       if (NS_KEYLOG)
4976         fprintf (stderr, "keyUp: passed test");
4977       ns_fake_keydown = YES;
4978       [self keyDown: theEvent];
4979     }
4981 #endif
4984 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4987 /* <NSTextInput>: called when done composing;
4988    NOTE: also called when we delete over working text, followed immed.
4989          by doCommandBySelector: deleteBackward: */
4990 - (void)insertText: (id)aString
4992   int code;
4993   int len = [(NSString *)aString length];
4994   int i;
4996   if (NS_KEYLOG)
4997     NSLog (@"insertText '%@'\tlen = %d", aString, len);
4998   processingCompose = NO;
5000   if (!emacs_event)
5001     return;
5003   /* first, clear any working text */
5004   if (workingText != nil)
5005     [self deleteWorkingText];
5007   /* now insert the string as keystrokes */
5008   for (i =0; i<len; i++)
5009     {
5010       code = [aString characterAtIndex: i];
5011       /* TODO: still need this? */
5012       if (code == 0x2DC)
5013         code = '~'; /* 0x7E */
5014       emacs_event->modifiers = 0;
5015       emacs_event->kind
5016         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5017       emacs_event->code = code;
5018       EV_TRAILER ((id)nil);
5019     }
5023 /* <NSTextInput>: inserts display of composing characters */
5024 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5026   NSString *str = [aString respondsToSelector: @selector (string)] ?
5027     [aString string] : aString;
5028   if (NS_KEYLOG)
5029     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
5030            selRange.length, selRange.location);
5032   if (workingText != nil)
5033     [self deleteWorkingText];
5034   if ([str length] == 0)
5035     return;
5037   if (!emacs_event)
5038     return;
5040   processingCompose = YES;
5041   workingText = [str copy];
5042   ns_working_text = build_string ([workingText UTF8String]);
5044   emacs_event->kind = NS_TEXT_EVENT;
5045   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5046   EV_TRAILER ((id)nil);
5050 /* delete display of composing characters [not in <NSTextInput>] */
5051 - (void)deleteWorkingText
5053   if (workingText == nil)
5054     return;
5055   if (NS_KEYLOG)
5056     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
5057   [workingText release];
5058   workingText = nil;
5059   processingCompose = NO;
5061   if (!emacs_event)
5062     return;
5064   emacs_event->kind = NS_TEXT_EVENT;
5065   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5066   EV_TRAILER ((id)nil);
5070 - (BOOL)hasMarkedText
5072   return workingText != nil;
5076 - (NSRange)markedRange
5078   NSRange rng = workingText != nil
5079     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5080   if (NS_KEYLOG)
5081     NSLog (@"markedRange request");
5082   return rng;
5086 - (void)unmarkText
5088   if (NS_KEYLOG)
5089     NSLog (@"unmark (accept) text");
5090   [self deleteWorkingText];
5091   processingCompose = NO;
5095 /* used to position char selection windows, etc. */
5096 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5098   NSRect rect;
5099   NSPoint pt;
5100   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5101   if (NS_KEYLOG)
5102     NSLog (@"firstRectForCharRange request");
5104   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5105   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5106   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5107   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5108                                        +FRAME_LINE_HEIGHT (emacsframe));
5110   pt = [self convertPoint: pt toView: nil];
5111   pt = [[self window] convertBaseToScreen: pt];
5112   rect.origin = pt;
5113   return rect;
5117 - (long)conversationIdentifier
5119   return (long)self;
5123 - (void)doCommandBySelector: (SEL)aSelector
5125   if (NS_KEYLOG)
5126     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5128   if (aSelector == @selector (deleteBackward:))
5129     {
5130       /* happens when user backspaces over an ongoing composition:
5131          throw a 'delete' into the event queue */
5132       if (!emacs_event)
5133         return;
5134       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5135       emacs_event->code = 0xFF08;
5136       EV_TRAILER ((id)nil);
5137     }
5140 - (NSArray *)validAttributesForMarkedText
5142   static NSArray *arr = nil;
5143   if (arr == nil) arr = [NSArray new];
5144  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5145   return arr;
5148 - (NSRange)selectedRange
5150   if (NS_KEYLOG)
5151     NSLog (@"selectedRange request");
5152   return NSMakeRange (NSNotFound, 0);
5155 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5157   if (NS_KEYLOG)
5158     NSLog (@"characterIndexForPoint request");
5159   return 0;
5162 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5164   static NSAttributedString *str = nil;
5165   if (str == nil) str = [NSAttributedString new];
5166   if (NS_KEYLOG)
5167     NSLog (@"attributedSubstringFromRange request");
5168   return str;
5171 /* End <NSTextInput> impl. */
5172 /*****************************************************************************/
5175 /* This is what happens when the user presses a mouse button.  */
5176 - (void)mouseDown: (NSEvent *)theEvent
5178   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5179   Lisp_Object window;
5181   NSTRACE (mouseDown);
5183   [self deleteWorkingText];
5185   if (!emacs_event)
5186     return;
5188   last_mouse_frame = emacsframe;
5189   /* appears to be needed to prevent spurious movement events generated on
5190      button clicks */
5191   last_mouse_frame->mouse_moved = 0;
5193   if ([theEvent type] == NSScrollWheel)
5194     {
5195       float delta = [theEvent deltaY];
5196       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5197       if (delta == 0)
5198         return;
5199       emacs_event->kind = WHEEL_EVENT;
5200       emacs_event->code = 0;
5201       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5202         ((delta > 0) ? up_modifier : down_modifier);
5203     }
5204   else
5205     {
5206       emacs_event->kind = MOUSE_CLICK_EVENT;
5207       emacs_event->code = EV_BUTTON (theEvent);
5208       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5209                              | EV_UDMODIFIERS (theEvent);
5210     }
5211   XSETINT (emacs_event->x, lrint (p.x));
5212   XSETINT (emacs_event->y, lrint (p.y));
5213   EV_TRAILER (theEvent);
5217 - (void)rightMouseDown: (NSEvent *)theEvent
5219   NSTRACE (rightMouseDown);
5220   [self mouseDown: theEvent];
5224 - (void)otherMouseDown: (NSEvent *)theEvent
5226   NSTRACE (otherMouseDown);
5227   [self mouseDown: theEvent];
5231 - (void)mouseUp: (NSEvent *)theEvent
5233   NSTRACE (mouseUp);
5234   [self mouseDown: theEvent];
5238 - (void)rightMouseUp: (NSEvent *)theEvent
5240   NSTRACE (rightMouseUp);
5241   [self mouseDown: theEvent];
5245 - (void)otherMouseUp: (NSEvent *)theEvent
5247   NSTRACE (otherMouseUp);
5248   [self mouseDown: theEvent];
5252 - (void) scrollWheel: (NSEvent *)theEvent
5254   NSTRACE (scrollWheel);
5255   [self mouseDown: theEvent];
5259 /* Tell emacs the mouse has moved. */
5260 - (void)mouseMoved: (NSEvent *)e
5262   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5263   Lisp_Object frame;
5265 //  NSTRACE (mouseMoved);
5267   last_mouse_movement_time = EV_TIMESTAMP (e);
5268   last_mouse_motion_position
5269     = [self convertPoint: [e locationInWindow] fromView: nil];
5271   /* update any mouse face */
5272   if (hlinfo->mouse_face_hidden)
5273     {
5274       hlinfo->mouse_face_hidden = 0;
5275       clear_mouse_face (hlinfo);
5276     }
5278   /* tooltip handling */
5279   previous_help_echo_string = help_echo_string;
5280   help_echo_string = Qnil;
5282   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5283                             last_mouse_motion_position.y))
5284     help_echo_string = previous_help_echo_string;
5286   XSETFRAME (frame, emacsframe);
5287   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5288     {
5289       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5290          (note_mouse_highlight), which is called through the
5291          note_mouse_movement () call above */
5292       gen_help_event (help_echo_string, frame, help_echo_window,
5293                       help_echo_object, help_echo_pos);
5294     }
5295   else
5296     {
5297       help_echo_string = Qnil;
5298       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5299     }
5301   if (emacsframe->mouse_moved && send_appdefined)
5302     ns_send_appdefined (-1);
5306 - (void)mouseDragged: (NSEvent *)e
5308   NSTRACE (mouseDragged);
5309   [self mouseMoved: e];
5313 - (void)rightMouseDragged: (NSEvent *)e
5315   NSTRACE (rightMouseDragged);
5316   [self mouseMoved: e];
5320 - (void)otherMouseDragged: (NSEvent *)e
5322   NSTRACE (otherMouseDragged);
5323   [self mouseMoved: e];
5327 - (BOOL)windowShouldClose: (id)sender
5329   NSEvent *e =[[self window] currentEvent];
5331   NSTRACE (windowShouldClose);
5332   windowClosing = YES;
5333   if (!emacs_event)
5334     return NO;
5335   emacs_event->kind = DELETE_WINDOW_EVENT;
5336   emacs_event->modifiers = 0;
5337   emacs_event->code = 0;
5338   EV_TRAILER (e);
5339   /* Don't close this window, let this be done from lisp code.  */
5340   return NO;
5344 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5345 /* normalize frame to gridded text size */
5347   NSTRACE (windowWillResize);
5348 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5350   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5351 #ifdef NS_IMPL_GNUSTEP
5352                                         frameSize.width + 3);
5353 #else
5354                                         frameSize.width);
5355 #endif
5356   if (cols < MINWIDTH)
5357     cols = MINWIDTH;
5359   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
5360 #ifdef NS_IMPL_GNUSTEP
5361       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
5362         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5363 #else
5364       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5365         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5366 #endif
5367   if (rows < MINHEIGHT)
5368     rows = MINHEIGHT;
5369 #ifdef NS_IMPL_COCOA
5370   {
5371     /* this sets window title to have size in it; the wm does this under GS */
5372     NSRect r = [[self window] frame];
5373     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5374       {
5375         if (old_title != 0)
5376           {
5377             xfree (old_title);
5378             old_title = 0;
5379           }
5380       }
5381     else
5382       {
5383         char *size_title;
5384         NSWindow *window = [self window];
5385         if (old_title == 0)
5386           {
5387             const char *t = [[[self window] title] UTF8String];
5388             char *pos = strstr (t, "  â€”  ");
5389             if (pos)
5390               *pos = '\0';
5391             old_title = (char *) xmalloc (strlen (t) + 1);
5392             strcpy (old_title, t);
5393           }
5394         size_title = xmalloc (strlen (old_title) + 40);
5395         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5396         [window setTitle: [NSString stringWithUTF8String: size_title]];
5397         [window display];
5398         xfree (size_title);
5399       }
5400   }
5401 #endif /* NS_IMPL_COCOA */
5402 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5404   return frameSize;
5408 - (void)windowDidResize: (NSNotification *)notification
5410   NSWindow *theWindow = [notification object];
5412 #ifdef NS_IMPL_GNUSTEP
5413    /* in GNUstep, at least currently, it's possible to get a didResize
5414       without getting a willResize.. therefore we need to act as if we got
5415       the willResize now */
5416   NSSize sz = [theWindow frame].size;
5417   sz = [self windowWillResize: theWindow toSize: sz];
5418 #endif /* NS_IMPL_GNUSTEP */
5420   NSTRACE (windowDidResize);
5421 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5423 #ifdef NS_IMPL_COCOA
5424   if (old_title != 0)
5425     {
5426       xfree (old_title);
5427       old_title = 0;
5428     }
5429 #endif /* NS_IMPL_COCOA */
5431   /* Avoid loop under GNUstep due to call at beginning of this function.
5432      (x_set_window_size causes a resize which causes
5433      a "windowDidResize" which calls x_set_window_size).  */
5434 #ifndef NS_IMPL_GNUSTEP
5435   if (cols > 0 && rows > 0)
5436     {
5437       if (ns_in_resize)
5438         x_set_window_size (emacsframe, 0, cols, rows);
5439       else
5440         {
5441           NSWindow *window = [self window];
5442           NSRect wr = [window frame];
5443           FRAME_PIXEL_WIDTH (emacsframe) = (int)wr.size.width
5444             - emacsframe->border_width;
5445           FRAME_PIXEL_HEIGHT (emacsframe) = (int)wr.size.height
5446             - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5447             - FRAME_TOOLBAR_HEIGHT (emacsframe);
5448           change_frame_size (emacsframe, rows, cols, 0, 0, 1);
5449           SET_FRAME_GARBAGED (emacsframe);
5450           cancel_mouse_face (emacsframe);
5451         }
5452     }
5453 #endif
5455   ns_send_appdefined (-1);
5459 - (void)windowDidBecomeKey: (NSNotification *)notification
5460 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5462   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5463   struct frame *old_focus = dpyinfo->x_focus_frame;
5465   NSTRACE (windowDidBecomeKey);
5467   if (emacsframe != old_focus)
5468     dpyinfo->x_focus_frame = emacsframe;
5470   ns_frame_rehighlight (emacsframe);
5472   if (emacs_event)
5473     {
5474       emacs_event->kind = FOCUS_IN_EVENT;
5475       EV_TRAILER ((id)nil);
5476     }
5480 - (void)windowDidResignKey: (NSNotification *)notification
5481 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5483   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5484   NSTRACE (windowDidResignKey);
5486   if (dpyinfo->x_focus_frame == emacsframe)
5487     dpyinfo->x_focus_frame = 0;
5489   ns_frame_rehighlight (emacsframe);
5491   /* FIXME: for some reason needed on second and subsequent clicks away
5492             from sole-frame Emacs to get hollow box to show */
5493   if (!windowClosing && [[self window] isVisible] == YES)
5494     {
5495       x_update_cursor (emacsframe, 1);
5496       x_set_frame_alpha (emacsframe);
5497     }
5499   if (emacs_event)
5500     {
5501       [self deleteWorkingText];
5502       emacs_event->kind = FOCUS_IN_EVENT;
5503       EV_TRAILER ((id)nil);
5504     }
5508 - (void)windowWillMiniaturize: sender
5510   NSTRACE (windowWillMiniaturize);
5514 - (BOOL)isFlipped
5516   return YES;
5520 - (BOOL)isOpaque
5522   return NO;
5526 - initFrameFromEmacs: (struct frame *)f
5528   NSRect r, wr;
5529   Lisp_Object tem;
5530   NSWindow *win;
5531   NSButton *toggleButton;
5532   int vbextra = NS_SCROLL_BAR_WIDTH (f);
5533   NSSize sz;
5534   NSColor *col;
5535   NSString *name;
5537   NSTRACE (initFrameFromEmacs);
5539   windowClosing = NO;
5540   processingCompose = NO;
5541   scrollbarsNeedingUpdate = 0;
5543 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5545   ns_userRect = NSMakeRect (0, 0, 0, 0);
5546   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5547                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5548   [self initWithFrame: r];
5549   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5551   FRAME_NS_VIEW (f) = self;
5552   emacsframe = f;
5553   old_title = 0;
5555   win = [[EmacsWindow alloc]
5556             initWithContentRect: r
5557                       styleMask: (NSResizableWindowMask |
5558 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5559                                   NSTitledWindowMask |
5560 #endif
5561                                   NSMiniaturizableWindowMask |
5562                                   NSClosableWindowMask)
5563                         backing: NSBackingStoreBuffered
5564                           defer: YES];
5566   wr = [win frame];
5567   f->border_width = wr.size.width - r.size.width;
5568   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5570   [win setAcceptsMouseMovedEvents: YES];
5571   [win setDelegate: self];
5572   [win useOptimizedDrawing: YES];
5574   sz.width = FRAME_COLUMN_WIDTH (f);
5575   sz.height = FRAME_LINE_HEIGHT (f);
5576   [win setResizeIncrements: sz];
5578   [[win contentView] addSubview: self];
5580   if (ns_drag_types)
5581     [self registerForDraggedTypes: ns_drag_types];
5583   tem = f->name;
5584   name = [NSString stringWithUTF8String:
5585                    NILP (tem) ? (unsigned char *)"Emacs" : SDATA (tem)];
5586   [win setTitle: name];
5588   /* toolbar support */
5589   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5590                          [NSString stringWithFormat: @"Emacs Frame %d",
5591                                    ns_window_num]];
5592   [win setToolbar: toolbar];
5593   [toolbar setVisible: NO];
5594 #ifdef NS_IMPL_COCOA
5595   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5596   [toggleButton setTarget: self];
5597   [toggleButton setAction: @selector (toggleToolbar: )];
5598 #endif
5599   FRAME_TOOLBAR_HEIGHT (f) = 0;
5601   tem = f->icon_name;
5602   if (!NILP (tem))
5603     [win setMiniwindowTitle:
5604            [NSString stringWithUTF8String: SDATA (tem)]];
5606   {
5607     NSScreen *screen = [win screen];
5609     if (screen != 0)
5610       [win setFrameTopLeftPoint: NSMakePoint
5611            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5612             IN_BOUND (-SCREENMAX,
5613                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5614   }
5616   [win makeFirstResponder: self];
5618   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5619                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5620   [win setBackgroundColor: col];
5621   if ([col alphaComponent] != 1.0)
5622     [win setOpaque: NO];
5624   [self allocateGState];
5626   [NSApp registerServicesMenuSendTypes: ns_send_types
5627                            returnTypes: nil];
5629   ns_window_num++;
5630   return self;
5634 - (void)windowDidMove: sender
5636   NSWindow *win = [self window];
5637   NSRect r = [win frame];
5638   NSArray *screens = [NSScreen screens];
5639   NSScreen *screen = [screens objectAtIndex: 0];
5641   NSTRACE (windowDidMove);
5643   if (!emacsframe->output_data.ns)
5644     return;
5645   if (screen != nil)
5646     {
5647       emacsframe->left_pos = r.origin.x;
5648       emacsframe->top_pos =
5649         [screen frame].size.height - (r.origin.y + r.size.height);
5650     }
5654 /* Called AFTER method below, but before our windowWillResize call there leads
5655    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5656    location so set_window_size moves the frame. */
5657 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5659   emacsframe->output_data.ns->zooming = 1;
5660   return YES;
5664 /* Override to do something slightly nonstandard, but nice.  First click on
5665    zoom button will zoom vertically.  Second will zoom completely.  Third
5666    returns to original. */
5667 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5668                         defaultFrame:(NSRect)defaultFrame
5670   NSRect result = [sender frame];
5672   NSTRACE (windowWillUseStandardFrame);
5674   if (abs (defaultFrame.size.height - result.size.height)
5675       > FRAME_LINE_HEIGHT (emacsframe))
5676     {
5677       /* first click */
5678       ns_userRect = result;
5679       result.size.height = defaultFrame.size.height;
5680       result.origin.y = defaultFrame.origin.y;
5681     }
5682   else
5683     {
5684       if (abs (defaultFrame.size.width - result.size.width)
5685           > FRAME_COLUMN_WIDTH (emacsframe))
5686         result = defaultFrame;  /* second click */
5687       else
5688         {
5689           /* restore */
5690           result = ns_userRect.size.height ? ns_userRect : result;
5691           ns_userRect = NSMakeRect (0, 0, 0, 0);
5692         }
5693     }
5695   [self windowWillResize: sender toSize: result.size];
5696   return result;
5700 - (void)windowDidDeminiaturize: sender
5702   NSTRACE (windowDidDeminiaturize);
5703   if (!emacsframe->output_data.ns)
5704     return;
5705   emacsframe->async_iconified = 0;
5706   emacsframe->async_visible   = 1;
5707   windows_or_buffers_changed++;
5709   if (emacs_event)
5710     {
5711       emacs_event->kind = ICONIFY_EVENT;
5712       EV_TRAILER ((id)nil);
5713     }
5717 - (void)windowDidExpose: sender
5719   NSTRACE (windowDidExpose);
5720   if (!emacsframe->output_data.ns)
5721     return;
5722   emacsframe->async_visible = 1;
5723   SET_FRAME_GARBAGED (emacsframe);
5725   if (send_appdefined)
5726     ns_send_appdefined (-1);
5730 - (void)windowDidMiniaturize: sender
5732   NSTRACE (windowDidMiniaturize);
5733   if (!emacsframe->output_data.ns)
5734     return;
5736   emacsframe->async_iconified = 1;
5737   emacsframe->async_visible = 0;
5739   if (emacs_event)
5740     {
5741       emacs_event->kind = ICONIFY_EVENT;
5742       EV_TRAILER ((id)nil);
5743     }
5747 - (void)mouseEntered: (NSEvent *)theEvent
5749   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5750   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5751   NSTRACE (mouseEntered);
5753   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5757 - (void)mouseExited: (NSEvent *)theEvent
5759   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5760   NSRect r;
5761   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
5763   NSTRACE (mouseExited);
5765   if (!hlinfo)
5766     return;
5768   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5770   if (emacsframe == hlinfo->mouse_face_mouse_frame)
5771     {
5772       clear_mouse_face (hlinfo);
5773       hlinfo->mouse_face_mouse_frame = 0;
5774     }
5778 - menuDown: sender
5780   NSTRACE (menuDown);
5781   if (context_menu_value == -1)
5782     context_menu_value = [sender tag];
5783   else
5784     find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5785                                   emacsframe->menu_bar_vector,
5786                                   (void *)[sender tag]);
5787   ns_send_appdefined (-1);
5788   return self;
5792 - (EmacsToolbar *)toolbar
5794   return toolbar;
5798 /* this gets called on toolbar button click */
5799 - toolbarClicked: (id)item
5801   NSEvent *theEvent;
5802   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5804   NSTRACE (toolbarClicked);
5806   if (!emacs_event)
5807     return self;
5809   /* send first event (for some reason two needed) */
5810   theEvent = [[self window] currentEvent];
5811   emacs_event->kind = TOOL_BAR_EVENT;
5812   XSETFRAME (emacs_event->arg, emacsframe);
5813   EV_TRAILER (theEvent);
5815   emacs_event->kind = TOOL_BAR_EVENT;
5816 /*   XSETINT (emacs_event->code, 0); */
5817   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5818                           idx + TOOL_BAR_ITEM_KEY);
5819   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5820   EV_TRAILER (theEvent);
5821   return self;
5825 - toggleToolbar: (id)sender
5827   if (!emacs_event)
5828     return self;
5830   emacs_event->kind = NS_NONKEY_EVENT;
5831   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
5832   EV_TRAILER ((id)nil);
5833   return self;
5837 - (void)drawRect: (NSRect)rect
5839   int x = NSMinX (rect), y = NSMinY (rect);
5840   int width = NSWidth (rect), height = NSHeight (rect);
5842   NSTRACE (drawRect);
5844   if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
5845     return;
5847   ns_clear_frame_area (emacsframe, x, y, width, height);
5848   expose_frame (emacsframe, x, y, width, height);
5850   /*
5851     drawRect: may be called (at least in OS X 10.5) for invisible
5852     views as well for some reason.  Thus, do not infer visibility
5853     here.
5855     emacsframe->async_visible = 1;
5856     emacsframe->async_iconified = 0;
5857   */
5861 /* NSDraggingDestination protocol methods.  Actually this is not really a
5862    protocol, but a category of Object.  O well...  */
5864 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
5866   NSTRACE (draggingEntered);
5867   return NSDragOperationGeneric;
5871 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5873   return YES;
5877 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5879   id pb;
5880   int x, y;
5881   NSString *type;
5882   NSEvent *theEvent = [[self window] currentEvent];
5883   NSPoint position;
5885   NSTRACE (performDragOperation);
5887   if (!emacs_event)
5888     return NO;
5890   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5891   x = lrint (position.x);  y = lrint (position.y);
5893   pb = [sender draggingPasteboard];
5894   type = [pb availableTypeFromArray: ns_drag_types];
5895   if (type == 0)
5896     {
5897       return NO;
5898     }
5899   else if ([type isEqualToString: NSFilenamesPboardType])
5900     {
5901       NSArray *files;
5902       NSEnumerator *fenum;
5903       NSString *file;
5905       if (!(files = [pb propertyListForType: type]))
5906         return NO;
5908       fenum = [files objectEnumerator];
5909       while ( (file = [fenum nextObject]) )
5910         {
5911           emacs_event->kind = NS_NONKEY_EVENT;
5912           emacs_event->code = KEY_NS_DRAG_FILE;
5913           XSETINT (emacs_event->x, x);
5914           XSETINT (emacs_event->y, y);
5915           ns_input_file = append2 (ns_input_file,
5916                                    build_string ([file UTF8String]));
5917           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5918           EV_TRAILER (theEvent);
5919         }
5920       return YES;
5921     }
5922   else if ([type isEqualToString: NSURLPboardType])
5923     {
5924       NSString *file;
5925       NSURL *fileURL;
5927       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5928           [fileURL isFileURL] == NO)
5929         return NO;
5931       file = [fileURL path];
5932       emacs_event->kind = NS_NONKEY_EVENT;
5933       emacs_event->code = KEY_NS_DRAG_FILE;
5934       XSETINT (emacs_event->x, x);
5935       XSETINT (emacs_event->y, y);
5936       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5937       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5938       EV_TRAILER (theEvent);
5939       return YES;
5940     }
5941   else if ([type isEqualToString: NSStringPboardType]
5942            || [type isEqualToString: NSTabularTextPboardType])
5943     {
5944       NSString *data;
5946       if (! (data = [pb stringForType: type]))
5947         return NO;
5949       emacs_event->kind = NS_NONKEY_EVENT;
5950       emacs_event->code = KEY_NS_DRAG_TEXT;
5951       XSETINT (emacs_event->x, x);
5952       XSETINT (emacs_event->y, y);
5953       ns_input_text = build_string ([data UTF8String]);
5954       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5955       EV_TRAILER (theEvent);
5956       return YES;
5957     }
5958   else if ([type isEqualToString: NSColorPboardType])
5959     {
5960       NSColor *c = [NSColor colorFromPasteboard: pb];
5961       emacs_event->kind = NS_NONKEY_EVENT;
5962       emacs_event->code = KEY_NS_DRAG_COLOR;
5963       XSETINT (emacs_event->x, x);
5964       XSETINT (emacs_event->y, y);
5965       ns_input_color = ns_color_to_lisp (c);
5966       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5967       EV_TRAILER (theEvent);
5968       return YES;
5969     }
5970   else if ([type isEqualToString: NSFontPboardType])
5971     {
5972       /* impl based on GNUstep NSTextView.m */
5973       NSData *data = [pb dataForType: NSFontPboardType];
5974       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5975       NSFont *font = [dict objectForKey: NSFontAttributeName];
5976       char fontSize[10];
5978       if (font == nil)
5979         return NO;
5981       emacs_event->kind = NS_NONKEY_EVENT;
5982       emacs_event->code = KEY_NS_CHANGE_FONT;
5983       XSETINT (emacs_event->x, x);
5984       XSETINT (emacs_event->y, y);
5985       ns_input_font = build_string ([[font fontName] UTF8String]);
5986       snprintf (fontSize, 10, "%f", [font pointSize]);
5987       ns_input_fontsize = build_string (fontSize);
5988       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5989       EV_TRAILER (theEvent);
5990       return YES;
5991     }
5992   else
5993     {
5994       error ("Invalid data type in dragging pasteboard.");
5995       return NO;
5996     }
6000 - (id) validRequestorForSendType: (NSString *)typeSent
6001                       returnType: (NSString *)typeReturned
6003   NSTRACE (validRequestorForSendType);
6004   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6005       && typeReturned == nil)
6006     {
6007       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6008         return self;
6009     }
6011   return [super validRequestorForSendType: typeSent
6012                                returnType: typeReturned];
6016 /* The next two methods are part of NSServicesRequests informal protocol,
6017    supposedly called when a services menu item is chosen from this app.
6018    But this should not happen because we override the services menu with our
6019    own entries which call ns-perform-service.
6020    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6021    So let's at least stub them out until further investigation can be done. */
6023 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6025   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6026      be written into the buffer in place of the existing selection..
6027      ordinary service calls go through functions defined in ns-win.el */
6028   return NO;
6031 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6033   NSArray *typesDeclared;
6034   Lisp_Object val;
6036   /* We only support NSStringPboardType */
6037   if ([types containsObject:NSStringPboardType] == NO) {
6038     return NO;
6039   }
6041   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6042   if (CONSP (val) && SYMBOLP (XCAR (val)))
6043     {
6044       val = XCDR (val);
6045       if (CONSP (val) && NILP (XCDR (val)))
6046         val = XCAR (val);
6047     }
6048   if (! STRINGP (val))
6049     return NO;
6051   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6052   [pb declareTypes:typesDeclared owner:nil];
6053   ns_string_to_pasteboard (pb, val);
6054   return YES;
6058 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6059    (gives a miniaturized version of the window); currently we use the latter for
6060    frames whose active buffer doesn't correspond to any file
6061    (e.g., '*scratch*') */
6062 - setMiniwindowImage: (BOOL) setMini
6064   id image = [[self window] miniwindowImage];
6065   NSTRACE (setMiniwindowImage);
6067   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6068      about "AppleDockIconEnabled" notwithstanding, however the set message
6069      below has its effect nonetheless. */
6070   if (image != emacsframe->output_data.ns->miniimage)
6071     {
6072       if (image && [image isKindOfClass: [EmacsImage class]])
6073         [image release];
6074       [[self window] setMiniwindowImage:
6075                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6076     }
6078   return self;
6082 - (void) setRows: (int) r andColumns: (int) c
6084   rows = r;
6085   cols = c;
6088 @end  /* EmacsView */
6092 /* ==========================================================================
6094     EmacsWindow implementation
6096    ========================================================================== */
6098 @implementation EmacsWindow
6100 /* If we have multiple monitors, one above the other, we don't want to
6101    restrict the height to just one monitor.  So we override this.  */
6102 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6104   /* When making the frame visible for the first time or if there is just
6105      one screen, we want to constrain.  Other times not.  */
6106   NSUInteger nr_screens = [[NSScreen screens] count];
6107   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6108   NSTRACE (constrainFrameRect);
6110   if (nr_screens == 1)
6111     return [super constrainFrameRect:frameRect toScreen:screen];
6112   
6113   if (f->output_data.ns->dont_constrain
6114       || ns_menu_bar_should_be_hidden ())
6115     return frameRect;
6117   f->output_data.ns->dont_constrain = 1;
6118   return [super constrainFrameRect:frameRect toScreen:screen];
6122 /* called only on resize clicks by special case in EmacsApp-sendEvent */
6123 - (void)mouseDown: (NSEvent *)theEvent
6125   if (ns_in_resize)
6126     {
6127       NSSize size = [[theEvent window] frame].size;
6128       grabOffset = [theEvent locationInWindow];
6129       grabOffset.x = size.width - grabOffset.x;
6130     }
6131   else
6132     [super mouseDown: theEvent];
6136 /* stop resizing */
6137 - (void)mouseUp: (NSEvent *)theEvent
6139   if (ns_in_resize)
6140     {
6141       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6142       ns_in_resize = NO;
6143       ns_set_name_as_filename (f);
6144       [self display];
6145       ns_send_appdefined (-1);
6146     }
6147   else
6148     [super mouseUp: theEvent];
6152 /* send resize events */
6153 - (void)mouseDragged: (NSEvent *)theEvent
6155   if (ns_in_resize)
6156     {
6157       NSPoint p = [theEvent locationInWindow];
6158       NSSize size, vettedSize, origSize = [self frame].size;
6160       size.width = p.x + grabOffset.x;
6161       size.height = origSize.height - p.y + grabOffset.y;
6163       if (size.width == origSize.width && size.height == origSize.height)
6164         return;
6166       vettedSize = [[self delegate] windowWillResize: self toSize: size];
6167       [[NSNotificationCenter defaultCenter]
6168             postNotificationName: NSWindowDidResizeNotification
6169                           object: self];
6170     }
6171   else
6172     [super mouseDragged: theEvent];
6175 @end /* EmacsWindow */
6178 /* ==========================================================================
6180     EmacsScroller implementation
6182    ========================================================================== */
6185 @implementation EmacsScroller
6187 /* for repeat button push */
6188 #define SCROLL_BAR_FIRST_DELAY 0.5
6189 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6191 + (CGFloat) scrollerWidth
6193   /* TODO: if we want to allow variable widths, this is the place to do it,
6194            however neither GNUstep nor Cocoa support it very well */
6195   return [NSScroller scrollerWidth];
6199 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6201   NSTRACE (EmacsScroller_initFrame);
6203   r.size.width = [EmacsScroller scrollerWidth];
6204   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6205   [self setContinuous: YES];
6206   [self setEnabled: YES];
6208   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6209      locked against the top and bottom edges, and right edge on OS X, where
6210      scrollers are on right. */
6211 #ifdef NS_IMPL_GNUSTEP
6212   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6213 #else
6214   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6215 #endif
6217   win = nwin;
6218   condemned = NO;
6219   pixel_height = NSHeight (r);
6220   if (pixel_height == 0) pixel_height = 1;
6221   min_portion = 20 / pixel_height;
6223   frame = XFRAME (XWINDOW (win)->frame);
6224   if (FRAME_LIVE_P (frame))
6225     {
6226       int i;
6227       EmacsView *view = FRAME_NS_VIEW (frame);
6228       NSView *sview = [[view window] contentView];
6229       NSArray *subs = [sview subviews];
6231       /* disable optimization stopping redraw of other scrollbars */
6232       view->scrollbarsNeedingUpdate = 0;
6233       for (i =[subs count]-1; i >= 0; i--)
6234         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6235           view->scrollbarsNeedingUpdate++;
6236       [sview addSubview: self];
6237     }
6239 /*  [self setFrame: r]; */
6241   return self;
6245 - (void)setFrame: (NSRect)newRect
6247   NSTRACE (EmacsScroller_setFrame);
6248 /*  BLOCK_INPUT; */
6249   pixel_height = NSHeight (newRect);
6250   if (pixel_height == 0) pixel_height = 1;
6251   min_portion = 20 / pixel_height;
6252   [super setFrame: newRect];
6253   [self display];
6254 /*  UNBLOCK_INPUT; */
6258 - (void)dealloc
6260   NSTRACE (EmacsScroller_dealloc);
6261   if (!NILP (win))
6262     XWINDOW (win)->vertical_scroll_bar = Qnil;
6263   [super dealloc];
6267 - condemn
6269   NSTRACE (condemn);
6270   condemned =YES;
6271   return self;
6275 - reprieve
6277   NSTRACE (reprieve);
6278   condemned =NO;
6279   return self;
6283 - judge
6285   NSTRACE (judge);
6286   if (condemned)
6287     {
6288       EmacsView *view;
6289       BLOCK_INPUT;
6290       /* ensure other scrollbar updates after deletion */
6291       view = (EmacsView *)FRAME_NS_VIEW (frame);
6292       if (view != nil)
6293         view->scrollbarsNeedingUpdate++;
6294       [self removeFromSuperview];
6295       [self release];
6296       UNBLOCK_INPUT;
6297     }
6298   return self;
6302 - (void)resetCursorRects
6304   NSRect visible = [self visibleRect];
6305   NSTRACE (resetCursorRects);
6307   if (!NSIsEmptyRect (visible))
6308     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6309   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6313 - (int) checkSamePosition: (int) position portion: (int) portion
6314                     whole: (int) whole
6316   return em_position ==position && em_portion ==portion && em_whole ==whole
6317     && portion != whole; /* needed for resize empty buf */
6321 - setPosition: (int)position portion: (int)portion whole: (int)whole
6323   NSTRACE (setPosition);
6325   em_position = position;
6326   em_portion = portion;
6327   em_whole = whole;
6329   if (portion >= whole)
6330     {
6331 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6332       [self setKnobProportion: 1.0];
6333       [self setDoubleValue: 1.0];
6334 #else
6335       [self setFloatValue: 0.0 knobProportion: 1.0];
6336 #endif
6337     }
6338   else
6339     {
6340       float pos, por;
6341       portion = max ((float)whole*min_portion/pixel_height, portion);
6342       pos = (float)position / (whole - portion);
6343       por = (float)portion/whole;
6344 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6345       [self setKnobProportion: por];
6346       [self setDoubleValue: pos];
6347 #else
6348       [self setFloatValue: pos knobProportion: por];
6349 #endif
6350     }
6351   return self;
6354 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6355      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6356 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6357                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6359   *part = last_hit_part;
6360   *window = win;
6361   XSETINT (*y, pixel_height);
6362   if ([self floatValue] > 0.999)
6363     XSETINT (*x, pixel_height);
6364   else
6365     XSETINT (*x, pixel_height * [self floatValue]);
6369 /* set up emacs_event */
6370 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6372   if (!emacs_event)
6373     return;
6375   emacs_event->part = last_hit_part;
6376   emacs_event->code = 0;
6377   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6378   emacs_event->frame_or_window = win;
6379   emacs_event->timestamp = EV_TIMESTAMP (e);
6380   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6381   emacs_event->arg = Qnil;
6382   XSETINT (emacs_event->x, loc * pixel_height);
6383   XSETINT (emacs_event->y, pixel_height-20);
6385   n_emacs_events_pending++;
6386   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6387   EVENT_INIT (*emacs_event);
6388   ns_send_appdefined (-1);
6392 /* called manually thru timer to implement repeated button action w/hold-down */
6393 - repeatScroll: (NSTimer *)scrollEntry
6395   NSEvent *e = [[self window] currentEvent];
6396   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6397   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6399   /* clear timer if need be */
6400   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6401     {
6402         [scroll_repeat_entry invalidate];
6403         [scroll_repeat_entry release];
6404         scroll_repeat_entry = nil;
6406         if (inKnob)
6407           return self;
6409         scroll_repeat_entry
6410           = [[NSTimer scheduledTimerWithTimeInterval:
6411                         SCROLL_BAR_CONTINUOUS_DELAY
6412                                             target: self
6413                                           selector: @selector (repeatScroll:)
6414                                           userInfo: 0
6415                                            repeats: YES]
6416               retain];
6417     }
6419   [self sendScrollEventAtLoc: 0 fromEvent: e];
6420   return self;
6424 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6425    mouseDragged events without going into a modal loop. */
6426 - (void)mouseDown: (NSEvent *)e
6428   NSRect sr, kr;
6429   /* hitPart is only updated AFTER event is passed on */
6430   NSScrollerPart part = [self testPart: [e locationInWindow]];
6431   double inc = 0.0, loc, kloc, pos;
6432   int edge = 0;
6434   NSTRACE (EmacsScroller_mouseDown);
6436   switch (part)
6437     {
6438     case NSScrollerDecrementPage:
6439         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6440     case NSScrollerIncrementPage:
6441         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6442     case NSScrollerDecrementLine:
6443       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6444     case NSScrollerIncrementLine:
6445       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6446     case NSScrollerKnob:
6447       last_hit_part = scroll_bar_handle; break;
6448     case NSScrollerKnobSlot:  /* GNUstep-only */
6449       last_hit_part = scroll_bar_move_ratio; break;
6450     default:  /* NSScrollerNoPart? */
6451       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6452                (long) part);
6453       return;
6454     }
6456   if (inc != 0.0)
6457     {
6458       pos = 0;      /* ignored */
6460       /* set a timer to repeat, as we can't let superclass do this modally */
6461       scroll_repeat_entry
6462         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6463                                             target: self
6464                                           selector: @selector (repeatScroll:)
6465                                           userInfo: 0
6466                                            repeats: YES]
6467             retain];
6468     }
6469   else
6470     {
6471       /* handle, or on GNUstep possibly slot */
6472       NSEvent *fake_event;
6474       /* compute float loc in slot and mouse offset on knob */
6475       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6476                       toView: nil];
6477       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6478       if (loc <= 0.0)
6479         {
6480           loc = 0.0;
6481           edge = -1;
6482         }
6483       else if (loc >= NSHeight (sr))
6484         {
6485           loc = NSHeight (sr);
6486           edge = 1;
6487         }
6489       if (edge)
6490         kloc = 0.5 * edge;
6491       else
6492         {
6493           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6494                           toView: nil];
6495           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6496         }
6497       last_mouse_offset = kloc;
6499       /* if knob, tell emacs a location offset by knob pos
6500          (to indicate top of handle) */
6501       if (part == NSScrollerKnob)
6502           pos = (loc - last_mouse_offset) / NSHeight (sr);
6503       else
6504         /* else this is a slot click on GNUstep: go straight there */
6505         pos = loc / NSHeight (sr);
6507       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6508       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6509                                       location: [e locationInWindow]
6510                                  modifierFlags: [e modifierFlags]
6511                                      timestamp: [e timestamp]
6512                                   windowNumber: [e windowNumber]
6513                                        context: [e context]
6514                                    eventNumber: [e eventNumber]
6515                                     clickCount: [e clickCount]
6516                                       pressure: [e pressure]];
6517       [super mouseUp: fake_event];
6518     }
6520   if (part != NSScrollerKnob)
6521     [self sendScrollEventAtLoc: pos fromEvent: e];
6525 /* Called as we manually track scroller drags, rather than superclass. */
6526 - (void)mouseDragged: (NSEvent *)e
6528     NSRect sr;
6529     double loc, pos;
6530     int edge = 0;
6532     NSTRACE (EmacsScroller_mouseDragged);
6534       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6535                       toView: nil];
6536       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6538       if (loc <= 0.0)
6539         {
6540           loc = 0.0;
6541           edge = -1;
6542         }
6543       else if (loc >= NSHeight (sr) + last_mouse_offset)
6544         {
6545           loc = NSHeight (sr) + last_mouse_offset;
6546           edge = 1;
6547         }
6549       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6550       [self sendScrollEventAtLoc: pos fromEvent: e];
6554 - (void)mouseUp: (NSEvent *)e
6556   if (scroll_repeat_entry)
6557     {
6558       [scroll_repeat_entry invalidate];
6559       [scroll_repeat_entry release];
6560       scroll_repeat_entry = nil;
6561     }
6562   last_hit_part = 0;
6566 /* treat scrollwheel events in the bar as though they were in the main window */
6567 - (void) scrollWheel: (NSEvent *)theEvent
6569   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6570   [view mouseDown: theEvent];
6573 @end  /* EmacsScroller */
6578 /* ==========================================================================
6580    Font-related functions; these used to be in nsfaces.m
6582    ========================================================================== */
6585 Lisp_Object
6586 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6588   struct font *font = XFONT_OBJECT (font_object);
6590   if (fontset < 0)
6591     fontset = fontset_from_font (font_object);
6592   FRAME_FONTSET (f) = fontset;
6594   if (FRAME_FONT (f) == font)
6595     /* This font is already set in frame F.  There's nothing more to
6596        do.  */
6597     return font_object;
6599   FRAME_FONT (f) = font;
6601   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6602   FRAME_COLUMN_WIDTH (f) = font->average_width;
6603   FRAME_SPACE_WIDTH (f) = font->space_width;
6604   FRAME_LINE_HEIGHT (f) = font->height;
6606   compute_fringe_widths (f, 1);
6608   /* Compute the scroll bar width in character columns.  */
6609   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6610     {
6611       int wid = FRAME_COLUMN_WIDTH (f);
6612       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6613         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6614     }
6615   else
6616     {
6617       int wid = FRAME_COLUMN_WIDTH (f);
6618       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6619     }
6621   /* Now make the frame display the given font.  */
6622   if (FRAME_NS_WINDOW (f) != 0)
6623         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6625   return font_object;
6629 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6630 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6631          in 1.43. */
6633 const char *
6634 ns_xlfd_to_fontname (const char *xlfd)
6635 /* --------------------------------------------------------------------------
6636     Convert an X font name (XLFD) to an NS font name.
6637     Only family is used.
6638     The string returned is temporarily allocated.
6639    -------------------------------------------------------------------------- */
6641   char *name = xmalloc (180);
6642   int i, len;
6643   const char *ret;
6645   if (!strncmp (xlfd, "--", 2))
6646     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6647   else
6648     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6650   /* stopgap for malformed XLFD input */
6651   if (strlen (name) == 0)
6652     strcpy (name, "Monaco");
6654   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6655      also uppercase after '-' or ' ' */
6656   name[0] = toupper (name[0]);
6657   for (len =strlen (name), i =0; i<len; i++)
6658     {
6659       if (name[i] == '$')
6660         {
6661           name[i] = '-';
6662           if (i+1<len)
6663             name[i+1] = toupper (name[i+1]);
6664         }
6665       else if (name[i] == '_')
6666         {
6667           name[i] = ' ';
6668           if (i+1<len)
6669             name[i+1] = toupper (name[i+1]);
6670         }
6671     }
6672 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6673   ret = [[NSString stringWithUTF8String: name] UTF8String];
6674   xfree (name);
6675   return ret;
6679 void
6680 syms_of_nsterm (void)
6682   NSTRACE (syms_of_nsterm);
6684   ns_antialias_threshold = 10.0;
6686   /* from 23+ we need to tell emacs what modifiers there are.. */
6687   DEFSYM (Qmodifier_value, "modifier-value");
6688   DEFSYM (Qalt, "alt");
6689   DEFSYM (Qhyper, "hyper");
6690   DEFSYM (Qmeta, "meta");
6691   DEFSYM (Qsuper, "super");
6692   DEFSYM (Qcontrol, "control");
6693   DEFSYM (Qnone, "none");
6694   DEFSYM (QUTF8_STRING, "UTF8_STRING");
6696   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6697   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6698   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6699   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6700   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6702   DEFVAR_LISP ("ns-input-file", ns_input_file,
6703               "The file specified in the last NS event.");
6704   ns_input_file =Qnil;
6706   DEFVAR_LISP ("ns-input-text", ns_input_text,
6707               "The data received in the last NS text drag event.");
6708   ns_input_text =Qnil;
6710   DEFVAR_LISP ("ns-working-text", ns_working_text,
6711               "String for visualizing working composition sequence.");
6712   ns_working_text =Qnil;
6714   DEFVAR_LISP ("ns-input-font", ns_input_font,
6715               "The font specified in the last NS event.");
6716   ns_input_font =Qnil;
6718   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
6719               "The fontsize specified in the last NS event.");
6720   ns_input_fontsize =Qnil;
6722   DEFVAR_LISP ("ns-input-line", ns_input_line,
6723                "The line specified in the last NS event.");
6724   ns_input_line =Qnil;
6726   DEFVAR_LISP ("ns-input-color", ns_input_color,
6727                "The color specified in the last NS event.");
6728   ns_input_color =Qnil;
6730   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
6731                "The service name specified in the last NS event.");
6732   ns_input_spi_name =Qnil;
6734   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
6735                "The service argument specified in the last NS event.");
6736   ns_input_spi_arg =Qnil;
6738   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
6739                "This variable describes the behavior of the alternate or option key.\n\
6740 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6741 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6742 at all, allowing it to be used at a lower level for accented character entry.");
6743   ns_alternate_modifier = Qmeta;
6745   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
6746                "This variable describes the behavior of the right alternate or option key.\n\
6747 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6748 Set to left means be the same key as `ns-alternate-modifier'.\n\
6749 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6750 at all, allowing it to be used at a lower level for accented character entry.");
6751   ns_right_alternate_modifier = Qleft;
6753   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
6754                "This variable describes the behavior of the command key.\n\
6755 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6756   ns_command_modifier = Qsuper;
6758   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
6759                "This variable describes the behavior of the right command key.\n\
6760 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6761 Set to left means be the same key as `ns-command-modifier'.\n\
6762 Set to none means that the command / option key is not interpreted by Emacs\n\
6763 at all, allowing it to be used at a lower level for accented character entry.");
6764   ns_right_command_modifier = Qleft;
6766   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
6767                "This variable describes the behavior of the control key.\n\
6768 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6769   ns_control_modifier = Qcontrol;
6771   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
6772                "This variable describes the behavior of the right control key.\n\
6773 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6774 Set to left means be the same key as `ns-control-modifier'.\n\
6775 Set to none means that the control / option key is not interpreted by Emacs\n\
6776 at all, allowing it to be used at a lower level for accented character entry.");
6777   ns_right_control_modifier = Qleft;
6779   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
6780                "This variable describes the behavior of the function key (on laptops).\n\
6781 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6782 Set to none means that the function key is not interpreted by Emacs at all,\n\
6783 allowing it to be used at a lower level for accented character entry.");
6784   ns_function_modifier = Qnone;
6786   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
6787                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6788   ns_antialias_text = Qt;
6790   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
6791                "Whether to confirm application quit using dialog.");
6792   ns_confirm_quit = Qnil;
6794   staticpro (&ns_display_name_list);
6795   ns_display_name_list = Qnil;
6797   staticpro (&last_mouse_motion_frame);
6798   last_mouse_motion_frame = Qnil;
6800   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
6801                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
6802 Only works on OSX 10.6 or later.  */);
6803   ns_auto_hide_menu_bar = Qnil;
6805   /* TODO: move to common code */
6806   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
6807                doc: /* Which toolkit scroll bars Emacs uses, if any.
6808 A value of nil means Emacs doesn't use toolkit scroll bars.
6809 With the X Window system, the value is a symbol describing the
6810 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
6811 With MS Windows or Nextstep, the value is t.  */);
6812   Vx_toolkit_scroll_bars = Qt;
6814   DEFVAR_BOOL ("x-use-underline-position-properties",
6815                x_use_underline_position_properties,
6816      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
6817 A value of nil means ignore them.  If you encounter fonts with bogus
6818 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6819 to 4.1, set this to nil. */);
6820   x_use_underline_position_properties = 0;
6822   DEFVAR_BOOL ("x-underline-at-descent-line",
6823                x_underline_at_descent_line,
6824      doc: /* Non-nil means to draw the underline at the same place as the descent line.
6825 A value of nil means to draw the underline according to the value of the
6826 variable `x-use-underline-position-properties', which is usually at the
6827 baseline level.  The default value is nil.  */);
6828   x_underline_at_descent_line = 0;
6830   /* Tell emacs about this window system. */
6831   Fprovide (intern ("ns"), Qnil);