Merge from emacs-24; up to 2012-04-24T21:47:24Z!michael.albinus@gmx.de
[emacs.git] / src / nsterm.m
blob8bd2bb283b29b08482afc47f6eaa809382a76a82
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   xfree (f->output_data.ns);
1160   if (f->output_data.ns->miniimage != nil)
1161     [f->output_data.ns->miniimage release];
1163   [[view window] close];
1164   [view release];
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 void
2599 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2600                          NSColor *defaultCol, CGFloat width, CGFloat x)
2601 /* --------------------------------------------------------------------------
2602    Draw underline, overline, and strike-through on glyph string s.
2603    -------------------------------------------------------------------------- */
2605   if (s->for_overlaps)
2606     return;
2608   /* Do underline. */
2609   if (face->underline_p)
2610     {
2611       NSRect r;
2612       unsigned long thickness, position;
2614       /* If the prev was underlined, match its appearance. */
2615       if (s->prev && s->prev->face->underline_p
2616           && s->prev->underline_thickness > 0)
2617         {
2618           thickness = s->prev->underline_thickness;
2619           position = s->prev->underline_position;
2620         }
2621       else
2622         {
2623           struct font *font;
2624           unsigned long descent;
2626           font=s->font;
2627           descent = s->y + s->height - s->ybase;
2629           /* Use underline thickness of font, defaulting to 1. */
2630           thickness = (font && font->underline_thickness > 0)
2631             ? font->underline_thickness : 1;
2633           /* Determine the offset of underlining from the baseline. */
2634           if (x_underline_at_descent_line)
2635             position = descent - thickness;
2636           else if (x_use_underline_position_properties
2637                    && font && font->underline_position >= 0)
2638             position = font->underline_position;
2639           else if (font)
2640             position = lround (font->descent / 2);
2641           else
2642             position = underline_minimum_offset;
2644           position = max (position, underline_minimum_offset);
2646           /* Ensure underlining is not cropped. */
2647           if (descent <= position)
2648             {
2649               position = descent - 1;
2650               thickness = 1;
2651             }
2652           else if (descent < position + thickness)
2653             thickness = 1;
2654         }
2656       s->underline_thickness = thickness;
2657       s->underline_position = position;
2659       r = NSMakeRect (x, s->ybase + position, width, thickness);
2661       if (face->underline_defaulted_p)
2662         [defaultCol set];
2663       else
2664         [ns_lookup_indexed_color (face->underline_color, s->f) set];
2665       NSRectFill (r);
2666     }
2668   /* Do overline. We follow other terms in using a thickness of 1
2669      and ignoring overline_margin. */
2670   if (face->overline_p)
2671     {
2672       NSRect r;
2673       r = NSMakeRect (x, s->y, width, 1);
2675       if (face->overline_color_defaulted_p)
2676         [defaultCol set];
2677       else
2678         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2679       NSRectFill (r);
2680     }
2682   /* Do strike-through.  We follow other terms for thickness and
2683      vertical position.*/
2684   if (face->strike_through_p)
2685     {
2686       NSRect r;
2687       unsigned long dy;
2689       dy = lrint ((s->height - 1) / 2);
2690       r = NSMakeRect (x, s->y + dy, width, 1);
2692       if (face->strike_through_color_defaulted_p)
2693         [defaultCol set];
2694       else
2695         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2696       NSRectFill (r);
2697     }
2700 static void
2701 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2702 /* --------------------------------------------------------------------------
2703     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2704     Note we can't just use an NSDrawRect command, because of the possibility
2705     of some sides not being drawn, and because the rect will be filled.
2706    -------------------------------------------------------------------------- */
2708   NSRect s = r;
2709   [col set];
2711   /* top, bottom */
2712   s.size.height = thickness;
2713   NSRectFill (s);
2714   s.origin.y += r.size.height - thickness;
2715   NSRectFill (s);
2717   s.size.height = r.size.height;
2718   s.origin.y = r.origin.y;
2720   /* left, right (optional) */
2721   s.size.width = thickness;
2722   if (left_p)
2723     NSRectFill (s);
2724   if (right_p)
2725     {
2726       s.origin.x += r.size.width - thickness;
2727       NSRectFill (s);
2728     }
2732 static void
2733 ns_draw_relief (NSRect r, int thickness, char raised_p,
2734                char top_p, char bottom_p, char left_p, char right_p,
2735                struct glyph_string *s)
2736 /* --------------------------------------------------------------------------
2737     Draw a relief rect inside r, optionally leaving some sides open.
2738     Note we can't just use an NSDrawBezel command, because of the possibility
2739     of some sides not being drawn, and because the rect will be filled.
2740    -------------------------------------------------------------------------- */
2742   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2743   NSColor *newBaseCol = nil;
2744   NSRect sr = r;
2746   NSTRACE (ns_draw_relief);
2748   /* set up colors */
2750   if (s->face->use_box_color_for_shadows_p)
2751     {
2752       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2753     }
2754 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2755            && s->img->pixmap
2756            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2757        {
2758          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2759        } */
2760   else
2761     {
2762       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2763     }
2765   if (newBaseCol == nil)
2766     newBaseCol = [NSColor grayColor];
2768   if (newBaseCol != baseCol)  /* TODO: better check */
2769     {
2770       [baseCol release];
2771       baseCol = [newBaseCol retain];
2772       [lightCol release];
2773       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2774       [darkCol release];
2775       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2776     }
2778   [(raised_p ? lightCol : darkCol) set];
2780   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2782   /* top */
2783   sr.size.height = thickness;
2784   if (top_p) NSRectFill (sr);
2786   /* left */
2787   sr.size.height = r.size.height;
2788   sr.size.width = thickness;
2789   if (left_p) NSRectFill (sr);
2791   [(raised_p ? darkCol : lightCol) set];
2793   /* bottom */
2794   sr.size.width = r.size.width;
2795   sr.size.height = thickness;
2796   sr.origin.y += r.size.height - thickness;
2797   if (bottom_p) NSRectFill (sr);
2799   /* right */
2800   sr.size.height = r.size.height;
2801   sr.origin.y = r.origin.y;
2802   sr.size.width = thickness;
2803   sr.origin.x += r.size.width - thickness;
2804   if (right_p) NSRectFill (sr);
2808 static void
2809 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2810 /* --------------------------------------------------------------------------
2811       Function modeled after x_draw_glyph_string_box ().
2812       Sets up parameters for drawing.
2813    -------------------------------------------------------------------------- */
2815   int right_x, last_x;
2816   char left_p, right_p;
2817   struct glyph *last_glyph;
2818   NSRect r;
2819   int thickness;
2820   struct face *face;
2822   if (s->hl == DRAW_MOUSE_FACE)
2823     {
2824       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2825       if (!face)
2826         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2827     }
2828   else
2829     face = s->face;
2831   thickness = face->box_line_width;
2833   NSTRACE (ns_dumpglyphs_box_or_relief);
2835   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2836             ? WINDOW_RIGHT_EDGE_X (s->w)
2837             : window_box_right (s->w, s->area));
2838   last_glyph = (s->cmp || s->img
2839                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2841   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2842               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2844   left_p = (s->first_glyph->left_box_line_p
2845             || (s->hl == DRAW_MOUSE_FACE
2846                 && (s->prev == NULL || s->prev->hl != s->hl)));
2847   right_p = (last_glyph->right_box_line_p
2848              || (s->hl == DRAW_MOUSE_FACE
2849                  && (s->next == NULL || s->next->hl != s->hl)));
2851   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2853   /* expand full-width row over internal borders */
2854   if (s->row->full_width_p)
2855     r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2856                         FRAME_PIXEL_WIDTH (s->f));
2858   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2859   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2860     {
2861       ns_draw_box (r, abs (thickness),
2862                    ns_lookup_indexed_color (face->box_color, s->f),
2863                   left_p, right_p);
2864     }
2865   else
2866     {
2867       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2868                      1, 1, left_p, right_p, s);
2869     }
2873 static void
2874 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2875 /* --------------------------------------------------------------------------
2876       Modeled after x_draw_glyph_string_background, which draws BG in
2877       certain cases.  Others are left to the text rendering routine.
2878    -------------------------------------------------------------------------- */
2880   NSTRACE (ns_maybe_dumpglyphs_background);
2882   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2883     {
2884       int box_line_width = max (s->face->box_line_width, 0);
2885       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2886           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2887         {
2888           struct face *face;
2889           if (s->hl == DRAW_MOUSE_FACE)
2890             {
2891               face = FACE_FROM_ID (s->f,
2892                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2893               if (!face)
2894                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2895             }
2896           else
2897             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2898           if (!face->stipple)
2899             [(NS_FACE_BACKGROUND (face) != 0
2900               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2901               : FRAME_BACKGROUND_COLOR (s->f)) set];
2902           else
2903             {
2904               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2905               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2906             }
2908           if (s->hl != DRAW_CURSOR)
2909             {
2910               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2911                                     s->background_width,
2912                                     s->height-2*box_line_width);
2914               /* expand full-width row over internal borders */
2915               if (s->row->full_width_p)
2916                 {
2917                   int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2918                   if (r.origin.y <= fibw+1 + box_line_width)
2919                     {
2920                       r.size.height += r.origin.y;
2921                       r.origin.y = 0;
2922                     }
2923                   if (r.origin.x <= fibw+1)
2924                     {
2925                       r.size.width += 2*r.origin.x;
2926                       r.origin.x = 0;
2927                     }
2928                   if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2929                       <= fibw+1)
2930                     r.size.width += fibw;
2931                 }
2933               NSRectFill (r);
2934             }
2936           s->background_filled_p = 1;
2937         }
2938     }
2942 static void
2943 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2944 /* --------------------------------------------------------------------------
2945       Renders an image and associated borders.
2946    -------------------------------------------------------------------------- */
2948   EmacsImage *img = s->img->pixmap;
2949   int box_line_vwidth = max (s->face->box_line_width, 0);
2950   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2951   int bg_x, bg_y, bg_height;
2952   int th;
2953   char raised_p;
2954   NSRect br;
2955   struct face *face;
2956   NSColor *tdCol;
2958   NSTRACE (ns_dumpglyphs_image);
2960   if (s->face->box != FACE_NO_BOX
2961       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2962     x += abs (s->face->box_line_width);
2964   bg_x = x;
2965   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2966   bg_height = s->height;
2967   /* other terms have this, but was causing problems w/tabbar mode */
2968   /* - 2 * box_line_vwidth; */
2970   if (s->slice.x == 0) x += s->img->hmargin;
2971   if (s->slice.y == 0) y += s->img->vmargin;
2973   /* Draw BG: if we need larger area than image itself cleared, do that,
2974      otherwise, since we composite the image under NS (instead of mucking
2975      with its background color), we must clear just the image area. */
2976   if (s->hl == DRAW_MOUSE_FACE)
2977     {
2978       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2979       if (!face)
2980        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2981     }
2982   else
2983     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2985   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2987   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2988       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2989     {
2990       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2991       s->background_filled_p = 1;
2992     }
2993   else
2994     {
2995       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2996     }
2998   /* expand full-width row over internal borders */
2999   if (s->row->full_width_p)
3000     {
3001       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
3002       if (br.origin.y <= fibw+1 + box_line_vwidth)
3003         {
3004           br.size.height += br.origin.y;
3005           br.origin.y = 0;
3006         }
3007       if (br.origin.x <= fibw+1 + box_line_vwidth)
3008         {
3009           br.size.width += br.origin.x;
3010           br.origin.x = 0;
3011         }
3012       if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
3013         br.size.width += fibw;
3014     }
3016   NSRectFill (br);
3018   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3019   if (img != nil)
3020     [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3021                 operation: NSCompositeSourceOver];
3023   if (s->hl == DRAW_CURSOR)
3024     {
3025     [FRAME_CURSOR_COLOR (s->f) set];
3026     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3027       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3028     else
3029       /* Currently on NS img->mask is always 0. Since
3030          get_window_cursor_type specifies a hollow box cursor when on
3031          a non-masked image we never reach this clause. But we put it
3032          in in anticipation of better support for image masks on
3033          NS. */
3034       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3035     }
3036   else
3037     {
3038       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3039     }
3041   /* Draw underline, overline, strike-through. */
3042   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3044   /* Draw relief, if requested */
3045   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3046     {
3047       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3048         {
3049           th = tool_bar_button_relief >= 0 ?
3050             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3051           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3052         }
3053       else
3054         {
3055           th = abs (s->img->relief);
3056           raised_p = (s->img->relief > 0);
3057         }
3059       r.origin.x = x - th;
3060       r.origin.y = y - th;
3061       r.size.width = s->slice.width + 2*th-1;
3062       r.size.height = s->slice.height + 2*th-1;
3063       ns_draw_relief (r, th, raised_p,
3064                       s->slice.y == 0,
3065                       s->slice.y + s->slice.height == s->img->height,
3066                       s->slice.x == 0,
3067                       s->slice.x + s->slice.width == s->img->width, s);
3068     }
3070   /* If there is no mask, the background won't be seen,
3071      so draw a rectangle on the image for the cursor.
3072      Do this for all images, getting transparency right is not reliable.  */
3073   if (s->hl == DRAW_CURSOR)
3074     {
3075       int thickness = abs (s->img->relief);
3076       if (thickness == 0) thickness = 1;
3077       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3078     }
3082 static void
3083 ns_dumpglyphs_stretch (struct glyph_string *s)
3085   NSRect r[2];
3086   int n, i;
3087   struct face *face;
3088   NSColor *fgCol, *bgCol;
3090   if (!s->background_filled_p)
3091     {
3092       n = ns_get_glyph_string_clip_rect (s, r);
3093       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3095       ns_focus (s->f, r, n);
3097       if (s->hl == DRAW_MOUSE_FACE)
3098        {
3099          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3100          if (!face)
3101            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3102        }
3103       else
3104        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3106       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3107       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3109       for (i=0; i<n; i++)
3110         {
3111           if (!s->row->full_width_p)
3112             {
3113               int overrun, leftoverrun;
3115               /* truncate to avoid overwriting fringe and/or scrollbar */
3116               overrun = max (0, (s->x + s->background_width)
3117                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3118                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3119               r[i].size.width -= overrun;
3121               /* truncate to avoid overwriting to left of the window box */
3122               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3123                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3125               if (leftoverrun > 0)
3126                 {
3127                   r[i].origin.x += leftoverrun;
3128                   r[i].size.width -= leftoverrun;
3129                 }
3131               /* XXX: Try to work between problem where a stretch glyph on
3132                  a partially-visible bottom row will clear part of the
3133                  modeline, and another where list-buffers headers and similar
3134                  rows erroneously have visible_height set to 0.  Not sure
3135                  where this is coming from as other terms seem not to show. */
3136               r[i].size.height = min (s->height, s->row->visible_height);
3137             }
3139           /* expand full-width rows over internal borders */
3140           else
3141             {
3142               r[i] = ns_fix_rect_ibw (r[i], FRAME_INTERNAL_BORDER_WIDTH (s->f),
3143                                       FRAME_PIXEL_WIDTH (s->f));
3144             }
3146           [bgCol set];
3148           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3149              overwriting cursor (usually when cursor on a tab) */
3150           if (s->hl == DRAW_CURSOR)
3151             {
3152               CGFloat x, width;
3154               x = r[i].origin.x;
3155               width = s->w->phys_cursor_width;
3156               r[i].size.width -= width;
3157               r[i].origin.x += width;
3159               NSRectFill (r[i]);
3161               /* Draw overlining, etc. on the cursor. */
3162               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3163                 ns_draw_text_decoration (s, face, bgCol, width, x);
3164               else
3165                 ns_draw_text_decoration (s, face, fgCol, width, x);
3166             }
3167           else
3168             {
3169               NSRectFill (r[i]);
3170             }
3172           /* Draw overlining, etc. on the stretch glyph (or the part
3173              of the stretch glyph after the cursor). */
3174           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3175                                    r[i].origin.x);
3176         }
3177       ns_unfocus (s->f);
3178       s->background_filled_p = 1;
3179     }
3183 static void
3184 ns_draw_glyph_string (struct glyph_string *s)
3185 /* --------------------------------------------------------------------------
3186       External (RIF): Main draw-text call.
3187    -------------------------------------------------------------------------- */
3189   /* TODO (optimize): focus for box and contents draw */
3190   NSRect r[2];
3191   int n;
3192   char box_drawn_p = 0;
3194   NSTRACE (ns_draw_glyph_string);
3196   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3197     {
3198       int width;
3199       struct glyph_string *next;
3201       for (width = 0, next = s->next;
3202            next && width < s->right_overhang;
3203            width += next->width, next = next->next)
3204         if (next->first_glyph->type != IMAGE_GLYPH)
3205           {
3206             if (next->first_glyph->type != STRETCH_GLYPH)
3207               {
3208                 n = ns_get_glyph_string_clip_rect (s->next, r);
3209                 ns_focus (s->f, r, n);
3210                 ns_maybe_dumpglyphs_background (s->next, 1);
3211                 ns_unfocus (s->f);
3212               }
3213             else
3214               {
3215                 ns_dumpglyphs_stretch (s->next);
3216               }
3217             next->num_clips = 0;
3218           }
3219     }
3221   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3222         && (s->first_glyph->type == CHAR_GLYPH
3223             || s->first_glyph->type == COMPOSITE_GLYPH))
3224     {
3225       n = ns_get_glyph_string_clip_rect (s, r);
3226       ns_focus (s->f, r, n);
3227       ns_maybe_dumpglyphs_background (s, 1);
3228       ns_dumpglyphs_box_or_relief (s);
3229       ns_unfocus (s->f);
3230       box_drawn_p = 1;
3231     }
3233   switch (s->first_glyph->type)
3234     {
3236     case IMAGE_GLYPH:
3237       n = ns_get_glyph_string_clip_rect (s, r);
3238       ns_focus (s->f, r, n);
3239       ns_dumpglyphs_image (s, r[0]);
3240       ns_unfocus (s->f);
3241       break;
3243     case STRETCH_GLYPH:
3244       ns_dumpglyphs_stretch (s);
3245       break;
3247     case CHAR_GLYPH:
3248     case COMPOSITE_GLYPH:
3249       n = ns_get_glyph_string_clip_rect (s, r);
3250       ns_focus (s->f, r, n);
3252       if (s->for_overlaps || (s->cmp_from > 0
3253                               && ! s->first_glyph->u.cmp.automatic))
3254         s->background_filled_p = 1;
3255       else
3256         ns_maybe_dumpglyphs_background
3257           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3259       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3260                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3261                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3262                       NS_DUMPGLYPH_NORMAL));
3263       ns_tmp_font = (struct nsfont_info *)s->face->font;
3264       if (ns_tmp_font == NULL)
3265           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3267       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3268         {
3269           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3270           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3271           NS_FACE_FOREGROUND (s->face) = tmp;
3272         }
3274       ns_tmp_font->font.driver->draw
3275         (s, 0, s->nchars, s->x, s->y,
3276          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3277          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3279       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3280         {
3281           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3282           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3283           NS_FACE_FOREGROUND (s->face) = tmp;
3284         }
3286       ns_unfocus (s->f);
3287       break;
3289     case GLYPHLESS_GLYPH:
3290       n = ns_get_glyph_string_clip_rect (s, r);
3291       ns_focus (s->f, r, n);
3293       if (s->for_overlaps || (s->cmp_from > 0
3294                               && ! s->first_glyph->u.cmp.automatic))
3295         s->background_filled_p = 1;
3296       else
3297         ns_maybe_dumpglyphs_background
3298           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3299       /* ... */
3300       /* Not yet implemented.  */
3301       /* ... */
3302       ns_unfocus (s->f);
3303       break;
3305     default:
3306       abort ();
3307     }
3309   /* Draw box if not done already. */
3310   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3311     {
3312       n = ns_get_glyph_string_clip_rect (s, r);
3313       ns_focus (s->f, r, n);
3314       ns_dumpglyphs_box_or_relief (s);
3315       ns_unfocus (s->f);
3316     }
3318   s->num_clips = 0;
3323 /* ==========================================================================
3325     Event loop
3327    ========================================================================== */
3330 static void
3331 ns_send_appdefined (int value)
3332 /* --------------------------------------------------------------------------
3333     Internal: post an appdefined event which EmacsApp-sendEvent will
3334               recognize and take as a command to halt the event loop.
3335    -------------------------------------------------------------------------- */
3337   /*NSTRACE (ns_send_appdefined); */
3339   /* Only post this event if we haven't already posted one.  This will end
3340        the [NXApp run] main loop after having processed all events queued at
3341        this moment.  */
3342   if (send_appdefined)
3343     {
3344       NSEvent *nxev;
3346       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3347       send_appdefined = NO;
3349       /* Don't need wakeup timer any more */
3350       if (timed_entry)
3351         {
3352           [timed_entry invalidate];
3353           [timed_entry release];
3354           timed_entry = nil;
3355         }
3357       /* Ditto for file descriptor poller */
3358       if (fd_entry)
3359         {
3360           [fd_entry invalidate];
3361           [fd_entry release];
3362           fd_entry = nil;
3363         }
3365       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3366                                 location: NSMakePoint (0, 0)
3367                            modifierFlags: 0
3368                                timestamp: 0
3369                             windowNumber: [[NSApp mainWindow] windowNumber]
3370                                  context: [NSApp context]
3371                                  subtype: 0
3372                                    data1: value
3373                                    data2: 0];
3375       /* Post an application defined event on the event queue.  When this is
3376          received the [NXApp run] will return, thus having processed all
3377          events which are currently queued.  */
3378       [NSApp postEvent: nxev atStart: NO];
3379     }
3383 static int
3384 ns_read_socket (struct terminal *terminal, int expected,
3385                 struct input_event *hold_quit)
3386 /* --------------------------------------------------------------------------
3387      External (hook): Post an event to ourself and keep reading events until
3388      we read it back again.  In effect process all events which were waiting.
3389      From 21+ we have to manage the event buffer ourselves.
3390    -------------------------------------------------------------------------- */
3392   struct input_event ev;
3393   int nevents;
3395 /* NSTRACE (ns_read_socket); */
3397   if (interrupt_input_blocked)
3398     {
3399       interrupt_input_pending = 1;
3400 #ifdef SYNC_INPUT
3401       pending_signals = 1;
3402 #endif
3403       return -1;
3404     }
3406   interrupt_input_pending = 0;
3407 #ifdef SYNC_INPUT
3408   pending_signals = pending_atimers;
3409 #endif
3411   BLOCK_INPUT;
3412   n_emacs_events_pending = 0;
3413   EVENT_INIT (ev);
3414   emacs_event = &ev;
3415   q_event_ptr = hold_quit;
3417   /* we manage autorelease pools by allocate/reallocate each time around
3418      the loop; strict nesting is occasionally violated but seems not to
3419      matter.. earlier methods using full nesting caused major memory leaks */
3420   [outerpool release];
3421   outerpool = [[NSAutoreleasePool alloc] init];
3423   /* If have pending open-file requests, attend to the next one of those. */
3424   if (ns_pending_files && [ns_pending_files count] != 0
3425       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3426     {
3427       [ns_pending_files removeObjectAtIndex: 0];
3428     }
3429   /* Deal with pending service requests. */
3430   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3431     && [(EmacsApp *)
3432          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3433                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3434     {
3435       [ns_pending_service_names removeObjectAtIndex: 0];
3436       [ns_pending_service_args removeObjectAtIndex: 0];
3437     }
3438   else
3439     {
3440       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3441          to ourself, otherwise [NXApp run] will never exit.  */
3442       send_appdefined = YES;
3444       /* If called via ns_select, this is called once with expected=1,
3445          because we expect either the timeout or file descriptor activity.
3446          In this case the first event through will either be real input or
3447          one of these.  read_avail_input() then calls once more with expected=0
3448          and in that case we need to return quickly if there is nothing.
3449          If we're being called outside of that, it's also OK to return quickly
3450          after one iteration through the event loop, since other terms do
3451          this and emacs expects it. */
3452       if (!(inNsSelect && expected))
3453         {
3454           /* Post an application defined event on the event queue.  When this is
3455              received the [NXApp run] will return, thus having processed all
3456              events which are currently queued, if any.  */
3457           ns_send_appdefined (-1);
3458         }
3460       [NSApp run];
3461     }
3463   nevents = n_emacs_events_pending;
3464   n_emacs_events_pending = 0;
3465   emacs_event = q_event_ptr = NULL;
3466   UNBLOCK_INPUT;
3468   return nevents;
3473 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3474            fd_set *exceptfds, struct timeval *timeout)
3475 /* --------------------------------------------------------------------------
3476      Replacement for select, checking for events
3477    -------------------------------------------------------------------------- */
3479   int result;
3480   double time;
3481   NSEvent *ev;
3482 /*  NSTRACE (ns_select); */
3484   if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO &&
3485                       [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
3486  inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
3487     return select (nfds, readfds, writefds, exceptfds, timeout);
3489   /* Save file descriptor set, which gets overwritten in calls to select ()
3490      Note, this is called from process.c, and only readfds is ever set */
3491   if (readfds)
3492     {
3493       memcpy (&select_readfds, readfds, sizeof (fd_set));
3494       select_nfds = nfds;
3495     }
3496   else
3497     select_nfds = 0;
3499     /* Try an initial select for pending data on input files */
3500   select_timeout.tv_sec = select_timeout.tv_usec = 0;
3501   result = select (nfds, readfds, writefds, exceptfds, &select_timeout);
3502   if (result)
3503     return result;
3505   /* if (!timeout || timed_entry || fd_entry)
3506        fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
3508     /* set a timeout and run the main AppKit event loop while continuing
3509        to monitor the files */
3510   time = ((double) timeout->tv_sec) + ((double) timeout->tv_usec)/1000000.0;
3511   timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3512                                            target: NSApp
3513                                          selector: @selector (timeout_handler:)
3514                                          userInfo: 0
3515                                           repeats: YES] /* for safe removal */
3516                                                          retain];
3518   /* set a periodic task to try the select () again */
3519   fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
3520                                                target: NSApp
3521                                              selector: @selector (fd_handler:)
3522                                              userInfo: 0
3523                                               repeats: YES]
3524                retain];
3526   /* Let Application dispatch events until it receives an event of the type
3527      NX_APPDEFINED, which should only be sent by timeout_handler.
3528      We tell read_avail_input() that input is "expected" because we do expect
3529      either the timeout or fd handler to fire, and if they don't, the original
3530      call from process.c that got us here expects us to wait until some input
3531      comes. */
3532   inNsSelect = 1;
3533   gobble_input (1);
3534   ev = last_appdefined_event;
3535   inNsSelect = 0;
3537   if (ev)
3538     {
3539       int t;
3540       if ([ev type] != NSApplicationDefined)
3541         abort ();
3543       t = [ev data1];
3544       last_appdefined_event = 0;
3546       if (t == -2)
3547         {
3548           /* The NX_APPDEFINED event we received was a timeout. */
3549           return 0;
3550         }
3551       else if (t == -1)
3552         {
3553           /* The NX_APPDEFINED event we received was the result of
3554              at least one real input event arriving.  */
3555           errno = EINTR;
3556           return -1;
3557         }
3558       else
3559         {
3560           /* Received back from select () in fd_handler; copy the results */
3561           if (readfds)
3562             memcpy (readfds, &select_readfds, sizeof (fd_set));
3563           return t;
3564         }
3565     }
3566   /* never reached, shut compiler up */
3567   return 0;
3572 /* ==========================================================================
3574     Scrollbar handling
3576    ========================================================================== */
3579 static void
3580 ns_set_vertical_scroll_bar (struct window *window,
3581                            int portion, int whole, int position)
3582 /* --------------------------------------------------------------------------
3583       External (hook): Update or add scrollbar
3584    -------------------------------------------------------------------------- */
3586   Lisp_Object win;
3587   NSRect r, v;
3588   struct frame *f = XFRAME (WINDOW_FRAME (window));
3589   EmacsView *view = FRAME_NS_VIEW (f);
3590   int window_y, window_height;
3591   BOOL barOnVeryLeft, barOnVeryRight;
3592   int top, left, height, width, sb_width, sb_left;
3593   EmacsScroller *bar;
3594 static int count = 0;
3596   /* optimization; display engine sends WAY too many of these.. */
3597   if (!NILP (window->vertical_scroll_bar))
3598     {
3599       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3600       if ([bar checkSamePosition: position portion: portion whole: whole])
3601         {
3602           if (view->scrollbarsNeedingUpdate == 0)
3603             {
3604               if (!windows_or_buffers_changed)
3605                   return;
3606             }
3607           else
3608             view->scrollbarsNeedingUpdate--;
3609         }
3610     }
3612   NSTRACE (ns_set_vertical_scroll_bar);
3614   /* Get dimensions.  */
3615   window_box (window, -1, 0, &window_y, 0, &window_height);
3616   top = window_y;
3617   height = window_height;
3618   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3619   left = WINDOW_SCROLL_BAR_AREA_X (window);
3621   if (top < 5) /* top scrollbar adjustment */
3622     {
3623       top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3624       height += FRAME_INTERNAL_BORDER_WIDTH (f);
3625     }
3627   /* allow for displaying a skinnier scrollbar than char area allotted */
3628   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3629     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3631   barOnVeryLeft = left < 5;
3632   barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3633   sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3634       * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3636   r = NSMakeRect (sb_left, top, sb_width, height);
3637   /* the parent view is flipped, so we need to flip y value */
3638   v = [view frame];
3639   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3641   XSETWINDOW (win, window);
3642   BLOCK_INPUT;
3644   /* we want at least 5 lines to display a scrollbar */
3645   if (WINDOW_TOTAL_LINES (window) < 5)
3646     {
3647       if (!NILP (window->vertical_scroll_bar))
3648         {
3649           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3650           [bar removeFromSuperview];
3651           window->vertical_scroll_bar = Qnil;
3652         }
3653       ns_clear_frame_area (f, sb_left, top, width, height);
3654       UNBLOCK_INPUT;
3655       return;
3656     }
3658   if (NILP (window->vertical_scroll_bar))
3659     {
3660       ns_clear_frame_area (f, sb_left, top, width, height);
3661       bar = [[EmacsScroller alloc] initFrame: r window: win];
3662       window->vertical_scroll_bar = make_save_value (bar, 0);
3663     }
3664   else
3665     {
3666       NSRect oldRect;
3667       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3668       oldRect = [bar frame];
3669       r.size.width = oldRect.size.width;
3670       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3671         {
3672           if (oldRect.origin.x != r.origin.x)
3673               ns_clear_frame_area (f, sb_left, top, width, height);
3674           [bar setFrame: r];
3675         }
3676     }
3678   [bar setPosition: position portion: portion whole: whole];
3679   UNBLOCK_INPUT;
3683 static void
3684 ns_condemn_scroll_bars (struct frame *f)
3685 /* --------------------------------------------------------------------------
3686      External (hook): arrange for all frame's scrollbars to be removed
3687      at next call to judge_scroll_bars, except for those redeemed.
3688    -------------------------------------------------------------------------- */
3690   int i;
3691   id view;
3692   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3694   NSTRACE (ns_condemn_scroll_bars);
3696   for (i =[subviews count]-1; i >= 0; i--)
3697     {
3698       view = [subviews objectAtIndex: i];
3699       if ([view isKindOfClass: [EmacsScroller class]])
3700         [view condemn];
3701     }
3705 static void
3706 ns_redeem_scroll_bar (struct window *window)
3707 /* --------------------------------------------------------------------------
3708      External (hook): arrange to spare this window's scrollbar
3709      at next call to judge_scroll_bars.
3710    -------------------------------------------------------------------------- */
3712   id bar;
3713   NSTRACE (ns_redeem_scroll_bar);
3714   if (!NILP (window->vertical_scroll_bar))
3715     {
3716       bar =XNS_SCROLL_BAR (window->vertical_scroll_bar);
3717       [bar reprieve];
3718     }
3722 static void
3723 ns_judge_scroll_bars (struct frame *f)
3724 /* --------------------------------------------------------------------------
3725      External (hook): destroy all scrollbars on frame that weren't
3726      redeemed after call to condemn_scroll_bars.
3727    -------------------------------------------------------------------------- */
3729   int i;
3730   id view;
3731   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3732   NSTRACE (ns_judge_scroll_bars);
3733   for (i =[subviews count]-1; i >= 0; i--)
3734     {
3735       view = [subviews objectAtIndex: i];
3736       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3737       [view judge];
3738     }
3742 void
3743 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3745   /* XXX irrelevant under NS */
3750 /* ==========================================================================
3752     Initialization
3754    ========================================================================== */
3757 x_display_pixel_height (struct ns_display_info *dpyinfo)
3759   NSScreen *screen = [NSScreen mainScreen];
3760   return [screen frame].size.height;
3764 x_display_pixel_width (struct ns_display_info *dpyinfo)
3766   NSScreen *screen = [NSScreen mainScreen];
3767   return [screen frame].size.width;
3771 static Lisp_Object ns_string_to_lispmod (const char *s)
3772 /* --------------------------------------------------------------------------
3773      Convert modifier name to lisp symbol
3774    -------------------------------------------------------------------------- */
3776   if (!strncmp (SDATA (SYMBOL_NAME (Qmeta)), s, 10))
3777     return Qmeta;
3778   else if (!strncmp (SDATA (SYMBOL_NAME (Qsuper)), s, 10))
3779     return Qsuper;
3780   else if (!strncmp (SDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3781     return Qcontrol;
3782   else if (!strncmp (SDATA (SYMBOL_NAME (Qalt)), s, 10))
3783     return Qalt;
3784   else if (!strncmp (SDATA (SYMBOL_NAME (Qhyper)), s, 10))
3785     return Qhyper;
3786   else if (!strncmp (SDATA (SYMBOL_NAME (Qnone)), s, 10))
3787     return Qnone;
3788   else
3789     return Qnil;
3793 static Lisp_Object ns_mod_to_lisp (int m)
3794 /* --------------------------------------------------------------------------
3795      Convert modifier code (see lisp.h) to lisp symbol
3796    -------------------------------------------------------------------------- */
3798   if (m == CHAR_META)
3799     return Qmeta;
3800   else if (m == CHAR_SUPER)
3801     return Qsuper;
3802   else if (m == CHAR_CTL)
3803     return Qcontrol;
3804   else if (m == CHAR_ALT)
3805     return Qalt;
3806   else if (m == CHAR_HYPER)
3807     return Qhyper;
3808   else /* if (m == 0) */
3809     return Qnone;
3813 static void
3814 ns_default (const char *parameter, Lisp_Object *result,
3815            Lisp_Object yesval, Lisp_Object noval,
3816            BOOL is_float, BOOL is_modstring)
3817 /* --------------------------------------------------------------------------
3818       Check a parameter value in user's preferences
3819    -------------------------------------------------------------------------- */
3821   const char *value = ns_get_defaults_value (parameter);
3823   if (value)
3824     {
3825       double f;
3826       char *pos;
3827       if (strcasecmp (value, "YES") == 0)
3828         *result = yesval;
3829       else if (strcasecmp (value, "NO") == 0)
3830         *result = noval;
3831       else if (is_float && (f = strtod (value, &pos), pos != value))
3832         *result = make_float (f);
3833       else if (is_modstring && value)
3834         *result = ns_string_to_lispmod (value);
3835       else fprintf (stderr,
3836                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3837     }
3841 void
3842 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3843 /* --------------------------------------------------------------------------
3844       Initialize global info and storage for display.
3845    -------------------------------------------------------------------------- */
3847     NSScreen *screen = [NSScreen mainScreen];
3848     NSWindowDepth depth = [screen depth];
3849     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3851     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3852     dpyinfo->resy = 72.27;
3853     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3854                                                   NSColorSpaceFromDepth (depth)]
3855                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3856                                                  NSColorSpaceFromDepth (depth)];
3857     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3858     dpyinfo->image_cache = make_image_cache ();
3859     dpyinfo->color_table
3860       = (struct ns_color_table *)xmalloc (sizeof (struct ns_color_table));
3861     dpyinfo->color_table->colors = NULL;
3862     dpyinfo->root_window = 42; /* a placeholder.. */
3864     hlinfo->mouse_face_mouse_frame = NULL;
3865     hlinfo->mouse_face_deferred_gc = 0;
3866     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3867     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3868     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3869     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3870     hlinfo->mouse_face_hidden = 0;
3872     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3873     hlinfo->mouse_face_defer = 0;
3875     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3877     dpyinfo->n_fonts = 0;
3878     dpyinfo->smallest_font_height = 1;
3879     dpyinfo->smallest_char_width = 1;
3883 /* This and next define (many of the) public functions in this file. */
3884 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3885          with using despite presence in the "system dependent" redisplay
3886          interface.  In addition, many of the ns_ methods have code that is
3887          shared with all terms, indicating need for further refactoring. */
3888 extern frame_parm_handler ns_frame_parm_handlers[];
3889 static struct redisplay_interface ns_redisplay_interface =
3891   ns_frame_parm_handlers,
3892   x_produce_glyphs,
3893   x_write_glyphs,
3894   x_insert_glyphs,
3895   x_clear_end_of_line,
3896   ns_scroll_run,
3897   ns_after_update_window_line,
3898   ns_update_window_begin,
3899   ns_update_window_end,
3900   x_cursor_to,
3901   ns_flush,
3902   0, /* flush_display_optional */
3903   x_clear_window_mouse_face,
3904   x_get_glyph_overhangs,
3905   x_fix_overlapping_area,
3906   ns_draw_fringe_bitmap,
3907   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3908   0, /* destroy_fringe_bitmap */
3909   ns_compute_glyph_string_overhangs,
3910   ns_draw_glyph_string, /* interface to nsfont.m */
3911   ns_define_frame_cursor,
3912   ns_clear_frame_area,
3913   ns_draw_window_cursor,
3914   ns_draw_vertical_window_border,
3915   ns_shift_glyphs_for_insert
3919 static void
3920 ns_delete_display (struct ns_display_info *dpyinfo)
3922   /* TODO... */
3926 /* This function is called when the last frame on a display is deleted. */
3927 static void
3928 ns_delete_terminal (struct terminal *terminal)
3930   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3931   int i;
3933   /* Protect against recursive calls.  delete_frame in
3934      delete_terminal calls us back when it deletes our last frame.  */
3935   if (!terminal->name)
3936     return;
3938   BLOCK_INPUT;
3940   x_destroy_all_bitmaps (dpyinfo);
3941   ns_delete_display (dpyinfo);
3942   UNBLOCK_INPUT;
3946 static struct terminal *
3947 ns_create_terminal (struct ns_display_info *dpyinfo)
3948 /* --------------------------------------------------------------------------
3949       Set up use of NS before we make the first connection.
3950    -------------------------------------------------------------------------- */
3952   struct terminal *terminal;
3954   NSTRACE (ns_create_terminal);
3956   terminal = create_terminal ();
3958   terminal->type = output_ns;
3959   terminal->display_info.ns = dpyinfo;
3960   dpyinfo->terminal = terminal;
3962   terminal->rif = &ns_redisplay_interface;
3964   terminal->clear_frame_hook = ns_clear_frame;
3965   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3966   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3967   terminal->ring_bell_hook = ns_ring_bell;
3968   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3969   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3970   terminal->update_begin_hook = ns_update_begin;
3971   terminal->update_end_hook = ns_update_end;
3972   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
3973   terminal->read_socket_hook = ns_read_socket;
3974   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3975   terminal->mouse_position_hook = ns_mouse_position;
3976   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3977   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3979   terminal->fullscreen_hook = 0; /* see XTfullscreen_hook */
3981   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3982   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3983   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3984   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3986   terminal->delete_frame_hook = x_destroy_window;
3987   terminal->delete_terminal_hook = ns_delete_terminal;
3989   terminal->scroll_region_ok = 1;
3990   terminal->char_ins_del_ok = 1;
3991   terminal->line_ins_del_ok = 1;
3992   terminal->fast_clear_end_of_line = 1;
3993   terminal->memory_below_frame = 0;
3995   return terminal;
3999 struct ns_display_info *
4000 ns_term_init (Lisp_Object display_name)
4001 /* --------------------------------------------------------------------------
4002      Start the Application and get things rolling.
4003    -------------------------------------------------------------------------- */
4005   struct terminal *terminal;
4006   struct ns_display_info *dpyinfo;
4007   static int ns_initialized = 0;
4008   Lisp_Object tmp;
4010   NSTRACE (ns_term_init);
4012   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4013   /*GSDebugAllocationActive (YES); */
4014   BLOCK_INPUT;
4015   handling_signal = 0;
4017   if (!ns_initialized)
4018     {
4019       baud_rate = 38400;
4020       Fset_input_interrupt_mode (Qnil);
4021       ns_initialized = 1;
4022     }
4024   ns_pending_files = [[NSMutableArray alloc] init];
4025   ns_pending_service_names = [[NSMutableArray alloc] init];
4026   ns_pending_service_args = [[NSMutableArray alloc] init];
4028   /* Start app and create the main menu, window, view.
4029      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4030      The view will then ask the NSApp to stop and return to Emacs. */
4031   [EmacsApp sharedApplication];
4032   if (NSApp == nil)
4033     return NULL;
4034   [NSApp setDelegate: NSApp];
4036   /* debugging: log all notifications */
4037   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4038                                          selector: @selector (logNotification:)
4039                                              name: nil object: nil]; */
4041   dpyinfo = (struct ns_display_info *)xmalloc (sizeof (struct ns_display_info));
4042   memset (dpyinfo, 0, sizeof (struct ns_display_info));
4044   ns_initialize_display_info (dpyinfo);
4045   terminal = ns_create_terminal (dpyinfo);
4047   terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
4048   init_kboard (terminal->kboard);
4049   KVAR (terminal->kboard, Vwindow_system) = Qns;
4050   terminal->kboard->next_kboard = all_kboards;
4051   all_kboards = terminal->kboard;
4052   /* Don't let the initial kboard remain current longer than necessary.
4053      That would cause problems if a file loaded on startup tries to
4054      prompt in the mini-buffer.  */
4055   if (current_kboard == initial_kboard)
4056     current_kboard = terminal->kboard;
4057   terminal->kboard->reference_count++;
4059   dpyinfo->next = x_display_list;
4060   x_display_list = dpyinfo;
4062   /* Put it on ns_display_name_list */
4063   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4064                                 ns_display_name_list);
4065   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4067   /* Set the name of the terminal. */
4068   terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
4069   strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
4070   terminal->name[SBYTES (display_name)] = 0;
4072   UNBLOCK_INPUT;
4074   if (!inhibit_x_resources)
4075     {
4076       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4077                  Qt, Qnil, NO, NO);
4078       tmp = Qnil;
4079       /* this is a standard variable */
4080       ns_default ("AppleAntiAliasingThreshold", &tmp,
4081                  make_float (10.0), make_float (6.0), YES, NO);
4082       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4083     }
4085   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4086                          stringForKey: @"AppleHighlightColor"];
4087   if (ns_selection_color == nil)
4088     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4090   {
4091     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4093     if ( cl == nil )
4094       {
4095         Lisp_Object color_file, color_map, color;
4096         int r,g,b;
4097         unsigned long c;
4098         char *name;
4100         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4101                          Fsymbol_value (intern ("data-directory")));
4102         if (NILP (Ffile_readable_p (color_file)))
4103           fatal ("Could not find %s.\n", SDATA (color_file));
4105         color_map = Fx_load_color_file (color_file);
4106         if (NILP (color_map))
4107           fatal ("Could not read %s.\n", SDATA (color_file));
4109         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4110         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4111           {
4112             color = XCAR (color_map);
4113             name = SDATA (XCAR (color));
4114             c = XINT (XCDR (color));
4115             [cl setColor:
4116                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4117                                             green: GREEN_FROM_ULONG (c) / 255.0
4118                                              blue: BLUE_FROM_ULONG (c) / 255.0
4119                                             alpha: 1.0]
4120                   forKey: [NSString stringWithUTF8String: name]];
4121           }
4122         [cl writeToFile: nil];
4123       }
4124   }
4126   {
4127     char c[128];
4128 #ifdef NS_IMPL_GNUSTEP
4129     strncpy (c, gnustep_base_version, sizeof (c));
4130 #else
4131     /*PSnextrelease (128, c); */
4132     snprintf (c, sizeof (c), "%g", NSAppKitVersionNumber);
4133 #endif
4134     Vwindow_system_version = build_string (c);
4135   }
4137   delete_keyboard_wait_descriptor (0);
4139   ns_app_name = [[NSProcessInfo processInfo] processName];
4141 /* Set up OS X app menu */
4142 #ifdef NS_IMPL_COCOA
4143   {
4144     NSMenu *appMenu;
4145     NSMenuItem *item;
4146     /* set up the application menu */
4147     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4148     [svcsMenu setAutoenablesItems: NO];
4149     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4150     [appMenu setAutoenablesItems: NO];
4151     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4152     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4154     [appMenu insertItemWithTitle: @"About Emacs"
4155                           action: @selector (orderFrontStandardAboutPanel:)
4156                    keyEquivalent: @""
4157                          atIndex: 0];
4158     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4159     [appMenu insertItemWithTitle: @"Preferences..."
4160                           action: @selector (showPreferencesWindow:)
4161                    keyEquivalent: @","
4162                          atIndex: 2];
4163     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4164     item = [appMenu insertItemWithTitle: @"Services"
4165                                  action: @selector (menuDown:)
4166                           keyEquivalent: @""
4167                                 atIndex: 4];
4168     [appMenu setSubmenu: svcsMenu forItem: item];
4169     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4170     [appMenu insertItemWithTitle: @"Hide Emacs"
4171                           action: @selector (hide:)
4172                    keyEquivalent: @"h"
4173                          atIndex: 6];
4174     item =  [appMenu insertItemWithTitle: @"Hide Others"
4175                           action: @selector (hideOtherApplications:)
4176                    keyEquivalent: @"h"
4177                          atIndex: 7];
4178     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4179     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4180     [appMenu insertItemWithTitle: @"Quit Emacs"
4181                           action: @selector (terminate:)
4182                    keyEquivalent: @"q"
4183                          atIndex: 9];
4185     item = [mainMenu insertItemWithTitle: ns_app_name
4186                                   action: @selector (menuDown:)
4187                            keyEquivalent: @""
4188                                  atIndex: 0];
4189     [mainMenu setSubmenu: appMenu forItem: item];
4190     [dockMenu insertItemWithTitle: @"New Frame"
4191                            action: @selector (newFrame:)
4192                     keyEquivalent: @""
4193                           atIndex: 0];
4195     [NSApp setMainMenu: mainMenu];
4196     [NSApp setAppleMenu: appMenu];
4197     [NSApp setServicesMenu: svcsMenu];
4198     /* Needed at least on Cocoa, to get dock menu to show windows */
4199     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4201     [[NSNotificationCenter defaultCenter]
4202       addObserver: mainMenu
4203          selector: @selector (trackingNotification:)
4204              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4205     [[NSNotificationCenter defaultCenter]
4206       addObserver: mainMenu
4207          selector: @selector (trackingNotification:)
4208              name: NSMenuDidEndTrackingNotification object: mainMenu];
4209   }
4210 #endif /* MAC OS X menu setup */
4212   [NSApp run];
4214   return dpyinfo;
4218 void
4219 ns_term_shutdown (int sig)
4221   [[NSUserDefaults standardUserDefaults] synchronize];
4223   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4224   if (STRINGP (Vauto_save_list_file_name))
4225     unlink (SDATA (Vauto_save_list_file_name));
4227   if (sig == 0 || sig == SIGTERM)
4228     {
4229       [NSApp terminate: NSApp];
4230     }
4231   else // force a stack trace to happen
4232     {
4233       abort();
4234     }
4238 /* ==========================================================================
4240     EmacsApp implementation
4242    ========================================================================== */
4245 @implementation EmacsApp
4247 - (void)logNotification: (NSNotification *)notification
4249   const char *name = [[notification name] UTF8String];
4250   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4251       && !strstr (name, "WindowNumber"))
4252     NSLog (@"notification: '%@'", [notification name]);
4256 - (void)sendEvent: (NSEvent *)theEvent
4257 /* --------------------------------------------------------------------------
4258      Called when NSApp is running for each event received.  Used to stop
4259      the loop when we choose, since there's no way to just run one iteration.
4260    -------------------------------------------------------------------------- */
4262   int type = [theEvent type];
4263   NSWindow *window = [theEvent window];
4264 /*  NSTRACE (sendEvent); */
4265 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4267 #ifdef NS_IMPL_COCOA
4268   if (type == NSApplicationDefined
4269       && [theEvent data2] == NSAPP_DATA2_RUNASSCRIPT)
4270     {
4271       ns_run_ascript ();
4272       [self stop: self];
4273       return;
4274     }
4275 #endif
4277   if (type == NSCursorUpdate && window == nil)
4278     {
4279       fprintf (stderr, "Dropping external cursor update event.\n");
4280       return;
4281     }
4283 #ifdef NS_IMPL_COCOA
4284   /* pass mouse down in resize handle and subsequent drags directly to
4285      EmacsWindow so we can generate continuous redisplays */
4286   if (ns_in_resize)
4287     {
4288       if (type == NSLeftMouseDragged)
4289         {
4290           [window mouseDragged: theEvent];
4291           return;
4292         }
4293       else if (type == NSLeftMouseUp)
4294         {
4295           [window mouseUp: theEvent];
4296           return;
4297         }
4298     }
4299   else if (type == NSLeftMouseDown)
4300     {
4301       NSRect r = ns_resize_handle_rect (window);
4302       if (NSPointInRect ([theEvent locationInWindow], r))
4303         {
4304           ns_in_resize = YES;
4305           [window mouseDown: theEvent];
4306           return;
4307         }
4308     }
4309 #endif
4311   if (type == NSApplicationDefined)
4312     {
4313       /* Events posted by ns_send_appdefined interrupt the run loop here.
4314          But, if a modal window is up, an appdefined can still come through,
4315          (e.g., from a makeKeyWindow event) but stopping self also stops the
4316          modal loop. Just defer it until later. */
4317       if ([NSApp modalWindow] == nil)
4318         {
4319           last_appdefined_event = theEvent;
4320           [self stop: self];
4321         }
4322       else
4323         {
4324           send_appdefined = YES;
4325         }
4326     }
4328   [super sendEvent: theEvent];
4332 - (void)showPreferencesWindow: (id)sender
4334   struct frame *emacsframe = SELECTED_FRAME ();
4335   NSEvent *theEvent = [NSApp currentEvent];
4337   if (!emacs_event)
4338     return;
4339   emacs_event->kind = NS_NONKEY_EVENT;
4340   emacs_event->code = KEY_NS_SHOW_PREFS;
4341   emacs_event->modifiers = 0;
4342   EV_TRAILER (theEvent);
4346 - (void)newFrame: (id)sender
4348   struct frame *emacsframe = SELECTED_FRAME ();
4349   NSEvent *theEvent = [NSApp currentEvent];
4351   if (!emacs_event)
4352     return;
4353   emacs_event->kind = NS_NONKEY_EVENT;
4354   emacs_event->code = KEY_NS_NEW_FRAME;
4355   emacs_event->modifiers = 0;
4356   EV_TRAILER (theEvent);
4360 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4361 - (BOOL) openFile: (NSString *)fileName
4363   struct frame *emacsframe = SELECTED_FRAME ();
4364   NSEvent *theEvent = [NSApp currentEvent];
4366   if (!emacs_event)
4367     return NO;
4369   emacs_event->kind = NS_NONKEY_EVENT;
4370   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4371   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4372   ns_input_line = Qnil; /* can be start or cons start,end */
4373   emacs_event->modifiers =0;
4374   EV_TRAILER (theEvent);
4376   return YES;
4380 /* **************************************************************************
4382       EmacsApp delegate implementation
4384    ************************************************************************** */
4386 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4387 /* --------------------------------------------------------------------------
4388      When application is loaded, terminate event loop in ns_term_init
4389    -------------------------------------------------------------------------- */
4391   NSTRACE (applicationDidFinishLaunching);
4392   [NSApp setServicesProvider: NSApp];
4393   ns_send_appdefined (-2);
4397 /* Termination sequences:
4398     C-x C-c:
4399     Cmd-Q:
4400     MenuBar | File | Exit:
4401     Select Quit from App menubar:
4402         -terminate
4403         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4404         ns_term_shutdown()
4406     Select Quit from Dock menu:
4407     Logout attempt:
4408         -appShouldTerminate
4409           Cancel -> Nothing else
4410           Accept ->
4412           -terminate
4413           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4414           ns_term_shutdown()
4418 - (void) terminate: (id)sender
4420   struct frame *emacsframe = SELECTED_FRAME ();
4422   if (!emacs_event)
4423     return;
4425   emacs_event->kind = NS_NONKEY_EVENT;
4426   emacs_event->code = KEY_NS_POWER_OFF;
4427   emacs_event->arg = Qt; /* mark as non-key event */
4428   EV_TRAILER ((id)nil);
4432 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4434   int ret;
4436   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4437     return NSTerminateNow;
4439     ret = NSRunAlertPanel(ns_app_name,
4440                           [NSString stringWithUTF8String:"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?"],
4441                           @"Save Buffers and Exit", @"Cancel", nil);
4443     if (ret == NSAlertDefaultReturn)
4444         return NSTerminateNow;
4445     else if (ret == NSAlertAlternateReturn)
4446         return NSTerminateCancel;
4447     return NSTerminateNow;  /* just in case */
4451 /*   Notification from the Workspace to open a file */
4452 - (BOOL)application: sender openFile: (NSString *)file
4454   [ns_pending_files addObject: file];
4455   return YES;
4459 /*   Open a file as a temporary file */
4460 - (BOOL)application: sender openTempFile: (NSString *)file
4462   [ns_pending_files addObject: file];
4463   return YES;
4467 /*   Notification from the Workspace to open a file noninteractively (?) */
4468 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4470   [ns_pending_files addObject: file];
4471   return YES;
4475 /*   Notification from the Workspace to open multiple files */
4476 - (void)application: sender openFiles: (NSArray *)fileList
4478   NSEnumerator *files = [fileList objectEnumerator];
4479   NSString *file;
4480   while ((file = [files nextObject]) != nil)
4481     [ns_pending_files addObject: file];
4483   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4488 /* Handle dock menu requests.  */
4489 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4491   return dockMenu;
4495 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4496 - (void)applicationWillBecomeActive: (NSNotification *)notification
4498   //ns_app_active=YES;
4500 - (void)applicationDidBecomeActive: (NSNotification *)notification
4502   NSTRACE (applicationDidBecomeActive);
4504   //ns_app_active=YES;
4506   ns_update_auto_hide_menu_bar ();
4507   // No constraining takes place when the application is not active.
4508   ns_constrain_all_frames ();
4510 - (void)applicationDidResignActive: (NSNotification *)notification
4512   //ns_app_active=NO;
4513   ns_send_appdefined (-1);
4518 /* ==========================================================================
4520     EmacsApp aux handlers for managing event loop
4522    ========================================================================== */
4525 - (void)timeout_handler: (NSTimer *)timedEntry
4526 /* --------------------------------------------------------------------------
4527      The timeout specified to ns_select has passed.
4528    -------------------------------------------------------------------------- */
4530   /*NSTRACE (timeout_handler); */
4531   ns_send_appdefined (-2);
4534 - (void)fd_handler: (NSTimer *) fdEntry
4535 /* --------------------------------------------------------------------------
4536      Check data waiting on file descriptors and terminate if so
4537    -------------------------------------------------------------------------- */
4539   int result;
4540   /* NSTRACE (fd_handler); */
4542   if (select_nfds == 0)
4543     return;
4545   memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4547   select_timeout.tv_sec = select_timeout.tv_usec = 0;
4548   result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
4549                   &select_timeout);
4550   if (result)
4551     {
4552       memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4553       ns_send_appdefined (result);
4554     }
4559 /* ==========================================================================
4561     Service provision
4563    ========================================================================== */
4565 /* called from system: queue for next pass through event loop */
4566 - (void)requestService: (NSPasteboard *)pboard
4567               userData: (NSString *)userData
4568                  error: (NSString **)error
4570   [ns_pending_service_names addObject: userData];
4571   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4572       SDATA (ns_string_from_pasteboard (pboard))]];
4576 /* called from ns_read_socket to clear queue */
4577 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4579   struct frame *emacsframe = SELECTED_FRAME ();
4580   NSEvent *theEvent = [NSApp currentEvent];
4582   if (!emacs_event)
4583     return NO;
4585   emacs_event->kind = NS_NONKEY_EVENT;
4586   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4587   ns_input_spi_name = build_string ([name UTF8String]);
4588   ns_input_spi_arg = build_string ([arg UTF8String]);
4589   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4590   EV_TRAILER (theEvent);
4592   return YES;
4596 @end  /* EmacsApp */
4600 /* ==========================================================================
4602     EmacsView implementation
4604    ========================================================================== */
4607 @implementation EmacsView
4609 /* needed to inform when window closed from LISP */
4610 - (void) setWindowClosing: (BOOL)closing
4612   windowClosing = closing;
4616 - (void)dealloc
4618   NSTRACE (EmacsView_dealloc);
4619   [toolbar release];
4620   [super dealloc];
4624 /* called on font panel selection */
4625 - (void)changeFont: (id)sender
4627   NSEvent *e =[[self window] currentEvent];
4628   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4629   id newFont;
4630   float size;
4632   NSTRACE (changeFont);
4633   if (!emacs_event)
4634     return;
4636   if (newFont = [sender convertFont:
4637                            ((struct nsfont_info *)face->font)->nsfont])
4638     {
4639       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4641       emacs_event->kind = NS_NONKEY_EVENT;
4642       emacs_event->modifiers = 0;
4643       emacs_event->code = KEY_NS_CHANGE_FONT;
4645       size = [newFont pointSize];
4646       ns_input_fontsize = make_number (lrint (size));
4647       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4648       EV_TRAILER (e);
4649     }
4653 - (BOOL)acceptsFirstResponder
4655   NSTRACE (acceptsFirstResponder);
4656   return YES;
4660 - (void)resetCursorRects
4662   NSRect visible = [self visibleRect];
4663   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4664   NSTRACE (resetCursorRects);
4666   if (currentCursor == nil)
4667     currentCursor = [NSCursor arrowCursor];
4669   if (!NSIsEmptyRect (visible))
4670     [self addCursorRect: visible cursor: currentCursor];
4671   [currentCursor setOnMouseEntered: YES];
4676 /*****************************************************************************/
4677 /* Keyboard handling. */
4678 #define NS_KEYLOG 0
4680 - (void)keyDown: (NSEvent *)theEvent
4682   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4683   int code;
4684   unsigned fnKeysym = 0;
4685   int flags;
4686   static NSMutableArray *nsEvArray;
4687 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4688   static BOOL firstTime = YES;
4689 #endif
4690   int left_is_none;
4692   NSTRACE (keyDown);
4694   /* Rhapsody and OS X give up and down events for the arrow keys */
4695   if (ns_fake_keydown == YES)
4696     ns_fake_keydown = NO;
4697   else if ([theEvent type] != NSKeyDown)
4698     return;
4700   if (!emacs_event)
4701     return;
4703  if (![[self window] isKeyWindow]
4704      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4705      /* we must avoid an infinite loop here. */
4706      && (EmacsView *)[[theEvent window] delegate] != self)
4707    {
4708      /* XXX: There is an occasional condition in which, when Emacs display
4709          updates a different frame from the current one, and temporarily
4710          selects it, then processes some interrupt-driven input
4711          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4712          for some reason that window has its first responder set to the NSView
4713          most recently updated (I guess), which is not the correct one. */
4714      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4715      return;
4716    }
4718   if (nsEvArray == nil)
4719     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4721   [NSCursor setHiddenUntilMouseMoves: YES];
4723   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4724     {
4725       clear_mouse_face (hlinfo);
4726       hlinfo->mouse_face_hidden = 1;
4727     }
4729   if (!processingCompose)
4730     {
4731       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4732         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4733       /* (Carbon way: [theEvent keyCode]) */
4735       /* is it a "function key"? */
4736       fnKeysym = ns_convert_key (code);
4737       if (fnKeysym)
4738         {
4739           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4740              because Emacs treats Delete and KP-Delete same (in simple.el). */
4741           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4742             code = 0xFF08; /* backspace */
4743           else
4744             code = fnKeysym;
4745         }
4747       /* are there modifiers? */
4748       emacs_event->modifiers = 0;
4749       flags = [theEvent modifierFlags];
4751       if (flags & NSHelpKeyMask)
4752           emacs_event->modifiers |= hyper_modifier;
4754       if (flags & NSShiftKeyMask)
4755         emacs_event->modifiers |= shift_modifier;
4757       if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask)
4758         emacs_event->modifiers |= parse_solitary_modifier
4759           (EQ (ns_right_command_modifier, Qleft)
4760            ? ns_command_modifier
4761            : ns_right_command_modifier);
4763       if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask)
4764         {
4765           emacs_event->modifiers |= parse_solitary_modifier
4766             (ns_command_modifier);
4768           /* if super (default), take input manager's word so things like
4769              dvorak / qwerty layout work */
4770           if (EQ (ns_command_modifier, Qsuper)
4771               && !fnKeysym
4772               && [[theEvent characters] length] != 0)
4773             {
4774               /* XXX: the code we get will be unshifted, so if we have
4775                  a shift modifier, must convert ourselves */
4776               if (!(flags & NSShiftKeyMask))
4777                 code = [[theEvent characters] characterAtIndex: 0];
4778 #if 0
4779               /* this is ugly and also requires linking w/Carbon framework
4780                  (for LMGetKbdType) so for now leave this rare (?) case
4781                  undealt with.. in future look into CGEvent methods */
4782               else
4783                 {
4784                   long smv = GetScriptManagerVariable (smKeyScript);
4785                   Handle uchrHandle = GetResource
4786                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4787                   UInt32 dummy = 0;
4788                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4789                                  [[theEvent characters] characterAtIndex: 0],
4790                                  kUCKeyActionDisplay,
4791                                  (flags & ~NSCommandKeyMask) >> 8,
4792                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4793                                  &dummy, 1, &dummy, &code);
4794                   code &= 0xFF;
4795                 }
4796 #endif
4797             }
4798         }
4800       if ((flags & NSRightControlKeyMask) == NSRightControlKeyMask)
4801           emacs_event->modifiers |= parse_solitary_modifier
4802               (EQ (ns_right_control_modifier, Qleft)
4803                ? ns_control_modifier
4804                : ns_right_control_modifier);
4806       if ((flags & NSLeftControlKeyMask) == NSLeftControlKeyMask)
4807         emacs_event->modifiers |= parse_solitary_modifier
4808           (ns_control_modifier);
4810       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4811           emacs_event->modifiers |=
4812             parse_solitary_modifier (ns_function_modifier);
4814       left_is_none = NILP (ns_alternate_modifier)
4815         || EQ (ns_alternate_modifier, Qnone);
4817       if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask)
4818         {
4819           if ((NILP (ns_right_alternate_modifier)
4820                || EQ (ns_right_alternate_modifier, Qnone)
4821                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4822               && !fnKeysym)
4823             {   /* accept pre-interp alt comb */
4824               if ([[theEvent characters] length] > 0)
4825                 code = [[theEvent characters] characterAtIndex: 0];
4826               /*HACK: clear lone shift modifier to stop next if from firing */
4827               if (emacs_event->modifiers == shift_modifier)
4828                 emacs_event->modifiers = 0;
4829             }
4830           else
4831             emacs_event->modifiers |= parse_solitary_modifier
4832               (EQ (ns_right_alternate_modifier, Qleft)
4833                ? ns_alternate_modifier
4834                : ns_right_alternate_modifier);
4835         }
4837       if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask) /* default = meta */
4838         {
4839           if (left_is_none && !fnKeysym)
4840             {   /* accept pre-interp alt comb */
4841               if ([[theEvent characters] length] > 0)
4842                 code = [[theEvent characters] characterAtIndex: 0];
4843               /*HACK: clear lone shift modifier to stop next if from firing */
4844               if (emacs_event->modifiers == shift_modifier)
4845                 emacs_event->modifiers = 0;
4846             }
4847           else
4848               emacs_event->modifiers |=
4849                 parse_solitary_modifier (ns_alternate_modifier);
4850         }
4852   if (NS_KEYLOG)
4853     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4854              code, fnKeysym, flags, emacs_event->modifiers);
4856       /* if it was a function key or had modifiers, pass it directly to emacs */
4857       if (fnKeysym || (emacs_event->modifiers
4858                        && (emacs_event->modifiers != shift_modifier)
4859                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4860 /*[[theEvent characters] length] */
4861         {
4862           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4863           if (code < 0x20)
4864             code |= (1<<28)|(3<<16);
4865           else if (code == 0x7f)
4866             code |= (1<<28)|(3<<16);
4867           else if (!fnKeysym)
4868             emacs_event->kind = code > 0xFF
4869               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4871           emacs_event->code = code;
4872           EV_TRAILER (theEvent);
4873           return;
4874         }
4875     }
4878 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4879   /* if we get here we should send the key for input manager processing */
4880   if (firstTime && [[NSInputManager currentInputManager]
4881                      wantsToDelayTextChangeNotifications] == NO)
4882     fprintf (stderr,
4883           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4884   firstTime = NO;
4885 #endif
4886   if (NS_KEYLOG && !processingCompose)
4887     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4889   processingCompose = YES;
4890   [nsEvArray addObject: theEvent];
4891   [self interpretKeyEvents: nsEvArray];
4892   [nsEvArray removeObject: theEvent];
4896 #ifdef NS_IMPL_COCOA
4897 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4898    decided not to send key-down for.
4899    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4900    This only applies on Tiger and earlier.
4901    If it matches one of these, send it on to keyDown. */
4902 -(void)keyUp: (NSEvent *)theEvent
4904   int flags = [theEvent modifierFlags];
4905   int code = [theEvent keyCode];
4906   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
4907       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4908     {
4909       if (NS_KEYLOG)
4910         fprintf (stderr, "keyUp: passed test");
4911       ns_fake_keydown = YES;
4912       [self keyDown: theEvent];
4913     }
4915 #endif
4918 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4921 /* <NSTextInput>: called when done composing;
4922    NOTE: also called when we delete over working text, followed immed.
4923          by doCommandBySelector: deleteBackward: */
4924 - (void)insertText: (id)aString
4926   int code;
4927   int len = [(NSString *)aString length];
4928   int i;
4930   if (NS_KEYLOG)
4931     NSLog (@"insertText '%@'\tlen = %d", aString, len);
4932   processingCompose = NO;
4934   if (!emacs_event)
4935     return;
4937   /* first, clear any working text */
4938   if (workingText != nil)
4939     [self deleteWorkingText];
4941   /* now insert the string as keystrokes */
4942   for (i =0; i<len; i++)
4943     {
4944       code = [aString characterAtIndex: i];
4945       /* TODO: still need this? */
4946       if (code == 0x2DC)
4947         code = '~'; /* 0x7E */
4948       emacs_event->modifiers = 0;
4949       emacs_event->kind
4950         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4951       emacs_event->code = code;
4952       EV_TRAILER ((id)nil);
4953     }
4957 /* <NSTextInput>: inserts display of composing characters */
4958 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
4960   NSString *str = [aString respondsToSelector: @selector (string)] ?
4961     [aString string] : aString;
4962   if (NS_KEYLOG)
4963     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
4964            selRange.length, selRange.location);
4966   if (workingText != nil)
4967     [self deleteWorkingText];
4968   if ([str length] == 0)
4969     return;
4971   if (!emacs_event)
4972     return;
4974   processingCompose = YES;
4975   workingText = [str copy];
4976   ns_working_text = build_string ([workingText UTF8String]);
4978   emacs_event->kind = NS_TEXT_EVENT;
4979   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
4980   EV_TRAILER ((id)nil);
4984 /* delete display of composing characters [not in <NSTextInput>] */
4985 - (void)deleteWorkingText
4987   if (workingText == nil)
4988     return;
4989   if (NS_KEYLOG)
4990     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
4991   [workingText release];
4992   workingText = nil;
4993   processingCompose = NO;
4995   if (!emacs_event)
4996     return;
4998   emacs_event->kind = NS_TEXT_EVENT;
4999   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5000   EV_TRAILER ((id)nil);
5004 - (BOOL)hasMarkedText
5006   return workingText != nil;
5010 - (NSRange)markedRange
5012   NSRange rng = workingText != nil
5013     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5014   if (NS_KEYLOG)
5015     NSLog (@"markedRange request");
5016   return rng;
5020 - (void)unmarkText
5022   if (NS_KEYLOG)
5023     NSLog (@"unmark (accept) text");
5024   [self deleteWorkingText];
5025   processingCompose = NO;
5029 /* used to position char selection windows, etc. */
5030 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5032   NSRect rect;
5033   NSPoint pt;
5034   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5035   if (NS_KEYLOG)
5036     NSLog (@"firstRectForCharRange request");
5038   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5039   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5040   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5041   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5042                                        +FRAME_LINE_HEIGHT (emacsframe));
5044   pt = [self convertPoint: pt toView: nil];
5045   pt = [[self window] convertBaseToScreen: pt];
5046   rect.origin = pt;
5047   return rect;
5051 - (long)conversationIdentifier
5053   return (long)self;
5057 - (void)doCommandBySelector: (SEL)aSelector
5059   if (NS_KEYLOG)
5060     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5062   if (aSelector == @selector (deleteBackward:))
5063     {
5064       /* happens when user backspaces over an ongoing composition:
5065          throw a 'delete' into the event queue */
5066       if (!emacs_event)
5067         return;
5068       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5069       emacs_event->code = 0xFF08;
5070       EV_TRAILER ((id)nil);
5071     }
5074 - (NSArray *)validAttributesForMarkedText
5076   static NSArray *arr = nil;
5077   if (arr == nil) arr = [NSArray new];
5078  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5079   return arr;
5082 - (NSRange)selectedRange
5084   if (NS_KEYLOG)
5085     NSLog (@"selectedRange request");
5086   return NSMakeRange (NSNotFound, 0);
5089 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5091   if (NS_KEYLOG)
5092     NSLog (@"characterIndexForPoint request");
5093   return 0;
5096 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5098   static NSAttributedString *str = nil;
5099   if (str == nil) str = [NSAttributedString new];
5100   if (NS_KEYLOG)
5101     NSLog (@"attributedSubstringFromRange request");
5102   return str;
5105 /* End <NSTextInput> impl. */
5106 /*****************************************************************************/
5109 /* This is what happens when the user presses a mouse button.  */
5110 - (void)mouseDown: (NSEvent *)theEvent
5112   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5113   Lisp_Object window;
5115   NSTRACE (mouseDown);
5117   [self deleteWorkingText];
5119   if (!emacs_event)
5120     return;
5122   last_mouse_frame = emacsframe;
5123   /* appears to be needed to prevent spurious movement events generated on
5124      button clicks */
5125   last_mouse_frame->mouse_moved = 0;
5127   if ([theEvent type] == NSScrollWheel)
5128     {
5129       float delta = [theEvent deltaY];
5130       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5131       if (delta == 0)
5132         return;
5133       emacs_event->kind = WHEEL_EVENT;
5134       emacs_event->code = 0;
5135       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5136         ((delta > 0) ? up_modifier : down_modifier);
5137     }
5138   else
5139     {
5140       emacs_event->kind = MOUSE_CLICK_EVENT;
5141       emacs_event->code = EV_BUTTON (theEvent);
5142       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5143                              | EV_UDMODIFIERS (theEvent);
5144     }
5145   XSETINT (emacs_event->x, lrint (p.x));
5146   XSETINT (emacs_event->y, lrint (p.y));
5147   EV_TRAILER (theEvent);
5151 - (void)rightMouseDown: (NSEvent *)theEvent
5153   NSTRACE (rightMouseDown);
5154   [self mouseDown: theEvent];
5158 - (void)otherMouseDown: (NSEvent *)theEvent
5160   NSTRACE (otherMouseDown);
5161   [self mouseDown: theEvent];
5165 - (void)mouseUp: (NSEvent *)theEvent
5167   NSTRACE (mouseUp);
5168   [self mouseDown: theEvent];
5172 - (void)rightMouseUp: (NSEvent *)theEvent
5174   NSTRACE (rightMouseUp);
5175   [self mouseDown: theEvent];
5179 - (void)otherMouseUp: (NSEvent *)theEvent
5181   NSTRACE (otherMouseUp);
5182   [self mouseDown: theEvent];
5186 - (void) scrollWheel: (NSEvent *)theEvent
5188   NSTRACE (scrollWheel);
5189   [self mouseDown: theEvent];
5193 /* Tell emacs the mouse has moved. */
5194 - (void)mouseMoved: (NSEvent *)e
5196   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5197   Lisp_Object frame;
5199 //  NSTRACE (mouseMoved);
5201   last_mouse_movement_time = EV_TIMESTAMP (e);
5202   last_mouse_motion_position
5203     = [self convertPoint: [e locationInWindow] fromView: nil];
5205   /* update any mouse face */
5206   if (hlinfo->mouse_face_hidden)
5207     {
5208       hlinfo->mouse_face_hidden = 0;
5209       clear_mouse_face (hlinfo);
5210     }
5212   /* tooltip handling */
5213   previous_help_echo_string = help_echo_string;
5214   help_echo_string = Qnil;
5216   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5217                             last_mouse_motion_position.y))
5218     help_echo_string = previous_help_echo_string;
5220   XSETFRAME (frame, emacsframe);
5221   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5222     {
5223       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5224          (note_mouse_highlight), which is called through the
5225          note_mouse_movement () call above */
5226       gen_help_event (help_echo_string, frame, help_echo_window,
5227                       help_echo_object, help_echo_pos);
5228     }
5229   else
5230     {
5231       help_echo_string = Qnil;
5232       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5233     }
5235   if (emacsframe->mouse_moved && send_appdefined)
5236     ns_send_appdefined (-1);
5240 - (void)mouseDragged: (NSEvent *)e
5242   NSTRACE (mouseDragged);
5243   [self mouseMoved: e];
5247 - (void)rightMouseDragged: (NSEvent *)e
5249   NSTRACE (rightMouseDragged);
5250   [self mouseMoved: e];
5254 - (void)otherMouseDragged: (NSEvent *)e
5256   NSTRACE (otherMouseDragged);
5257   [self mouseMoved: e];
5261 - (BOOL)windowShouldClose: (id)sender
5263   NSEvent *e =[[self window] currentEvent];
5265   NSTRACE (windowShouldClose);
5266   windowClosing = YES;
5267   if (!emacs_event)
5268     return NO;
5269   emacs_event->kind = DELETE_WINDOW_EVENT;
5270   emacs_event->modifiers = 0;
5271   emacs_event->code = 0;
5272   EV_TRAILER (e);
5273   /* Don't close this window, let this be done from lisp code.  */
5274   return NO;
5278 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5279 /* normalize frame to gridded text size */
5281   NSTRACE (windowWillResize);
5282 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5284   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5285 #ifdef NS_IMPL_GNUSTEP
5286                                         frameSize.width + 3);
5287 #else
5288                                         frameSize.width);
5289 #endif
5290   if (cols < MINWIDTH)
5291     cols = MINWIDTH;
5293   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
5294 #ifdef NS_IMPL_GNUSTEP
5295       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
5296         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5297 #else
5298       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5299         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5300 #endif
5301   if (rows < MINHEIGHT)
5302     rows = MINHEIGHT;
5303 #ifdef NS_IMPL_COCOA
5304   {
5305     /* this sets window title to have size in it; the wm does this under GS */
5306     NSRect r = [[self window] frame];
5307     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5308       {
5309         if (old_title != 0)
5310           {
5311             xfree (old_title);
5312             old_title = 0;
5313           }
5314       }
5315     else
5316       {
5317         char *size_title;
5318         NSWindow *window = [self window];
5319         if (old_title == 0)
5320           {
5321             const char *t = [[[self window] title] UTF8String];
5322             char *pos = strstr (t, "  â€”  ");
5323             if (pos)
5324               *pos = '\0';
5325             old_title = (char *) xmalloc (strlen (t) + 1);
5326             strcpy (old_title, t);
5327           }
5328         size_title = xmalloc (strlen (old_title) + 40);
5329         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5330         [window setTitle: [NSString stringWithUTF8String: size_title]];
5331         [window display];
5332         xfree (size_title);
5333       }
5334   }
5335 #endif /* NS_IMPL_COCOA */
5336 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5338   return frameSize;
5342 - (void)windowDidResize: (NSNotification *)notification
5344   NSWindow *theWindow = [notification object];
5346 #ifdef NS_IMPL_GNUSTEP
5347    /* in GNUstep, at least currently, it's possible to get a didResize
5348       without getting a willResize.. therefore we need to act as if we got
5349       the willResize now */
5350   NSSize sz = [theWindow frame].size;
5351   sz = [self windowWillResize: theWindow toSize: sz];
5352 #endif /* NS_IMPL_GNUSTEP */
5354   NSTRACE (windowDidResize);
5355 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5357 #ifdef NS_IMPL_COCOA
5358   if (old_title != 0)
5359     {
5360       xfree (old_title);
5361       old_title = 0;
5362     }
5363 #endif /* NS_IMPL_COCOA */
5365   /* Avoid loop under GNUstep due to call at beginning of this function.
5366      (x_set_window_size causes a resize which causes
5367      a "windowDidResize" which calls x_set_window_size).  */
5368 #ifndef NS_IMPL_GNUSTEP
5369   if (cols > 0 && rows > 0)
5370     {
5371       if (ns_in_resize)
5372         x_set_window_size (emacsframe, 0, cols, rows);
5373       else
5374         {
5375           NSWindow *window = [self window];
5376           NSRect wr = [window frame];
5377           FRAME_PIXEL_WIDTH (emacsframe) = (int)wr.size.width
5378             - emacsframe->border_width;
5379           FRAME_PIXEL_HEIGHT (emacsframe) = (int)wr.size.height
5380             - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5381             - FRAME_TOOLBAR_HEIGHT (emacsframe);
5382           change_frame_size (emacsframe, rows, cols, 0, 0, 1);
5383           SET_FRAME_GARBAGED (emacsframe);
5384           cancel_mouse_face (emacsframe);
5385         }
5386     }
5387 #endif
5389   ns_send_appdefined (-1);
5393 - (void)windowDidBecomeKey: (NSNotification *)notification
5394 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5396   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5397   struct frame *old_focus = dpyinfo->x_focus_frame;
5399   NSTRACE (windowDidBecomeKey);
5401   if (emacsframe != old_focus)
5402     dpyinfo->x_focus_frame = emacsframe;
5404   ns_frame_rehighlight (emacsframe);
5406   if (emacs_event)
5407     {
5408       emacs_event->kind = FOCUS_IN_EVENT;
5409       EV_TRAILER ((id)nil);
5410     }
5414 - (void)windowDidResignKey: (NSNotification *)notification
5415 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5417   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5418   NSTRACE (windowDidResignKey);
5420   if (dpyinfo->x_focus_frame == emacsframe)
5421     dpyinfo->x_focus_frame = 0;
5423   ns_frame_rehighlight (emacsframe);
5425   /* FIXME: for some reason needed on second and subsequent clicks away
5426             from sole-frame Emacs to get hollow box to show */
5427   if (!windowClosing && [[self window] isVisible] == YES)
5428     {
5429       x_update_cursor (emacsframe, 1);
5430       x_set_frame_alpha (emacsframe);
5431     }
5433   if (emacs_event)
5434     {
5435       [self deleteWorkingText];
5436       emacs_event->kind = FOCUS_IN_EVENT;
5437       EV_TRAILER ((id)nil);
5438     }
5442 - (void)windowWillMiniaturize: sender
5444   NSTRACE (windowWillMiniaturize);
5448 - (BOOL)isFlipped
5450   return YES;
5454 - (BOOL)isOpaque
5456   return NO;
5460 - initFrameFromEmacs: (struct frame *)f
5462   NSRect r, wr;
5463   Lisp_Object tem;
5464   NSWindow *win;
5465   NSButton *toggleButton;
5466   int vbextra = NS_SCROLL_BAR_WIDTH (f);
5467   NSSize sz;
5468   NSColor *col;
5469   NSString *name;
5471   NSTRACE (initFrameFromEmacs);
5473   windowClosing = NO;
5474   processingCompose = NO;
5475   scrollbarsNeedingUpdate = 0;
5477 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5479   ns_userRect = NSMakeRect (0, 0, 0, 0);
5480   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5481                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5482   [self initWithFrame: r];
5483   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5485   FRAME_NS_VIEW (f) = self;
5486   emacsframe = f;
5487   old_title = 0;
5489   win = [[EmacsWindow alloc]
5490             initWithContentRect: r
5491                       styleMask: (NSResizableWindowMask |
5492 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5493                                   NSTitledWindowMask |
5494 #endif
5495                                   NSMiniaturizableWindowMask |
5496                                   NSClosableWindowMask)
5497                         backing: NSBackingStoreBuffered
5498                           defer: YES];
5500   wr = [win frame];
5501   f->border_width = wr.size.width - r.size.width;
5502   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5504   [win setAcceptsMouseMovedEvents: YES];
5505   [win setDelegate: self];
5506   [win useOptimizedDrawing: YES];
5508   sz.width = FRAME_COLUMN_WIDTH (f);
5509   sz.height = FRAME_LINE_HEIGHT (f);
5510   [win setResizeIncrements: sz];
5512   [[win contentView] addSubview: self];
5514   if (ns_drag_types)
5515     [self registerForDraggedTypes: ns_drag_types];
5517   tem = f->name;
5518   name = [NSString stringWithUTF8String:
5519                    NILP (tem) ? (unsigned char *)"Emacs" : SDATA (tem)];
5520   [win setTitle: name];
5522   /* toolbar support */
5523   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5524                          [NSString stringWithFormat: @"Emacs Frame %d",
5525                                    ns_window_num]];
5526   [win setToolbar: toolbar];
5527   [toolbar setVisible: NO];
5528 #ifdef NS_IMPL_COCOA
5529   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5530   [toggleButton setTarget: self];
5531   [toggleButton setAction: @selector (toggleToolbar: )];
5532 #endif
5533   FRAME_TOOLBAR_HEIGHT (f) = 0;
5535   tem = f->icon_name;
5536   if (!NILP (tem))
5537     [win setMiniwindowTitle:
5538            [NSString stringWithUTF8String: SDATA (tem)]];
5540   {
5541     NSScreen *screen = [win screen];
5543     if (screen != 0)
5544       [win setFrameTopLeftPoint: NSMakePoint
5545            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5546             IN_BOUND (-SCREENMAX,
5547                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5548   }
5550   [win makeFirstResponder: self];
5552   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5553                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5554   [win setBackgroundColor: col];
5555   if ([col alphaComponent] != 1.0)
5556     [win setOpaque: NO];
5558   [self allocateGState];
5560   [NSApp registerServicesMenuSendTypes: ns_send_types
5561                            returnTypes: nil];
5563   ns_window_num++;
5564   return self;
5568 - (void)windowDidMove: sender
5570   NSWindow *win = [self window];
5571   NSRect r = [win frame];
5572   NSArray *screens = [NSScreen screens];
5573   NSScreen *screen = [screens objectAtIndex: 0];
5575   NSTRACE (windowDidMove);
5577   if (!emacsframe->output_data.ns)
5578     return;
5579   if (screen != nil)
5580     {
5581       emacsframe->left_pos = r.origin.x;
5582       emacsframe->top_pos =
5583         [screen frame].size.height - (r.origin.y + r.size.height);
5584     }
5588 /* Called AFTER method below, but before our windowWillResize call there leads
5589    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5590    location so set_window_size moves the frame. */
5591 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5593   emacsframe->output_data.ns->zooming = 1;
5594   return YES;
5598 /* Override to do something slightly nonstandard, but nice.  First click on
5599    zoom button will zoom vertically.  Second will zoom completely.  Third
5600    returns to original. */
5601 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5602                         defaultFrame:(NSRect)defaultFrame
5604   NSRect result = [sender frame];
5606   NSTRACE (windowWillUseStandardFrame);
5608   if (abs (defaultFrame.size.height - result.size.height)
5609       > FRAME_LINE_HEIGHT (emacsframe))
5610     {
5611       /* first click */
5612       ns_userRect = result;
5613       result.size.height = defaultFrame.size.height;
5614       result.origin.y = defaultFrame.origin.y;
5615     }
5616   else
5617     {
5618       if (abs (defaultFrame.size.width - result.size.width)
5619           > FRAME_COLUMN_WIDTH (emacsframe))
5620         result = defaultFrame;  /* second click */
5621       else
5622         {
5623           /* restore */
5624           result = ns_userRect.size.height ? ns_userRect : result;
5625           ns_userRect = NSMakeRect (0, 0, 0, 0);
5626         }
5627     }
5629   [self windowWillResize: sender toSize: result.size];
5630   return result;
5634 - (void)windowDidDeminiaturize: sender
5636   NSTRACE (windowDidDeminiaturize);
5637   if (!emacsframe->output_data.ns)
5638     return;
5639   emacsframe->async_iconified = 0;
5640   emacsframe->async_visible   = 1;
5641   windows_or_buffers_changed++;
5643   if (emacs_event)
5644     {
5645       emacs_event->kind = ICONIFY_EVENT;
5646       EV_TRAILER ((id)nil);
5647     }
5651 - (void)windowDidExpose: sender
5653   NSTRACE (windowDidExpose);
5654   if (!emacsframe->output_data.ns)
5655     return;
5656   emacsframe->async_visible = 1;
5657   SET_FRAME_GARBAGED (emacsframe);
5659   if (send_appdefined)
5660     ns_send_appdefined (-1);
5664 - (void)windowDidMiniaturize: sender
5666   NSTRACE (windowDidMiniaturize);
5667   if (!emacsframe->output_data.ns)
5668     return;
5670   emacsframe->async_iconified = 1;
5671   emacsframe->async_visible = 0;
5673   if (emacs_event)
5674     {
5675       emacs_event->kind = ICONIFY_EVENT;
5676       EV_TRAILER ((id)nil);
5677     }
5681 - (void)mouseEntered: (NSEvent *)theEvent
5683   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5684   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5685   NSTRACE (mouseEntered);
5687   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5691 - (void)mouseExited: (NSEvent *)theEvent
5693   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5694   NSRect r;
5695   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
5697   NSTRACE (mouseExited);
5699   if (!hlinfo)
5700     return;
5702   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5704   if (emacsframe == hlinfo->mouse_face_mouse_frame)
5705     {
5706       clear_mouse_face (hlinfo);
5707       hlinfo->mouse_face_mouse_frame = 0;
5708     }
5712 - menuDown: sender
5714   NSTRACE (menuDown);
5715   if (context_menu_value == -1)
5716     context_menu_value = [sender tag];
5717   else
5718     find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5719                                   emacsframe->menu_bar_vector,
5720                                   (void *)[sender tag]);
5721   ns_send_appdefined (-1);
5722   return self;
5726 - (EmacsToolbar *)toolbar
5728   return toolbar;
5732 /* this gets called on toolbar button click */
5733 - toolbarClicked: (id)item
5735   NSEvent *theEvent;
5736   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5738   NSTRACE (toolbarClicked);
5740   if (!emacs_event)
5741     return self;
5743   /* send first event (for some reason two needed) */
5744   theEvent = [[self window] currentEvent];
5745   emacs_event->kind = TOOL_BAR_EVENT;
5746   XSETFRAME (emacs_event->arg, emacsframe);
5747   EV_TRAILER (theEvent);
5749   emacs_event->kind = TOOL_BAR_EVENT;
5750 /*   XSETINT (emacs_event->code, 0); */
5751   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5752                           idx + TOOL_BAR_ITEM_KEY);
5753   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5754   EV_TRAILER (theEvent);
5755   return self;
5759 - toggleToolbar: (id)sender
5761   if (!emacs_event)
5762     return self;
5764   emacs_event->kind = NS_NONKEY_EVENT;
5765   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
5766   EV_TRAILER ((id)nil);
5767   return self;
5771 - (void)drawRect: (NSRect)rect
5773   int x = NSMinX (rect), y = NSMinY (rect);
5774   int width = NSWidth (rect), height = NSHeight (rect);
5776   NSTRACE (drawRect);
5778   if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
5779     return;
5781   ns_clear_frame_area (emacsframe, x, y, width, height);
5782   expose_frame (emacsframe, x, y, width, height);
5784   /*
5785     drawRect: may be called (at least in OS X 10.5) for invisible
5786     views as well for some reason.  Thus, do not infer visibility
5787     here.
5789     emacsframe->async_visible = 1;
5790     emacsframe->async_iconified = 0;
5791   */
5795 /* NSDraggingDestination protocol methods.  Actually this is not really a
5796    protocol, but a category of Object.  O well...  */
5798 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
5800   NSTRACE (draggingEntered);
5801   return NSDragOperationGeneric;
5805 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5807   return YES;
5811 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5813   id pb;
5814   int x, y;
5815   NSString *type;
5816   NSEvent *theEvent = [[self window] currentEvent];
5817   NSPoint position;
5819   NSTRACE (performDragOperation);
5821   if (!emacs_event)
5822     return NO;
5824   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5825   x = lrint (position.x);  y = lrint (position.y);
5827   pb = [sender draggingPasteboard];
5828   type = [pb availableTypeFromArray: ns_drag_types];
5829   if (type == 0)
5830     {
5831       return NO;
5832     }
5833   else if ([type isEqualToString: NSFilenamesPboardType])
5834     {
5835       NSArray *files;
5836       NSEnumerator *fenum;
5837       NSString *file;
5839       if (!(files = [pb propertyListForType: type]))
5840         return NO;
5842       fenum = [files objectEnumerator];
5843       while ( (file = [fenum nextObject]) )
5844         {
5845           emacs_event->kind = NS_NONKEY_EVENT;
5846           emacs_event->code = KEY_NS_DRAG_FILE;
5847           XSETINT (emacs_event->x, x);
5848           XSETINT (emacs_event->y, y);
5849           ns_input_file = append2 (ns_input_file,
5850                                    build_string ([file UTF8String]));
5851           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5852           EV_TRAILER (theEvent);
5853         }
5854       return YES;
5855     }
5856   else if ([type isEqualToString: NSURLPboardType])
5857     {
5858       NSString *file;
5859       NSURL *fileURL;
5861       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5862           [fileURL isFileURL] == NO)
5863         return NO;
5865       file = [fileURL path];
5866       emacs_event->kind = NS_NONKEY_EVENT;
5867       emacs_event->code = KEY_NS_DRAG_FILE;
5868       XSETINT (emacs_event->x, x);
5869       XSETINT (emacs_event->y, y);
5870       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5871       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5872       EV_TRAILER (theEvent);
5873       return YES;
5874     }
5875   else if ([type isEqualToString: NSStringPboardType]
5876            || [type isEqualToString: NSTabularTextPboardType])
5877     {
5878       NSString *data;
5880       if (! (data = [pb stringForType: type]))
5881         return NO;
5883       emacs_event->kind = NS_NONKEY_EVENT;
5884       emacs_event->code = KEY_NS_DRAG_TEXT;
5885       XSETINT (emacs_event->x, x);
5886       XSETINT (emacs_event->y, y);
5887       ns_input_text = build_string ([data UTF8String]);
5888       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5889       EV_TRAILER (theEvent);
5890       return YES;
5891     }
5892   else if ([type isEqualToString: NSColorPboardType])
5893     {
5894       NSColor *c = [NSColor colorFromPasteboard: pb];
5895       emacs_event->kind = NS_NONKEY_EVENT;
5896       emacs_event->code = KEY_NS_DRAG_COLOR;
5897       XSETINT (emacs_event->x, x);
5898       XSETINT (emacs_event->y, y);
5899       ns_input_color = ns_color_to_lisp (c);
5900       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5901       EV_TRAILER (theEvent);
5902       return YES;
5903     }
5904   else if ([type isEqualToString: NSFontPboardType])
5905     {
5906       /* impl based on GNUstep NSTextView.m */
5907       NSData *data = [pb dataForType: NSFontPboardType];
5908       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5909       NSFont *font = [dict objectForKey: NSFontAttributeName];
5910       char fontSize[10];
5912       if (font == nil)
5913         return NO;
5915       emacs_event->kind = NS_NONKEY_EVENT;
5916       emacs_event->code = KEY_NS_CHANGE_FONT;
5917       XSETINT (emacs_event->x, x);
5918       XSETINT (emacs_event->y, y);
5919       ns_input_font = build_string ([[font fontName] UTF8String]);
5920       snprintf (fontSize, 10, "%f", [font pointSize]);
5921       ns_input_fontsize = build_string (fontSize);
5922       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5923       EV_TRAILER (theEvent);
5924       return YES;
5925     }
5926   else
5927     {
5928       error ("Invalid data type in dragging pasteboard.");
5929       return NO;
5930     }
5934 - (id) validRequestorForSendType: (NSString *)typeSent
5935                       returnType: (NSString *)typeReturned
5937   NSTRACE (validRequestorForSendType);
5938   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
5939       && typeReturned == nil)
5940     {
5941       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
5942         return self;
5943     }
5945   return [super validRequestorForSendType: typeSent
5946                                returnType: typeReturned];
5950 /* The next two methods are part of NSServicesRequests informal protocol,
5951    supposedly called when a services menu item is chosen from this app.
5952    But this should not happen because we override the services menu with our
5953    own entries which call ns-perform-service.
5954    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
5955    So let's at least stub them out until further investigation can be done. */
5957 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
5959   /* we could call ns_string_from_pasteboard(pboard) here but then it should
5960      be written into the buffer in place of the existing selection..
5961      ordinary service calls go through functions defined in ns-win.el */
5962   return NO;
5965 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
5967   NSArray *typesDeclared;
5968   Lisp_Object val;
5970   /* We only support NSStringPboardType */
5971   if ([types containsObject:NSStringPboardType] == NO) {
5972     return NO;
5973   }
5975   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
5976   if (CONSP (val) && SYMBOLP (XCAR (val)))
5977     {
5978       val = XCDR (val);
5979       if (CONSP (val) && NILP (XCDR (val)))
5980         val = XCAR (val);
5981     }
5982   if (! STRINGP (val))
5983     return NO;
5985   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
5986   [pb declareTypes:typesDeclared owner:nil];
5987   ns_string_to_pasteboard (pb, val);
5988   return YES;
5992 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
5993    (gives a miniaturized version of the window); currently we use the latter for
5994    frames whose active buffer doesn't correspond to any file
5995    (e.g., '*scratch*') */
5996 - setMiniwindowImage: (BOOL) setMini
5998   id image = [[self window] miniwindowImage];
5999   NSTRACE (setMiniwindowImage);
6001   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6002      about "AppleDockIconEnabled" notwithstanding, however the set message
6003      below has its effect nonetheless. */
6004   if (image != emacsframe->output_data.ns->miniimage)
6005     {
6006       if (image && [image isKindOfClass: [EmacsImage class]])
6007         [image release];
6008       [[self window] setMiniwindowImage:
6009                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6010     }
6012   return self;
6016 - (void) setRows: (int) r andColumns: (int) c
6018   rows = r;
6019   cols = c;
6022 @end  /* EmacsView */
6026 /* ==========================================================================
6028     EmacsWindow implementation
6030    ========================================================================== */
6032 @implementation EmacsWindow
6034 /* If we have multiple monitors, one above the other, we don't want to
6035    restrict the height to just one monitor.  So we override this.  */
6036 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6038   /* When making the frame visible for the first time or if there is just
6039      one screen, we want to constrain.  Other times not.  */
6040   NSUInteger nr_screens = [[NSScreen screens] count];
6041   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6042   NSTRACE (constrainFrameRect);
6044   if (nr_screens == 1)
6045     return [super constrainFrameRect:frameRect toScreen:screen];
6046   
6047   if (f->output_data.ns->dont_constrain
6048       || ns_menu_bar_should_be_hidden ())
6049     return frameRect;
6051   f->output_data.ns->dont_constrain = 1;
6052   return [super constrainFrameRect:frameRect toScreen:screen];
6056 /* called only on resize clicks by special case in EmacsApp-sendEvent */
6057 - (void)mouseDown: (NSEvent *)theEvent
6059   if (ns_in_resize)
6060     {
6061       NSSize size = [[theEvent window] frame].size;
6062       grabOffset = [theEvent locationInWindow];
6063       grabOffset.x = size.width - grabOffset.x;
6064     }
6065   else
6066     [super mouseDown: theEvent];
6070 /* stop resizing */
6071 - (void)mouseUp: (NSEvent *)theEvent
6073   if (ns_in_resize)
6074     {
6075       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6076       ns_in_resize = NO;
6077       ns_set_name_as_filename (f);
6078       [self display];
6079       ns_send_appdefined (-1);
6080     }
6081   else
6082     [super mouseUp: theEvent];
6086 /* send resize events */
6087 - (void)mouseDragged: (NSEvent *)theEvent
6089   if (ns_in_resize)
6090     {
6091       NSPoint p = [theEvent locationInWindow];
6092       NSSize size, vettedSize, origSize = [self frame].size;
6094       size.width = p.x + grabOffset.x;
6095       size.height = origSize.height - p.y + grabOffset.y;
6097       if (size.width == origSize.width && size.height == origSize.height)
6098         return;
6100       vettedSize = [[self delegate] windowWillResize: self toSize: size];
6101       [[NSNotificationCenter defaultCenter]
6102             postNotificationName: NSWindowDidResizeNotification
6103                           object: self];
6104     }
6105   else
6106     [super mouseDragged: theEvent];
6109 @end /* EmacsWindow */
6112 /* ==========================================================================
6114     EmacsScroller implementation
6116    ========================================================================== */
6119 @implementation EmacsScroller
6121 /* for repeat button push */
6122 #define SCROLL_BAR_FIRST_DELAY 0.5
6123 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6125 + (CGFloat) scrollerWidth
6127   /* TODO: if we want to allow variable widths, this is the place to do it,
6128            however neither GNUstep nor Cocoa support it very well */
6129   return [NSScroller scrollerWidth];
6133 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6135   NSTRACE (EmacsScroller_initFrame);
6137   r.size.width = [EmacsScroller scrollerWidth];
6138   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6139   [self setContinuous: YES];
6140   [self setEnabled: YES];
6142   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6143      locked against the top and bottom edges, and right edge on OS X, where
6144      scrollers are on right. */
6145 #ifdef NS_IMPL_GNUSTEP
6146   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6147 #else
6148   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6149 #endif
6151   win = nwin;
6152   condemned = NO;
6153   pixel_height = NSHeight (r);
6154   if (pixel_height == 0) pixel_height = 1;
6155   min_portion = 20 / pixel_height;
6157   frame = XFRAME (XWINDOW (win)->frame);
6158   if (FRAME_LIVE_P (frame))
6159     {
6160       int i;
6161       EmacsView *view = FRAME_NS_VIEW (frame);
6162       NSView *sview = [[view window] contentView];
6163       NSArray *subs = [sview subviews];
6165       /* disable optimization stopping redraw of other scrollbars */
6166       view->scrollbarsNeedingUpdate = 0;
6167       for (i =[subs count]-1; i >= 0; i--)
6168         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6169           view->scrollbarsNeedingUpdate++;
6170       [sview addSubview: self];
6171     }
6173 /*  [self setFrame: r]; */
6175   return self;
6179 - (void)setFrame: (NSRect)newRect
6181   NSTRACE (EmacsScroller_setFrame);
6182 /*  BLOCK_INPUT; */
6183   pixel_height = NSHeight (newRect);
6184   if (pixel_height == 0) pixel_height = 1;
6185   min_portion = 20 / pixel_height;
6186   [super setFrame: newRect];
6187   [self display];
6188 /*  UNBLOCK_INPUT; */
6192 - (void)dealloc
6194   NSTRACE (EmacsScroller_dealloc);
6195   if (!NILP (win))
6196     XWINDOW (win)->vertical_scroll_bar = Qnil;
6197   [super dealloc];
6201 - condemn
6203   NSTRACE (condemn);
6204   condemned =YES;
6205   return self;
6209 - reprieve
6211   NSTRACE (reprieve);
6212   condemned =NO;
6213   return self;
6217 - judge
6219   NSTRACE (judge);
6220   if (condemned)
6221     {
6222       EmacsView *view;
6223       BLOCK_INPUT;
6224       /* ensure other scrollbar updates after deletion */
6225       view = (EmacsView *)FRAME_NS_VIEW (frame);
6226       if (view != nil)
6227         view->scrollbarsNeedingUpdate++;
6228       [self removeFromSuperview];
6229       [self release];
6230       UNBLOCK_INPUT;
6231     }
6232   return self;
6236 - (void)resetCursorRects
6238   NSRect visible = [self visibleRect];
6239   NSTRACE (resetCursorRects);
6241   if (!NSIsEmptyRect (visible))
6242     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6243   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6247 - (int) checkSamePosition: (int) position portion: (int) portion
6248                     whole: (int) whole
6250   return em_position ==position && em_portion ==portion && em_whole ==whole
6251     && portion != whole; /* needed for resize empty buf */
6255 - setPosition: (int)position portion: (int)portion whole: (int)whole
6257   NSTRACE (setPosition);
6259   em_position = position;
6260   em_portion = portion;
6261   em_whole = whole;
6263   if (portion >= whole)
6264     {
6265 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6266       [self setKnobProportion: 1.0];
6267       [self setDoubleValue: 1.0];
6268 #else
6269       [self setFloatValue: 0.0 knobProportion: 1.0];
6270 #endif
6271     }
6272   else
6273     {
6274       float pos, por;
6275       portion = max ((float)whole*min_portion/pixel_height, portion);
6276       pos = (float)position / (whole - portion);
6277       por = (float)portion/whole;
6278 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6279       [self setKnobProportion: por];
6280       [self setDoubleValue: pos];
6281 #else
6282       [self setFloatValue: pos knobProportion: por];
6283 #endif
6284     }
6285   return self;
6288 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6289      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6290 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6291                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6293   *part = last_hit_part;
6294   *window = win;
6295   XSETINT (*y, pixel_height);
6296   if ([self floatValue] > 0.999)
6297     XSETINT (*x, pixel_height);
6298   else
6299     XSETINT (*x, pixel_height * [self floatValue]);
6303 /* set up emacs_event */
6304 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6306   if (!emacs_event)
6307     return;
6309   emacs_event->part = last_hit_part;
6310   emacs_event->code = 0;
6311   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6312   emacs_event->frame_or_window = win;
6313   emacs_event->timestamp = EV_TIMESTAMP (e);
6314   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6315   emacs_event->arg = Qnil;
6316   XSETINT (emacs_event->x, loc * pixel_height);
6317   XSETINT (emacs_event->y, pixel_height-20);
6319   n_emacs_events_pending++;
6320   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6321   EVENT_INIT (*emacs_event);
6322   ns_send_appdefined (-1);
6326 /* called manually thru timer to implement repeated button action w/hold-down */
6327 - repeatScroll: (NSTimer *)scrollEntry
6329   NSEvent *e = [[self window] currentEvent];
6330   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6331   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6333   /* clear timer if need be */
6334   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6335     {
6336         [scroll_repeat_entry invalidate];
6337         [scroll_repeat_entry release];
6338         scroll_repeat_entry = nil;
6340         if (inKnob)
6341           return self;
6343         scroll_repeat_entry
6344           = [[NSTimer scheduledTimerWithTimeInterval:
6345                         SCROLL_BAR_CONTINUOUS_DELAY
6346                                             target: self
6347                                           selector: @selector (repeatScroll:)
6348                                           userInfo: 0
6349                                            repeats: YES]
6350               retain];
6351     }
6353   [self sendScrollEventAtLoc: 0 fromEvent: e];
6354   return self;
6358 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6359    mouseDragged events without going into a modal loop. */
6360 - (void)mouseDown: (NSEvent *)e
6362   NSRect sr, kr;
6363   /* hitPart is only updated AFTER event is passed on */
6364   NSScrollerPart part = [self testPart: [e locationInWindow]];
6365   double inc = 0.0, loc, kloc, pos;
6366   int edge = 0;
6368   NSTRACE (EmacsScroller_mouseDown);
6370   switch (part)
6371     {
6372     case NSScrollerDecrementPage:
6373         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6374     case NSScrollerIncrementPage:
6375         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6376     case NSScrollerDecrementLine:
6377       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6378     case NSScrollerIncrementLine:
6379       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6380     case NSScrollerKnob:
6381       last_hit_part = scroll_bar_handle; break;
6382     case NSScrollerKnobSlot:  /* GNUstep-only */
6383       last_hit_part = scroll_bar_move_ratio; break;
6384     default:  /* NSScrollerNoPart? */
6385       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6386                (long) part);
6387       return;
6388     }
6390   if (inc != 0.0)
6391     {
6392       pos = 0;      /* ignored */
6394       /* set a timer to repeat, as we can't let superclass do this modally */
6395       scroll_repeat_entry
6396         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6397                                             target: self
6398                                           selector: @selector (repeatScroll:)
6399                                           userInfo: 0
6400                                            repeats: YES]
6401             retain];
6402     }
6403   else
6404     {
6405       /* handle, or on GNUstep possibly slot */
6406       NSEvent *fake_event;
6408       /* compute float loc in slot and mouse offset on knob */
6409       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6410                       toView: nil];
6411       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6412       if (loc <= 0.0)
6413         {
6414           loc = 0.0;
6415           edge = -1;
6416         }
6417       else if (loc >= NSHeight (sr))
6418         {
6419           loc = NSHeight (sr);
6420           edge = 1;
6421         }
6423       if (edge)
6424         kloc = 0.5 * edge;
6425       else
6426         {
6427           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6428                           toView: nil];
6429           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6430         }
6431       last_mouse_offset = kloc;
6433       /* if knob, tell emacs a location offset by knob pos
6434          (to indicate top of handle) */
6435       if (part == NSScrollerKnob)
6436           pos = (loc - last_mouse_offset) / NSHeight (sr);
6437       else
6438         /* else this is a slot click on GNUstep: go straight there */
6439         pos = loc / NSHeight (sr);
6441       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6442       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6443                                       location: [e locationInWindow]
6444                                  modifierFlags: [e modifierFlags]
6445                                      timestamp: [e timestamp]
6446                                   windowNumber: [e windowNumber]
6447                                        context: [e context]
6448                                    eventNumber: [e eventNumber]
6449                                     clickCount: [e clickCount]
6450                                       pressure: [e pressure]];
6451       [super mouseUp: fake_event];
6452     }
6454   if (part != NSScrollerKnob)
6455     [self sendScrollEventAtLoc: pos fromEvent: e];
6459 /* Called as we manually track scroller drags, rather than superclass. */
6460 - (void)mouseDragged: (NSEvent *)e
6462     NSRect sr;
6463     double loc, pos;
6464     int edge = 0;
6466     NSTRACE (EmacsScroller_mouseDragged);
6468       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6469                       toView: nil];
6470       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6472       if (loc <= 0.0)
6473         {
6474           loc = 0.0;
6475           edge = -1;
6476         }
6477       else if (loc >= NSHeight (sr) + last_mouse_offset)
6478         {
6479           loc = NSHeight (sr) + last_mouse_offset;
6480           edge = 1;
6481         }
6483       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6484       [self sendScrollEventAtLoc: pos fromEvent: e];
6488 - (void)mouseUp: (NSEvent *)e
6490   if (scroll_repeat_entry)
6491     {
6492       [scroll_repeat_entry invalidate];
6493       [scroll_repeat_entry release];
6494       scroll_repeat_entry = nil;
6495     }
6496   last_hit_part = 0;
6500 /* treat scrollwheel events in the bar as though they were in the main window */
6501 - (void) scrollWheel: (NSEvent *)theEvent
6503   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6504   [view mouseDown: theEvent];
6507 @end  /* EmacsScroller */
6512 /* ==========================================================================
6514    Font-related functions; these used to be in nsfaces.m
6516    ========================================================================== */
6519 Lisp_Object
6520 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6522   struct font *font = XFONT_OBJECT (font_object);
6524   if (fontset < 0)
6525     fontset = fontset_from_font (font_object);
6526   FRAME_FONTSET (f) = fontset;
6528   if (FRAME_FONT (f) == font)
6529     /* This font is already set in frame F.  There's nothing more to
6530        do.  */
6531     return font_object;
6533   FRAME_FONT (f) = font;
6535   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6536   FRAME_COLUMN_WIDTH (f) = font->average_width;
6537   FRAME_SPACE_WIDTH (f) = font->space_width;
6538   FRAME_LINE_HEIGHT (f) = font->height;
6540   compute_fringe_widths (f, 1);
6542   /* Compute the scroll bar width in character columns.  */
6543   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6544     {
6545       int wid = FRAME_COLUMN_WIDTH (f);
6546       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6547         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6548     }
6549   else
6550     {
6551       int wid = FRAME_COLUMN_WIDTH (f);
6552       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6553     }
6555   /* Now make the frame display the given font.  */
6556   if (FRAME_NS_WINDOW (f) != 0)
6557         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6559   return font_object;
6563 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6564 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6565          in 1.43. */
6567 const char *
6568 ns_xlfd_to_fontname (const char *xlfd)
6569 /* --------------------------------------------------------------------------
6570     Convert an X font name (XLFD) to an NS font name.
6571     Only family is used.
6572     The string returned is temporarily allocated.
6573    -------------------------------------------------------------------------- */
6575   char *name = xmalloc (180);
6576   int i, len;
6577   const char *ret;
6579   if (!strncmp (xlfd, "--", 2))
6580     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6581   else
6582     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6584   /* stopgap for malformed XLFD input */
6585   if (strlen (name) == 0)
6586     strcpy (name, "Monaco");
6588   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6589      also uppercase after '-' or ' ' */
6590   name[0] = toupper (name[0]);
6591   for (len =strlen (name), i =0; i<len; i++)
6592     {
6593       if (name[i] == '$')
6594         {
6595           name[i] = '-';
6596           if (i+1<len)
6597             name[i+1] = toupper (name[i+1]);
6598         }
6599       else if (name[i] == '_')
6600         {
6601           name[i] = ' ';
6602           if (i+1<len)
6603             name[i+1] = toupper (name[i+1]);
6604         }
6605     }
6606 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6607   ret = [[NSString stringWithUTF8String: name] UTF8String];
6608   xfree (name);
6609   return ret;
6613 void
6614 syms_of_nsterm (void)
6616   NSTRACE (syms_of_nsterm);
6618   ns_antialias_threshold = 10.0;
6620   /* from 23+ we need to tell emacs what modifiers there are.. */
6621   DEFSYM (Qmodifier_value, "modifier-value");
6622   DEFSYM (Qalt, "alt");
6623   DEFSYM (Qhyper, "hyper");
6624   DEFSYM (Qmeta, "meta");
6625   DEFSYM (Qsuper, "super");
6626   DEFSYM (Qcontrol, "control");
6627   DEFSYM (Qnone, "none");
6628   DEFSYM (QUTF8_STRING, "UTF8_STRING");
6630   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6631   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6632   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6633   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6634   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6636   DEFVAR_LISP ("ns-input-file", ns_input_file,
6637               "The file specified in the last NS event.");
6638   ns_input_file =Qnil;
6640   DEFVAR_LISP ("ns-input-text", ns_input_text,
6641               "The data received in the last NS text drag event.");
6642   ns_input_text =Qnil;
6644   DEFVAR_LISP ("ns-working-text", ns_working_text,
6645               "String for visualizing working composition sequence.");
6646   ns_working_text =Qnil;
6648   DEFVAR_LISP ("ns-input-font", ns_input_font,
6649               "The font specified in the last NS event.");
6650   ns_input_font =Qnil;
6652   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
6653               "The fontsize specified in the last NS event.");
6654   ns_input_fontsize =Qnil;
6656   DEFVAR_LISP ("ns-input-line", ns_input_line,
6657                "The line specified in the last NS event.");
6658   ns_input_line =Qnil;
6660   DEFVAR_LISP ("ns-input-color", ns_input_color,
6661                "The color specified in the last NS event.");
6662   ns_input_color =Qnil;
6664   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
6665                "The service name specified in the last NS event.");
6666   ns_input_spi_name =Qnil;
6668   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
6669                "The service argument specified in the last NS event.");
6670   ns_input_spi_arg =Qnil;
6672   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
6673                "This variable describes the behavior of the alternate or option key.\n\
6674 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6675 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6676 at all, allowing it to be used at a lower level for accented character entry.");
6677   ns_alternate_modifier = Qmeta;
6679   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
6680                "This variable describes the behavior of the right alternate or option key.\n\
6681 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6682 Set to left means be the same key as `ns-alternate-modifier'.\n\
6683 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6684 at all, allowing it to be used at a lower level for accented character entry.");
6685   ns_right_alternate_modifier = Qleft;
6687   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
6688                "This variable describes the behavior of the command key.\n\
6689 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6690   ns_command_modifier = Qsuper;
6692   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
6693                "This variable describes the behavior of the right command key.\n\
6694 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6695 Set to left means be the same key as `ns-command-modifier'.\n\
6696 Set to none means that the command / option key is not interpreted by Emacs\n\
6697 at all, allowing it to be used at a lower level for accented character entry.");
6698   ns_right_command_modifier = Qleft;
6700   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
6701                "This variable describes the behavior of the control key.\n\
6702 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6703   ns_control_modifier = Qcontrol;
6705   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
6706                "This variable describes the behavior of the right control key.\n\
6707 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6708 Set to left means be the same key as `ns-control-modifier'.\n\
6709 Set to none means that the control / option key is not interpreted by Emacs\n\
6710 at all, allowing it to be used at a lower level for accented character entry.");
6711   ns_right_control_modifier = Qleft;
6713   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
6714                "This variable describes the behavior of the function key (on laptops).\n\
6715 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6716 Set to none means that the function key is not interpreted by Emacs at all,\n\
6717 allowing it to be used at a lower level for accented character entry.");
6718   ns_function_modifier = Qnone;
6720   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
6721                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6722   ns_antialias_text = Qt;
6724   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
6725                "Whether to confirm application quit using dialog.");
6726   ns_confirm_quit = Qnil;
6728   staticpro (&ns_display_name_list);
6729   ns_display_name_list = Qnil;
6731   staticpro (&last_mouse_motion_frame);
6732   last_mouse_motion_frame = Qnil;
6734   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
6735                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
6736 Only works on OSX 10.6 or later.  */);
6737   ns_auto_hide_menu_bar = Qnil;
6739   /* TODO: move to common code */
6740   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
6741                doc: /* Which toolkit scroll bars Emacs uses, if any.
6742 A value of nil means Emacs doesn't use toolkit scroll bars.
6743 With the X Window system, the value is a symbol describing the
6744 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
6745 With MS Windows or Nextstep, the value is t.  */);
6746   Vx_toolkit_scroll_bars = Qt;
6748   DEFVAR_BOOL ("x-use-underline-position-properties",
6749                x_use_underline_position_properties,
6750      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
6751 A value of nil means ignore them.  If you encounter fonts with bogus
6752 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6753 to 4.1, set this to nil. */);
6754   x_use_underline_position_properties = 0;
6756   DEFVAR_BOOL ("x-underline-at-descent-line",
6757                x_underline_at_descent_line,
6758      doc: /* Non-nil means to draw the underline at the same place as the descent line.
6759 A value of nil means to draw the underline according to the value of the
6760 variable `x-use-underline-position-properties', which is usually at the
6761 baseline level.  The default value is nil.  */);
6762   x_underline_at_descent_line = 0;
6764   /* Tell emacs about this window system. */
6765   Fprovide (intern ("ns"), Qnil);