* simple.el (current-kill): Clarify what `interprogram-paste-function' does.
[emacs.git] / src / nsterm.m
blob546247ab74ac817dc39d35cbcc6c7a3f3d700f03
1 /* NeXT/Open/GNUstep / MacOSX communication module.
2    Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2011
3      Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
21 Originally by Carl Edman
22 Updated by Christian Limpach (chris@nice.ch)
23 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
24 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
25 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
28 /* This should be the first include, as it may set up #defines affecting
29    interpretation of even the system includes. */
30 #include <config.h>
32 #include <math.h>
33 #include <sys/types.h>
34 #include <time.h>
35 #include <signal.h>
36 #include <unistd.h>
37 #include <setjmp.h>
39 #include "lisp.h"
40 #include "blockinput.h"
41 #include "sysselect.h"
42 #include "nsterm.h"
43 #include "systime.h"
44 #include "character.h"
45 #include "fontset.h"
46 #include "composite.h"
47 #include "ccl.h"
49 #include "termhooks.h"
50 #include "termopts.h"
51 #include "termchar.h"
53 #include "window.h"
54 #include "keyboard.h"
56 #include "font.h"
58 /* call tracing */
59 #if 0
60 int term_trace_num = 0;
61 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
62                                 __FILE__, __LINE__, ++term_trace_num)
63 #else
64 #define NSTRACE(x)
65 #endif
68 /* ==========================================================================
70     Local declarations
72    ========================================================================== */
74 /* Convert a symbol indexed with an NSxxx value to a value as defined
75    in keyboard.c (lispy_function_key). I hope this is a correct way
76    of doing things... */
77 static unsigned convert_ns_to_X_keysym[] =
79   NSHomeFunctionKey,            0x50,
80   NSLeftArrowFunctionKey,       0x51,
81   NSUpArrowFunctionKey,         0x52,
82   NSRightArrowFunctionKey,      0x53,
83   NSDownArrowFunctionKey,       0x54,
84   NSPageUpFunctionKey,          0x55,
85   NSPageDownFunctionKey,        0x56,
86   NSEndFunctionKey,             0x57,
87   NSBeginFunctionKey,           0x58,
88   NSSelectFunctionKey,          0x60,
89   NSPrintFunctionKey,           0x61,
90   NSExecuteFunctionKey,         0x62,
91   NSInsertFunctionKey,          0x63,
92   NSUndoFunctionKey,            0x65,
93   NSRedoFunctionKey,            0x66,
94   NSMenuFunctionKey,            0x67,
95   NSFindFunctionKey,            0x68,
96   NSHelpFunctionKey,            0x6A,
97   NSBreakFunctionKey,           0x6B,
99   NSF1FunctionKey,              0xBE,
100   NSF2FunctionKey,              0xBF,
101   NSF3FunctionKey,              0xC0,
102   NSF4FunctionKey,              0xC1,
103   NSF5FunctionKey,              0xC2,
104   NSF6FunctionKey,              0xC3,
105   NSF7FunctionKey,              0xC4,
106   NSF8FunctionKey,              0xC5,
107   NSF9FunctionKey,              0xC6,
108   NSF10FunctionKey,             0xC7,
109   NSF11FunctionKey,             0xC8,
110   NSF12FunctionKey,             0xC9,
111   NSF13FunctionKey,             0xCA,
112   NSF14FunctionKey,             0xCB,
113   NSF15FunctionKey,             0xCC,
114   NSF16FunctionKey,             0xCD,
115   NSF17FunctionKey,             0xCE,
116   NSF18FunctionKey,             0xCF,
117   NSF19FunctionKey,             0xD0,
118   NSF20FunctionKey,             0xD1,
119   NSF21FunctionKey,             0xD2,
120   NSF22FunctionKey,             0xD3,
121   NSF23FunctionKey,             0xD4,
122   NSF24FunctionKey,             0xD5,
124   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
125   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
126   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
128   NSTabCharacter,               0x09,
129   0x19,                         0x09,  /* left tab->regular since pass shift */
130   NSCarriageReturnCharacter,    0x0D,
131   NSNewlineCharacter,           0x0D,
132   NSEnterCharacter,             0x8D,
134   0x1B,                         0x1B   /* escape */
137 static Lisp_Object Qmodifier_value;
138 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper, Qnone;
139 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
141 static Lisp_Object QUTF8_STRING;
143 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
144    the maximum font size to NOT antialias.  On GNUstep there is currently
145    no way to control this behavior. */
146 float ns_antialias_threshold;
148 /* Used to pick up AppleHighlightColor on OS X */
149 NSString *ns_selection_color;
151 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
152 NSString *ns_app_name = @"Emacs";  /* default changed later */
154 /* Display variables */
155 struct ns_display_info *x_display_list; /* Chain of existing displays */
156 Lisp_Object ns_display_name_list;
157 long context_menu_value = 0;
159 /* display update */
160 NSPoint last_mouse_motion_position;
161 static NSRect last_mouse_glyph;
162 static Time last_mouse_movement_time = 0;
163 static Lisp_Object last_mouse_motion_frame;
164 static EmacsScroller *last_mouse_scroll_bar = nil;
165 static struct frame *ns_updating_frame;
166 static NSView *focus_view = NULL;
167 static int ns_window_num =0;
168 static NSRect uRect;
169 static BOOL gsaved = NO;
170 BOOL ns_in_resize = NO;
171 static BOOL ns_fake_keydown = NO;
172 int ns_tmp_flags; /* FIXME */
173 struct nsfont_info *ns_tmp_font; /* FIXME */
174 static BOOL ns_menu_bar_is_hidden = NO;
175 /*static int debug_lock = 0; */
177 /* event loop */
178 static BOOL send_appdefined = YES;
179 static NSEvent *last_appdefined_event = 0;
180 static NSTimer *timed_entry = 0;
181 static NSTimer *fd_entry = nil;
182 static NSTimer *scroll_repeat_entry = nil;
183 static fd_set select_readfds, t_readfds;
184 static struct timeval select_timeout;
185 static int select_nfds;
186 static NSAutoreleasePool *outerpool;
187 static struct input_event *emacs_event = NULL;
188 static struct input_event *q_event_ptr = NULL;
189 static int n_emacs_events_pending = 0;
190 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
191   *ns_pending_service_args;
192 static BOOL inNsSelect = 0;
194 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
195 #define NS_FUNCTION_KEY_MASK 0x800000
196 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
197 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
198 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
199 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
200 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
201 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
202 #define EV_MODIFIERS(e)                               \
203     ((([e modifierFlags] & NSHelpKeyMask) ?           \
204            hyper_modifier : 0)                        \
205      | (!EQ (ns_right_alternate_modifier, Qleft) && \
206         (([e modifierFlags] & NSRightAlternateKeyMask) \
207          == NSRightAlternateKeyMask) ? \
208            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
209      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
210            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
211      | (([e modifierFlags] & NSShiftKeyMask) ?     \
212            shift_modifier : 0)                        \
213      | (!EQ (ns_right_control_modifier, Qleft) && \
214         (([e modifierFlags] & NSRightControlKeyMask) \
215          == NSRightControlKeyMask) ? \
216            parse_solitary_modifier (ns_right_control_modifier) : 0) \
217      | (([e modifierFlags] & NSControlKeyMask) ?      \
218            parse_solitary_modifier (ns_control_modifier) : 0)     \
219      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
220            parse_solitary_modifier (ns_function_modifier) : 0)    \
221      | (!EQ (ns_right_command_modifier, Qleft) && \
222         (([e modifierFlags] & NSRightCommandKeyMask) \
223          == NSRightCommandKeyMask) ? \
224            parse_solitary_modifier (ns_right_command_modifier) : 0) \
225      | (([e modifierFlags] & NSCommandKeyMask) ?      \
226            parse_solitary_modifier (ns_command_modifier):0))
228 #define EV_UDMODIFIERS(e)                                      \
229     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
230      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
231      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
232      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
233      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
234      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
235      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
236      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
237      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
239 #define EV_BUTTON(e)                                                         \
240     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
241       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
242      [e buttonNumber] - 1)
244 /* Convert the time field to a timestamp in milliseconds. */
245 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
247 /* This is a piece of code which is common to all the event handling
248    methods.  Maybe it should even be a function.  */
249 #define EV_TRAILER(e)                                         \
250   {                                                           \
251   XSETFRAME (emacs_event->frame_or_window, emacsframe);       \
252   if (e) emacs_event->timestamp = EV_TIMESTAMP (e);           \
253   n_emacs_events_pending++;                                   \
254   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);     \
255   EVENT_INIT (*emacs_event);                                  \
256   ns_send_appdefined (-1);                                    \
257   }
259 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
261 /* TODO: get rid of need for these forward declarations */
262 static void ns_condemn_scroll_bars (struct frame *f);
263 static void ns_judge_scroll_bars (struct frame *f);
264 void x_set_frame_alpha (struct frame *f);
266 /* FIXME: figure out what to do with underline_minimum_offset. */
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   if (!getenv ("EMACSPATH"))
342     {
343       NSArray *paths = [binDir stringsByAppendingPaths:
344                                   [NSArray arrayWithObjects: @"bin",
345                                                              @"lib-exec", nil]];
346       NSEnumerator *pathEnum = [paths objectEnumerator];
347       resourcePaths = @"";
348       while (resourcePath = [pathEnum nextObject])
349         {
350           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
351             if (isDir)
352               {
353                 if ([resourcePaths length] > 0)
354                   resourcePaths
355                     = [resourcePaths stringByAppendingString: pathSeparator];
356                 resourcePaths
357                   = [resourcePaths stringByAppendingString: resourcePath];
358               }
359         }
360       if ([resourcePaths length] > 0)
361         setenv ("EMACSPATH", [resourcePaths UTF8String], 1);
362     }
364   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
365   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
366     {
367       if (isDir)
368         {
369           if (!getenv ("EMACSDATA"))
370             setenv ("EMACSDATA", [resourcePath UTF8String], 1);
371           if (!getenv ("EMACSDOC"))
372             setenv ("EMACSDOC", [resourcePath UTF8String], 1);
373         }
374     }
376   if (!getenv ("INFOPATH"))
377     {
378       resourcePath = [resourceDir stringByAppendingPathComponent: @"info"];
379       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
380         if (isDir)
381           setenv ("INFOPATH", [[resourcePath stringByAppendingString: @":"]
382                                              UTF8String], 1);
383       /* Note, extra colon needed to cause merge w/later user additions. */
384     }
388 static int
389 timeval_subtract (struct timeval *result, struct timeval x, struct timeval y)
390 /* --------------------------------------------------------------------------
391    Subtract the `struct timeval' values X and Y, storing the result in RESULT.
392    Return 1 if the difference is negative, otherwise 0.
393    -------------------------------------------------------------------------- */
395   /* Perform the carry for the later subtraction by updating y.
396      This is safer because on some systems
397      the tv_sec member is unsigned.  */
398   if (x.tv_usec < y.tv_usec)
399     {
400       int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
401       y.tv_usec -= 1000000 * nsec;
402       y.tv_sec += nsec;
403     }
404   if (x.tv_usec - y.tv_usec > 1000000)
405     {
406       int nsec = (y.tv_usec - x.tv_usec) / 1000000;
407       y.tv_usec += 1000000 * nsec;
408       y.tv_sec -= nsec;
409     }
411   /* Compute the time remaining to wait.  tv_usec is certainly positive.  */
412   result->tv_sec = x.tv_sec - y.tv_sec;
413   result->tv_usec = x.tv_usec - y.tv_usec;
415   /* Return indication of whether the result should be considered negative.  */
416   return x.tv_sec < y.tv_sec;
419 static void
420 ns_timeout (int usecs)
421 /* --------------------------------------------------------------------------
422      Blocking timer utility used by ns_ring_bell
423    -------------------------------------------------------------------------- */
425   struct timeval wakeup;
427   EMACS_GET_TIME (wakeup);
429   /* Compute time to wait until, propagating carry from usecs.  */
430   wakeup.tv_usec += usecs;
431   wakeup.tv_sec += (wakeup.tv_usec / 1000000);
432   wakeup.tv_usec %= 1000000;
434   /* Keep waiting until past the time wakeup.  */
435   while (1)
436     {
437       struct timeval timeout;
439       EMACS_GET_TIME (timeout);
441       /* In effect, timeout = wakeup - timeout.
442          Break if result would be negative.  */
443       if (timeval_subtract (&timeout, wakeup, timeout))
444         break;
446       /* Try to wait that long--but we might wake up sooner.  */
447       select (0, NULL, NULL, NULL, &timeout);
448     }
452 void
453 ns_release_object (void *obj)
454 /* --------------------------------------------------------------------------
455     Release an object (callable from C)
456    -------------------------------------------------------------------------- */
458     [(id)obj release];
462 void
463 ns_retain_object (void *obj)
464 /* --------------------------------------------------------------------------
465     Retain an object (callable from C)
466    -------------------------------------------------------------------------- */
468     [(id)obj retain];
472 void *
473 ns_alloc_autorelease_pool (void)
474 /* --------------------------------------------------------------------------
475      Allocate a pool for temporary objects (callable from C)
476    -------------------------------------------------------------------------- */
478   return [[NSAutoreleasePool alloc] init];
482 void
483 ns_release_autorelease_pool (void *pool)
484 /* --------------------------------------------------------------------------
485      Free a pool and temporary objects it refers to (callable from C)
486    -------------------------------------------------------------------------- */
488   ns_release_object (pool);
493 /* ==========================================================================
495     Focus (clipping) and screen update
497    ========================================================================== */
499 static NSRect
500 ns_resize_handle_rect (NSWindow *window)
502   NSRect r = [window frame];
503   r.origin.x = r.size.width - RESIZE_HANDLE_SIZE;
504   r.origin.y = 0;
505   r.size.width = r.size.height = RESIZE_HANDLE_SIZE;
506   return r;
511 // Window constraining
512 // -------------------
514 // To ensure that the windows are not placed under the menu bar, they
515 // are typically moved by the call-back constrainFrameRect. However,
516 // by overriding it, it's possible to inhibit this, leaving the window
517 // in it's original position.
519 // It's possible to hide the menu bar. However, technically, it's only
520 // possible to hide it when the application is active. To ensure that
521 // this work properly, the menu bar and window constraining are
522 // deferred until the application becomes active.
524 // Even though it's not possible to manually move a window above the
525 // top of the screen, it is allowed if it's done programmatically,
526 // when the menu is hidden. This allows the editable area to cover the
527 // full screen height.
529 // Test cases
530 // ----------
532 // Use the following extra files:
534 //    init.el:
535 //       ;; Hide menu and place frame slightly above the top of the screen.
536 //       (setq ns-auto-hide-menu-bar t)
537 //       (set-frame-position (selected-frame) 0 -20)
539 // Test 1:
541 //    emacs -Q -l init.el
543 //    Result: No menu bar, and the title bar should be above the screen.
545 // Test 2:
547 //    emacs -Q
549 //    Result: Menu bar visible, frame placed immediately below the menu.
552 static void
553 ns_constrain_all_frames (void)
555   Lisp_Object tail, frame;
557   FOR_EACH_FRAME (tail, frame)
558     {
559       struct frame *f = XFRAME (frame);
560       if (FRAME_NS_P (f))
561         {
562           NSView *view = FRAME_NS_VIEW (f);
563           /* This no-op will trigger the default window placing
564            * constriant system. */
565           f->output_data.ns->dont_constrain = 0;
566           [[view window] setFrameOrigin:[[view window] frame].origin];
567         }
568     }
572 /* True, if the menu bar should be hidden.  */
574 static BOOL
575 ns_menu_bar_should_be_hidden (void)
577   return !NILP (ns_auto_hide_menu_bar)
578     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
582 /* Show or hide the menu bar, based on user setting.  */
584 static void
585 ns_update_auto_hide_menu_bar (void)
587 #ifndef MAC_OS_X_VERSION_10_6
588 #define MAC_OS_X_VERSION_10_6 1060
589 #endif
590 #ifdef NS_IMPL_COCOA
591 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
592   BLOCK_INPUT;
594   NSTRACE (ns_update_auto_hide_menu_bar);
596   if (NSApp != nil
597       && [NSApp isActive]
598       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
599     {
600       // Note, "setPresentationOptions" triggers an error unless the
601       // application is active.
602       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
604       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
605         {
606           NSApplicationPresentationOptions options
607             = NSApplicationPresentationAutoHideDock;
609           if (menu_bar_should_be_hidden)
610             options |= NSApplicationPresentationAutoHideMenuBar;
612           [NSApp setPresentationOptions: options];
614           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
616           if (!ns_menu_bar_is_hidden)
617             {
618               ns_constrain_all_frames ();
619             }
620         }
621     }
623   UNBLOCK_INPUT;
624 #endif
625 #endif
629 static void
630 ns_update_begin (struct frame *f)
631 /* --------------------------------------------------------------------------
632    Prepare for a grouped sequence of drawing calls
633    external (RIF) call; whole frame, called before update_window_begin
634    -------------------------------------------------------------------------- */
636   NSView *view = FRAME_NS_VIEW (f);
637   NSTRACE (ns_update_begin);
639   ns_update_auto_hide_menu_bar ();
641   ns_updating_frame = f;
642   [view lockFocus];
644 #ifdef NS_IMPL_GNUSTEP
645   uRect = NSMakeRect (0, 0, 0, 0);
646 #endif
650 static void
651 ns_update_window_begin (struct window *w)
652 /* --------------------------------------------------------------------------
653    Prepare for a grouped sequence of drawing calls
654    external (RIF) call; for one window, called after update_begin
655    -------------------------------------------------------------------------- */
657   struct frame *f = XFRAME (WINDOW_FRAME (w));
658  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
659   NSTRACE (ns_update_window_begin);
661   updated_window = w;
662   set_output_cursor (&w->cursor);
664   BLOCK_INPUT;
666   if (f == hlinfo->mouse_face_mouse_frame)
667     {
668       /* Don't do highlighting for mouse motion during the update.  */
669       hlinfo->mouse_face_defer = 1;
671         /* If the frame needs to be redrawn,
672            simply forget about any prior mouse highlighting.  */
673       if (FRAME_GARBAGED_P (f))
674         hlinfo->mouse_face_window = Qnil;
676       /* (further code for mouse faces ifdef'd out in other terms elided) */
677     }
679   UNBLOCK_INPUT;
683 static void
684 ns_update_window_end (struct window *w, int cursor_on_p,
685                       int mouse_face_overwritten_p)
686 /* --------------------------------------------------------------------------
687    Finished a grouped sequence of drawing calls
688    external (RIF) call; for one window called before update_end
689    -------------------------------------------------------------------------- */
691   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
693   /* note: this fn is nearly identical in all terms */
694   if (!w->pseudo_window_p)
695     {
696       BLOCK_INPUT;
698       if (cursor_on_p)
699         display_and_set_cursor (w, 1,
700                                 output_cursor.hpos, output_cursor.vpos,
701                                 output_cursor.x, output_cursor.y);
703       if (draw_window_fringes (w, 1))
704         x_draw_vertical_border (w);
706       UNBLOCK_INPUT;
707     }
709   /* If a row with mouse-face was overwritten, arrange for
710      frame_up_to_date to redisplay the mouse highlight.  */
711   if (mouse_face_overwritten_p)
712     {
713       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
714       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
715       hlinfo->mouse_face_window = Qnil;
716     }
718   updated_window = NULL;
719   NSTRACE (update_window_end);
723 static void
724 ns_update_end (struct frame *f)
725 /* --------------------------------------------------------------------------
726    Finished a grouped sequence of drawing calls
727    external (RIF) call; for whole frame, called after update_window_end
728    -------------------------------------------------------------------------- */
730   NSView *view = FRAME_NS_VIEW (f);
732 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
733     MOUSE_HL_INFO (f)->mouse_face_defer = 0;
735   BLOCK_INPUT;
737 #ifdef NS_IMPL_GNUSTEP
738   /* trigger flush only in the rectangle we tracked as being drawn */
739   [view unlockFocusNeedsFlush: NO];
740 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
741   [view lockFocusInRect: uRect];
742 #endif
744   [view unlockFocus];
745   [[view window] flushWindow];
747   UNBLOCK_INPUT;
748   ns_updating_frame = NULL;
749   NSTRACE (ns_update_end);
753 static void
754 ns_flush (struct frame *f)
755 /* --------------------------------------------------------------------------
756    external (RIF) call
757    NS impl is no-op since currently we flush in ns_update_end and elsewhere
758    -------------------------------------------------------------------------- */
760     NSTRACE (ns_flush);
764 static void
765 ns_focus (struct frame *f, NSRect *r, int n)
766 /* --------------------------------------------------------------------------
767    Internal: Focus on given frame.  During small local updates this is used to
768      draw, however during large updates, ns_update_begin and ns_update_end are
769      called to wrap the whole thing, in which case these calls are stubbed out.
770      Except, on GNUstep, we accumulate the rectangle being drawn into, because
771      the back end won't do this automatically, and will just end up flushing
772      the entire window.
773    -------------------------------------------------------------------------- */
775 //  NSTRACE (ns_focus);
776 #ifdef NS_IMPL_GNUSTEP
777   NSRect u;
778     if (n == 2)
779       u = NSUnionRect (r[0], r[1]);
780     else if (r)
781       u = *r;
782 #endif
783 /* static int c =0;
784    fprintf (stderr, "focus: %d", c++);
785    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
786    fprintf (stderr, "\n"); */
788   if (f != ns_updating_frame)
789     {
790       NSView *view = FRAME_NS_VIEW (f);
791       if (view != focus_view)
792         {
793           if (focus_view != NULL)
794             {
795               [focus_view unlockFocus];
796               [[focus_view window] flushWindow];
797 /*debug_lock--; */
798             }
800           if (view)
801 #ifdef NS_IMPL_GNUSTEP
802             r ? [view lockFocusInRect: u] : [view lockFocus];
803 #else
804             [view lockFocus];
805 #endif
806           focus_view = view;
807 /*if (view) debug_lock++; */
808         }
809 #ifdef NS_IMPL_GNUSTEP
810       else
811         {
812           /* more than one rect being drawn into */
813           if (view && r)
814             {
815               [view unlockFocus]; /* add prev rect to redraw list */
816               [view lockFocusInRect: u]; /* focus for draw in new rect */
817             }
818         }
819 #endif
820     }
821 #ifdef NS_IMPL_GNUSTEP
822   else
823     {
824       /* in batch mode, but in GNUstep must still track rectangles explicitly */
825       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
826     }
827 #endif
829   /* clipping */
830   if (r)
831     {
832       [[NSGraphicsContext currentContext] saveGraphicsState];
833       if (n == 2)
834         NSRectClipList (r, 2);
835       else
836         NSRectClip (*r);
837       gsaved = YES;
838     }
842 static void
843 ns_unfocus (struct frame *f)
844 /* --------------------------------------------------------------------------
845      Internal: Remove focus on given frame
846    -------------------------------------------------------------------------- */
848 //  NSTRACE (ns_unfocus);
850   if (gsaved)
851     {
852       [[NSGraphicsContext currentContext] restoreGraphicsState];
853       gsaved = NO;
854     }
856   if (f != ns_updating_frame)
857     {
858       if (focus_view != NULL)
859         {
860           [focus_view unlockFocus];
861           [[focus_view window] flushWindow];
862           focus_view = NULL;
863 /*debug_lock--; */
864         }
865     }
869 static void
870 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
871 /* --------------------------------------------------------------------------
872      Internal (but parallels other terms): Focus drawing on given row
873    -------------------------------------------------------------------------- */
875   struct frame *f = XFRAME (WINDOW_FRAME (w));
876   NSRect clip_rect;
877   int window_x, window_y, window_width;
879   window_box (w, area, &window_x, &window_y, &window_width, 0);
881   clip_rect.origin.x = window_x - FRAME_INTERNAL_BORDER_WIDTH (f);
882   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
883   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
884   clip_rect.size.width = window_width + 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
885   clip_rect.size.height = row->visible_height;
887   /* allow a full-height row at the top when requested
888      (used to draw fringe all the way through internal border area) */
889   if (gc && clip_rect.origin.y < 5)
890     {
891       clip_rect.origin.y -= FRAME_INTERNAL_BORDER_WIDTH (f);
892       clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
893     }
895   /* likewise at bottom */
896   if (gc &&
897       FRAME_PIXEL_HEIGHT (f) - (clip_rect.origin.y + clip_rect.size.height) < 5)
898     clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
900   ns_focus (f, &clip_rect, 1);
904 static void
905 ns_ring_bell (struct frame *f)
906 /* --------------------------------------------------------------------------
907      "Beep" routine
908    -------------------------------------------------------------------------- */
910   NSTRACE (ns_ring_bell);
911   if (visible_bell)
912     {
913       NSAutoreleasePool *pool;
914       struct frame *frame = SELECTED_FRAME ();
915       NSView *view;
917       BLOCK_INPUT;
918       pool = [[NSAutoreleasePool alloc] init];
920       view = FRAME_NS_VIEW (frame);
921       if (view != nil)
922         {
923           NSRect r, surr;
924           NSPoint dim = NSMakePoint (128, 128);
926           r = [view bounds];
927           r.origin.x += (r.size.width - dim.x) / 2;
928           r.origin.y += (r.size.height - dim.y) / 2;
929           r.size.width = dim.x;
930           r.size.height = dim.y;
931           surr = NSInsetRect (r, -2, -2);
932           ns_focus (frame, &surr, 1);
933           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
934           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
935                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
936           NSRectFill (r);
937           [[view window] flushWindow];
938           ns_timeout (150000);
939           [[view window] restoreCachedImage];
940           [[view window] flushWindow];
941           ns_unfocus (frame);
942         }
943       [pool release];
944       UNBLOCK_INPUT;
945     }
946   else
947     {
948       NSBeep ();
949     }
953 static void
954 ns_reset_terminal_modes (struct terminal *terminal)
955 /*  Externally called as hook */
957   NSTRACE (ns_reset_terminal_modes);
961 static void
962 ns_set_terminal_modes (struct terminal *terminal)
963 /*  Externally called as hook */
965   NSTRACE (ns_set_terminal_modes);
970 /* ==========================================================================
972     Frame / window manager related functions
974    ========================================================================== */
977 static void
978 ns_raise_frame (struct frame *f)
979 /* --------------------------------------------------------------------------
980      Bring window to foreground and make it active
981    -------------------------------------------------------------------------- */
983   NSView *view = FRAME_NS_VIEW (f);
984   check_ns ();
985   BLOCK_INPUT;
986   FRAME_SAMPLE_VISIBILITY (f);
987   if (FRAME_VISIBLE_P (f))
988     {
989       [[view window] makeKeyAndOrderFront: NSApp];
990     }
991   UNBLOCK_INPUT;
995 static void
996 ns_lower_frame (struct frame *f)
997 /* --------------------------------------------------------------------------
998      Send window to back
999    -------------------------------------------------------------------------- */
1001   NSView *view = FRAME_NS_VIEW (f);
1002   check_ns ();
1003   BLOCK_INPUT;
1004   [[view window] orderBack: NSApp];
1005   UNBLOCK_INPUT;
1009 static void
1010 ns_frame_raise_lower (struct frame *f, int raise)
1011 /* --------------------------------------------------------------------------
1012      External (hook)
1013    -------------------------------------------------------------------------- */
1015   NSTRACE (ns_frame_raise_lower);
1017   if (raise)
1018     ns_raise_frame (f);
1019   else
1020     ns_lower_frame (f);
1024 static void
1025 ns_frame_rehighlight (struct frame *frame)
1026 /* --------------------------------------------------------------------------
1027      External (hook): called on things like window switching within frame
1028    -------------------------------------------------------------------------- */
1030   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1031   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1033   NSTRACE (ns_frame_rehighlight);
1034   if (dpyinfo->x_focus_frame)
1035     {
1036       dpyinfo->x_highlight_frame
1037         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1038            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1039            : dpyinfo->x_focus_frame);
1040       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1041         {
1042           FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
1043           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1044         }
1045     }
1046   else
1047       dpyinfo->x_highlight_frame = 0;
1049   if (dpyinfo->x_highlight_frame &&
1050          dpyinfo->x_highlight_frame != old_highlight)
1051     {
1052       if (old_highlight)
1053         {
1054           x_update_cursor (old_highlight, 1);
1055           x_set_frame_alpha (old_highlight);
1056         }
1057       if (dpyinfo->x_highlight_frame)
1058         {
1059           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1060           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1061         }
1062     }
1066 void
1067 x_make_frame_visible (struct frame *f)
1068 /* --------------------------------------------------------------------------
1069      External: Show the window (X11 semantics)
1070    -------------------------------------------------------------------------- */
1072   NSTRACE (x_make_frame_visible);
1073   /* XXX: at some points in past this was not needed, as the only place that
1074      called this (frame.c:Fraise_frame ()) also called raise_lower;
1075      if this ends up the case again, comment this out again. */
1076   if (!FRAME_VISIBLE_P (f))
1077     {
1078       f->async_visible = 1;
1079       ns_raise_frame (f);
1080     }
1084 void
1085 x_make_frame_invisible (struct frame *f)
1086 /* --------------------------------------------------------------------------
1087      External: Hide the window (X11 semantics)
1088    -------------------------------------------------------------------------- */
1090   NSView * view = FRAME_NS_VIEW (f);
1091   NSTRACE (x_make_frame_invisible);
1092   check_ns ();
1093   [[view window] orderOut: NSApp];
1094   f->async_visible = 0;
1095   f->async_iconified = 0;
1099 void
1100 x_iconify_frame (struct frame *f)
1101 /* --------------------------------------------------------------------------
1102      External: Iconify window
1103    -------------------------------------------------------------------------- */
1105   NSView * view = FRAME_NS_VIEW (f);
1106   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1107   NSTRACE (x_iconify_frame);
1108   check_ns ();
1110   if (dpyinfo->x_highlight_frame == f)
1111     dpyinfo->x_highlight_frame = 0;
1113   if ([[view window] windowNumber] <= 0)
1114     {
1115       /* the window is still deferred.  Make it very small, bring it
1116          on screen and order it out. */
1117       NSRect s = { { 100, 100}, {0, 0} };
1118       NSRect t;
1119       t = [[view window] frame];
1120       [[view window] setFrame: s display: NO];
1121       [[view window] orderBack: NSApp];
1122       [[view window] orderOut: NSApp];
1123       [[view window] setFrame: t display: NO];
1124     }
1125   [[view window] miniaturize: NSApp];
1129 void
1130 x_destroy_window (struct frame *f)
1131 /* --------------------------------------------------------------------------
1132      External: Delete the window
1133    -------------------------------------------------------------------------- */
1135   NSView *view = FRAME_NS_VIEW (f);
1136   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1137   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1138   NSTRACE (x_destroy_window);
1139   check_ns ();
1141   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1143   BLOCK_INPUT;
1145   free_frame_menubar (f);
1147   if (FRAME_FACE_CACHE (f))
1148     free_frame_faces (f);
1150   if (f == dpyinfo->x_focus_frame)
1151     dpyinfo->x_focus_frame = 0;
1152   if (f == dpyinfo->x_highlight_frame)
1153     dpyinfo->x_highlight_frame = 0;
1154   if (f == hlinfo->mouse_face_mouse_frame)
1155     {
1156       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1157       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1158       hlinfo->mouse_face_window = Qnil;
1159       hlinfo->mouse_face_deferred_gc = 0;
1160       hlinfo->mouse_face_mouse_frame = 0;
1161     }
1163   xfree (f->output_data.ns);
1165   [[view window] close];
1166   [view release];
1168   ns_window_num--;
1169   UNBLOCK_INPUT;
1173 void
1174 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1175 /* --------------------------------------------------------------------------
1176      External: Position the window
1177    -------------------------------------------------------------------------- */
1179   NSView *view = FRAME_NS_VIEW (f);
1180   NSArray *screens = [NSScreen screens];
1181   NSScreen *fscreen = [screens objectAtIndex: 0];
1182   NSScreen *screen = [[view window] screen];
1184   NSTRACE (x_set_offset);
1186   BLOCK_INPUT;
1188   f->left_pos = xoff;
1189   f->top_pos = yoff;
1191   if (view != nil && screen && fscreen)
1192     {
1193       f->left_pos = f->size_hint_flags & XNegative
1194         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1195         : f->left_pos;
1196       /* We use visibleFrame here to take menu bar into account.
1197          Ideally we should also adjust left/top with visibleFrame.origin.  */
1199       f->top_pos = f->size_hint_flags & YNegative
1200         ? ([screen visibleFrame].size.height + f->top_pos
1201            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1202            - FRAME_TOOLBAR_HEIGHT (f))
1203         : f->top_pos;
1204 #ifdef NS_IMPL_GNUSTEP
1205       if (f->left_pos < 100)
1206         f->left_pos = 100;  /* don't overlap menu */
1207 #endif
1208       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1209          menu bar.  */
1210       f->output_data.ns->dont_constrain = 0;
1211       [[view window] setFrameTopLeftPoint:
1212                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1213                                     SCREENMAXBOUND ([fscreen frame].size.height
1214                                                     - NS_TOP_POS (f)))];
1215       f->size_hint_flags &= ~(XNegative|YNegative);
1216     }
1218   UNBLOCK_INPUT;
1222 void
1223 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1224 /* --------------------------------------------------------------------------
1225      Adjust window pixel size based on given character grid size
1226      Impl is a bit more complex than other terms, need to do some
1227      internal clipping.
1228    -------------------------------------------------------------------------- */
1230   EmacsView *view = FRAME_NS_VIEW (f);
1231   EmacsToolbar *toolbar = [view toolbar];
1232   NSWindow *window = [view window];
1233   NSRect wr = [window frame];
1234   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1235   int pixelwidth, pixelheight;
1236   static int oldRows, oldCols, oldFontWidth, oldFontHeight;
1237   static int oldTB;
1238   static struct frame *oldF;
1240   NSTRACE (x_set_window_size);
1242   if (view == nil ||
1243       (f == oldF
1244        && rows == oldRows && cols == oldCols
1245        && oldFontWidth == FRAME_COLUMN_WIDTH (f)
1246        && oldFontHeight == FRAME_LINE_HEIGHT (f)
1247        && oldTB == tb))
1248     return;
1250 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1252   BLOCK_INPUT;
1254   check_frame_size (f, &rows, &cols);
1255   oldF = f;
1256   oldRows = rows;
1257   oldCols = cols;
1258   oldFontWidth = FRAME_COLUMN_WIDTH (f);
1259   oldFontHeight = FRAME_LINE_HEIGHT (f);
1260   oldTB = tb;
1262   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1263   compute_fringe_widths (f, 0);
1265   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1266   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1268   /* If we have a toolbar, take its height into account. */
1269   if (tb)
1270     /* NOTE: previously this would generate wrong result if toolbar not
1271              yet displayed and fixing toolbar_height=32 helped, but
1272              now (200903) seems no longer needed */
1273     FRAME_TOOLBAR_HEIGHT (f) =
1274       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1275         - FRAME_NS_TITLEBAR_HEIGHT (f);
1276   else
1277     FRAME_TOOLBAR_HEIGHT (f) = 0;
1279   wr.size.width = pixelwidth + f->border_width;
1280   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f)
1281                   + FRAME_TOOLBAR_HEIGHT (f);
1283   /* Do not try to constrain to this screen.  We may have multiple
1284      screens, and want Emacs to span those.  Constraining to screen
1285      prevents that, and that is not nice to the user.  */
1286  if (f->output_data.ns->zooming)
1287    f->output_data.ns->zooming = 0;
1288  else
1289    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1291   [view setRows: rows andColumns: cols];
1292   [window setFrame: wr display: YES];
1294 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1296   /* This is a trick to compensate for Emacs' managing the scrollbar area
1297      as a fixed number of standard character columns.  Instead of leaving
1298      blank space for the extra, we chopped it off above.  Now for
1299      left-hand scrollbars, we shift all rendering to the left by the
1300      difference between the real width and Emacs' imagined one.  For
1301      right-hand bars, don't worry about it since the extra is never used.
1302      (Obviously doesn't work for vertically split windows tho..) */
1303   {
1304     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1305       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1306                      - NS_SCROLL_BAR_WIDTH (f), 0)
1307       : NSMakePoint (0, 0);
1308     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1309     [view setBoundsOrigin: origin];
1310   }
1312   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1313   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1314   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1315 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1317   mark_window_cursors_off (XWINDOW (f->root_window));
1318   cancel_mouse_face (f);
1320   UNBLOCK_INPUT;
1325 /* ==========================================================================
1327     Color management
1329    ========================================================================== */
1332 NSColor *
1333 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1335   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1336   if (idx < 1 || idx >= color_table->avail)
1337     return nil;
1338   return color_table->colors[idx];
1342 unsigned long
1343 ns_index_color (NSColor *color, struct frame *f)
1345   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1346   int idx;
1347   NSNumber *index;
1349   if (!color_table->colors)
1350     {
1351       color_table->size = NS_COLOR_CAPACITY;
1352       color_table->avail = 1; /* skip idx=0 as marker */
1353       color_table->colors
1354         = (NSColor **)xmalloc (color_table->size * sizeof (NSColor *));
1355       color_table->colors[0] = nil;
1356       color_table->empty_indices = [[NSMutableSet alloc] init];
1357     }
1359   /* do we already have this color ? */
1360   {
1361     int i;
1362     for (i = 1; i < color_table->avail; i++)
1363       {
1364         if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1365           {
1366             [color_table->colors[i] retain];
1367             return i;
1368           }
1369       }
1370   }
1372   if ([color_table->empty_indices count] > 0)
1373     {
1374       index = [color_table->empty_indices anyObject];
1375       [color_table->empty_indices removeObject: index];
1376       idx = [index unsignedIntValue];
1377     }
1378   else
1379     {
1380       if (color_table->avail == color_table->size)
1381         {
1382           color_table->size += NS_COLOR_CAPACITY;
1383           color_table->colors
1384             = (NSColor **)xrealloc (color_table->colors,
1385                                     color_table->size * sizeof (NSColor *));
1386         }
1387       idx = color_table->avail++;
1388     }
1390   color_table->colors[idx] = color;
1391   [color retain];
1392 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1393   return idx;
1397 void
1398 ns_free_indexed_color (unsigned long idx, struct frame *f)
1400   struct ns_color_table *color_table;
1401   NSColor *color;
1402   NSNumber *index;
1404   if (!f)
1405     return;
1407   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1409   if (idx <= 0 || idx >= color_table->size) {
1410     message1("ns_free_indexed_color: Color index out of range.\n");
1411     return;
1412   }
1414   index = [NSNumber numberWithUnsignedInt: idx];
1415   if ([color_table->empty_indices containsObject: index]) {
1416     message1("ns_free_indexed_color: attempt to free already freed color.\n");
1417     return;
1418   }
1420   color = color_table->colors[idx];
1421   [color release];
1422   color_table->colors[idx] = nil;
1423   [color_table->empty_indices addObject: [NSNumber numberWithUnsignedInt: idx]];
1424 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1428 static int
1429 ns_get_color (const char *name, NSColor **col)
1430 /* --------------------------------------------------------------------------
1431      Parse a color name
1432    -------------------------------------------------------------------------- */
1433 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1434    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1435    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1437   NSColor *new = nil;
1438   static char hex[20];
1439   int scaling;
1440   float r = -1.0, g, b;
1441   NSString *nsname = [NSString stringWithUTF8String: name];
1443 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1444   BLOCK_INPUT;
1446   if ([nsname isEqualToString: @"ns_selection_color"])
1447     {
1448       nsname = ns_selection_color;
1449       name = [ns_selection_color UTF8String];
1450     }
1452   /* First, check for some sort of numeric specification. */
1453   hex[0] = '\0';
1455   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1456     {
1457       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1458       [scanner scanFloat: &r];
1459       [scanner scanFloat: &g];
1460       [scanner scanFloat: &b];
1461     }
1462   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1463     {
1464       strncpy (hex, name + 4, 19);
1465       hex[19] = '\0';
1466       scaling = (strlen(hex) - 2) / 3;
1467     }
1468   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1469     {
1470       int len = (strlen(name) - 1);
1471       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1472       int i;
1473       scaling = strlen(name+start) / 3;
1474       for (i=0; i<3; i++) {
1475         strncpy(hex + i * (scaling + 1), name + start + i * scaling, scaling);
1476         hex[(i+1) * (scaling + 1) - 1] = '/';
1477       }
1478       hex[3 * (scaling + 1) - 1] = '\0';
1479     }
1481   if (hex[0])
1482     {
1483       int rr, gg, bb;
1484       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1485       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1486         {
1487           r = rr / fscale;
1488           g = gg / fscale;
1489           b = bb / fscale;
1490         }
1491     }
1493   if (r >= 0.0)
1494     {
1495       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1496       UNBLOCK_INPUT;
1497       return 0;
1498     }
1500   /* Otherwise, color is expected to be from a list */
1501   {
1502     NSEnumerator *lenum, *cenum;
1503     NSString *name;
1504     NSColorList *clist;
1506 #ifdef NS_IMPL_GNUSTEP
1507     /* XXX: who is wrong, the requestor or the implementation? */
1508     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1509         == NSOrderedSame)
1510       nsname = @"highlightColor";
1511 #endif
1513     lenum = [[NSColorList availableColorLists] objectEnumerator];
1514     while ( (clist = [lenum nextObject]) && new == nil)
1515       {
1516         cenum = [[clist allKeys] objectEnumerator];
1517         while ( (name = [cenum nextObject]) && new == nil )
1518           {
1519             if ([name compare: nsname
1520                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1521               new = [clist colorWithKey: name];
1522           }
1523       }
1524   }
1526   if (new)
1527     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1528   UNBLOCK_INPUT;
1529   return new ? 0 : 1;
1533 static NSColor *
1534 ns_get_color_default (const char *name, NSColor *dflt)
1535 /* --------------------------------------------------------------------------
1536      Parse a color or use a default value
1537    -------------------------------------------------------------------------- */
1539   NSColor * col;
1541   if (ns_get_color (name, &col))
1542     return dflt;
1543   else
1544     return col;
1549 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1550 /* --------------------------------------------------------------------------
1551      Convert a Lisp string object to a NS color
1552    -------------------------------------------------------------------------- */
1554   NSTRACE (ns_lisp_to_color);
1555   if (STRINGP (color))
1556     return ns_get_color (SDATA (color), col);
1557   else if (SYMBOLP (color))
1558     return ns_get_color (SDATA (SYMBOL_NAME (color)), col);
1559   return 1;
1563 Lisp_Object
1564 ns_color_to_lisp (NSColor *col)
1565 /* --------------------------------------------------------------------------
1566      Convert a color to a lisp string with the RGB equivalent
1567    -------------------------------------------------------------------------- */
1569   CGFloat red, green, blue, alpha, gray;
1570   char buf[1024];
1571   const char *str;
1572   NSTRACE (ns_color_to_lisp);
1574   BLOCK_INPUT;
1575   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1577       if ((str =[[col colorNameComponent] UTF8String]))
1578         {
1579           UNBLOCK_INPUT;
1580           return build_string ((char *)str);
1581         }
1583     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1584         getRed: &red green: &green blue: &blue alpha: &alpha];
1585   if (red ==green && red ==blue)
1586     {
1587       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1588             getWhite: &gray alpha: &alpha];
1589       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1590                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1591       UNBLOCK_INPUT;
1592       return build_string (buf);
1593     }
1595   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1596             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1598   UNBLOCK_INPUT;
1599   return build_string (buf);
1603 void
1604 ns_query_color(void *col, XColor *color_def, int setPixel)
1605 /* --------------------------------------------------------------------------
1606          Get ARGB values out of NSColor col and put them into color_def.
1607          If setPixel, set the pixel to a concatenated version.
1608          and set color_def pixel to the resulting index.
1609    -------------------------------------------------------------------------- */
1611   CGFloat r, g, b, a;
1613   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1614   color_def->red   = r * 65535;
1615   color_def->green = g * 65535;
1616   color_def->blue  = b * 65535;
1618   if (setPixel == YES)
1619     color_def->pixel
1620       = ARGB_TO_ULONG((int)(a*255),
1621                       (int)(r*255), (int)(g*255), (int)(b*255));
1626 ns_defined_color (struct frame *f,
1627                   const char *name,
1628                   XColor *color_def,
1629                   int alloc,
1630                   char makeIndex)
1631 /* --------------------------------------------------------------------------
1632          Return 1 if named color found, and set color_def rgb accordingly.
1633          If makeIndex and alloc are nonzero put the color in the color_table,
1634          and set color_def pixel to the resulting index.
1635          If makeIndex is zero, set color_def pixel to ARGB.
1636          Return 0 if not found
1637    -------------------------------------------------------------------------- */
1639   NSColor *col;
1640   NSTRACE (ns_defined_color);
1642   BLOCK_INPUT;
1643   if (ns_get_color (name, &col) != 0) /* Color not found  */
1644     {
1645       UNBLOCK_INPUT;
1646       return 0;
1647     }
1648   if (makeIndex && alloc)
1649     color_def->pixel = ns_index_color (col, f);
1650   ns_query_color (col, color_def, !makeIndex);
1651   UNBLOCK_INPUT;
1652   return 1;
1656 unsigned long
1657 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1658 /* --------------------------------------------------------------------------
1659     return an autoreleased RGB color
1660    -------------------------------------------------------------------------- */
1662 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1663   if (r < 0.0) r = 0.0;
1664   else if (r > 1.0) r = 1.0;
1665   if (g < 0.0) g = 0.0;
1666   else if (g > 1.0) g = 1.0;
1667   if (b < 0.0) b = 0.0;
1668   else if (b > 1.0) b = 1.0;
1669   if (a < 0.0) a = 0.0;
1670   else if (a > 1.0) a = 1.0;
1671   return (unsigned long) ns_index_color(
1672     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1676 void
1677 x_set_frame_alpha (struct frame *f)
1678 /* --------------------------------------------------------------------------
1679      change the entire-frame transparency
1680    -------------------------------------------------------------------------- */
1682   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1683   EmacsView *view = FRAME_NS_VIEW (f);
1684   double alpha = 1.0;
1685   double alpha_min = 1.0;
1687   if (dpyinfo->x_highlight_frame == f)
1688     alpha = f->alpha[0];
1689   else
1690     alpha = f->alpha[1];
1692   if (FLOATP (Vframe_alpha_lower_limit))
1693     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1694   else if (INTEGERP (Vframe_alpha_lower_limit))
1695     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1697   if (alpha < 0.0)
1698     return;
1699   else if (1.0 < alpha)
1700     alpha = 1.0;
1701   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1702     alpha = alpha_min;
1704 #ifdef NS_IMPL_COCOA
1705   [[view window] setAlphaValue: alpha];
1706 #endif
1710 /* ==========================================================================
1712     Mouse handling
1714    ========================================================================== */
1717 void
1718 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1719 /* --------------------------------------------------------------------------
1720      Programmatically reposition mouse pointer in pixel coordinates
1721    -------------------------------------------------------------------------- */
1723   NSTRACE (x_set_mouse_pixel_position);
1724   ns_raise_frame (f);
1725 #if 0
1726   /* FIXME: this does not work, and what about GNUstep? */
1727 #ifdef NS_IMPL_COCOA
1728   [FRAME_NS_VIEW (f) lockFocus];
1729   PSsetmouse ((float)pix_x, (float)pix_y);
1730   [FRAME_NS_VIEW (f) unlockFocus];
1731 #endif
1732 #endif
1736 void
1737 x_set_mouse_position (struct frame *f, int h, int v)
1738 /* --------------------------------------------------------------------------
1739      Programmatically reposition mouse pointer in character coordinates
1740    -------------------------------------------------------------------------- */
1742   int pix_x, pix_y;
1744   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1745   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1747   if (pix_x < 0) pix_x = 0;
1748   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1750   if (pix_y < 0) pix_y = 0;
1751   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1753   x_set_mouse_pixel_position (f, pix_x, pix_y);
1757 static int
1758 note_mouse_movement (struct frame *frame, float x, float y)
1759 /*   ------------------------------------------------------------------------
1760      Called by EmacsView on mouseMovement events.  Passes on
1761      to emacs mainstream code if we moved off of a rect of interest
1762      known as last_mouse_glyph.
1763      ------------------------------------------------------------------------ */
1765 //  NSTRACE (note_mouse_movement);
1767   XSETFRAME (last_mouse_motion_frame, frame);
1769   /* Note, this doesn't get called for enter/leave, since we don't have a
1770      position.  Those are taken care of in the corresponding NSView methods. */
1772   /* has movement gone beyond last rect we were tracking? */
1773   if (x < last_mouse_glyph.origin.x ||
1774       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1775       y < last_mouse_glyph.origin.y ||
1776       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1777     {
1778       ns_update_begin(frame);
1779       frame->mouse_moved = 1;
1780       note_mouse_highlight (frame, x, y);
1781       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1782       ns_update_end(frame);
1783       return 1;
1784     }
1786   return 0;
1790 static void
1791 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1792                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1793                    Time *time)
1794 /* --------------------------------------------------------------------------
1795     External (hook): inform emacs about mouse position and hit parts.
1796     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1797     x & y should be position in the scrollbar (the whole bar, not the handle)
1798     and length of scrollbar respectively
1799    -------------------------------------------------------------------------- */
1801   id view;
1802   NSPoint position;
1803   int xchar, ychar;
1804   Lisp_Object frame, tail;
1805   struct frame *f;
1806   struct ns_display_info *dpyinfo;
1808   NSTRACE (ns_mouse_position);
1810   if (*fp == NULL)
1811     {
1812       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1813       return;
1814     }
1816   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1818   BLOCK_INPUT;
1820   if (last_mouse_scroll_bar != nil && insist == 0)
1821     {
1822       /* TODO: we do not use this path at the moment because drag events will
1823            go directly to the EmacsScroller.  Leaving code in for now. */
1824       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1825                                               x: x y: y];
1826       if (time) *time = last_mouse_movement_time;
1827       last_mouse_scroll_bar = nil;
1828     }
1829   else
1830     {
1831       /* Clear the mouse-moved flag for every frame on this display.  */
1832       FOR_EACH_FRAME (tail, frame)
1833         if (FRAME_NS_P (XFRAME (frame))
1834             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1835           XFRAME (frame)->mouse_moved = 0;
1837       last_mouse_scroll_bar = nil;
1838       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1839         f = last_mouse_frame;
1840       else
1841         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1842                                     : SELECTED_FRAME ();
1844       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1845         {
1846           view = FRAME_NS_VIEW (*fp);
1848           position = [[view window] mouseLocationOutsideOfEventStream];
1849           position = [view convertPoint: position fromView: nil];
1850           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1851 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1853           if (bar_window) *bar_window = Qnil;
1854           if (part) *part = 0; /*scroll_bar_handle; */
1856           if (x) XSETINT (*x, lrint (position.x));
1857           if (y) XSETINT (*y, lrint (position.y));
1858           if (time) *time = last_mouse_movement_time;
1859           *fp = f;
1860         }
1861     }
1863   UNBLOCK_INPUT;
1867 static void
1868 ns_frame_up_to_date (struct frame *f)
1869 /* --------------------------------------------------------------------------
1870     External (hook): Fix up mouse highlighting right after a full update.
1871     Some highlighting was deferred if GC was happening during
1872     note_mouse_highlight (), while other highlighting was deferred for update.
1873    -------------------------------------------------------------------------- */
1875   NSTRACE (ns_frame_up_to_date);
1877   if (FRAME_NS_P (f))
1878     {
1879       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1880       if ((hlinfo->mouse_face_deferred_gc || f ==hlinfo->mouse_face_mouse_frame)
1881       /*&& hlinfo->mouse_face_mouse_frame*/)
1882         {
1883           BLOCK_INPUT;
1884           ns_update_begin(f);
1885           if (hlinfo->mouse_face_mouse_frame)
1886             note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1887                                   hlinfo->mouse_face_mouse_x,
1888                                   hlinfo->mouse_face_mouse_y);
1889           hlinfo->mouse_face_deferred_gc = 0;
1890           ns_update_end(f);
1891           UNBLOCK_INPUT;
1892         }
1893     }
1897 void
1898 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1899 /* --------------------------------------------------------------------------
1900     External (RIF): set frame mouse pointer type.
1901    -------------------------------------------------------------------------- */
1903   NSTRACE (ns_define_frame_cursor);
1904   if (FRAME_POINTER_TYPE (f) != cursor)
1905     {
1906       EmacsView *view = FRAME_NS_VIEW (f);
1907       FRAME_POINTER_TYPE (f) = cursor;
1908       [[view window] invalidateCursorRectsForView: view];
1909       /* Redisplay assumes this function also draws the changed frame
1910          cursor, but this function doesn't, so do it explicitly.  */
1911       x_update_cursor (f, 1);
1912     }
1917 /* ==========================================================================
1919     Keyboard handling
1921    ========================================================================== */
1924 static unsigned
1925 ns_convert_key (unsigned code)
1926 /* --------------------------------------------------------------------------
1927     Internal call used by NSView-keyDown.
1928    -------------------------------------------------------------------------- */
1930   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1931                                 / sizeof (convert_ns_to_X_keysym[0]));
1932   unsigned keysym;
1933   /* An array would be faster, but less easy to read. */
1934   for (keysym = 0; keysym < last_keysym; keysym += 2)
1935     if (code == convert_ns_to_X_keysym[keysym])
1936       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1937   return 0;
1938 /* if decide to use keyCode and Carbon table, use this line:
1939      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1943 char *
1944 x_get_keysym_name (int keysym)
1945 /* --------------------------------------------------------------------------
1946     Called by keyboard.c.  Not sure if the return val is important, except
1947     that it be unique.
1948    -------------------------------------------------------------------------- */
1950   static char value[16];
1951   NSTRACE (x_get_keysym_name);
1952   sprintf (value, "%d", keysym);
1953   return value;
1958 /* ==========================================================================
1960     Block drawing operations
1962    ========================================================================== */
1965 static void
1966 ns_redraw_scroll_bars (struct frame *f)
1968   int i;
1969   id view;
1970   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1971   NSTRACE (ns_judge_scroll_bars);
1972   for (i =[subviews count]-1; i >= 0; i--)
1973     {
1974       view = [subviews objectAtIndex: i];
1975       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1976       [view display];
1977     }
1981 void
1982 ns_clear_frame (struct frame *f)
1983 /* --------------------------------------------------------------------------
1984       External (hook): Erase the entire frame
1985    -------------------------------------------------------------------------- */
1987   NSView *view = FRAME_NS_VIEW (f);
1988   NSRect r;
1990   NSTRACE (ns_clear_frame);
1991   if (ns_in_resize)
1992     return;
1994  /* comes on initial frame because we have
1995     after-make-frame-functions = select-frame */
1996  if (!FRAME_DEFAULT_FACE (f))
1997    return;
1999   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2001   output_cursor.hpos = output_cursor.vpos = 0;
2002   output_cursor.x = -1;
2004   r = [view bounds];
2006   BLOCK_INPUT;
2007   ns_focus (f, &r, 1);
2008   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2009   NSRectFill (r);
2010   ns_unfocus (f);
2012 #ifdef NS_IMPL_COCOA
2013   [[view window] display];  /* redraw resize handle */
2014 #endif
2016   /* as of 2006/11 or so this is now needed */
2017   ns_redraw_scroll_bars (f);
2018   UNBLOCK_INPUT;
2022 void
2023 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2024 /* --------------------------------------------------------------------------
2025     External (RIF):  Clear section of frame
2026    -------------------------------------------------------------------------- */
2028   NSRect r = NSMakeRect (x, y, width, height);
2029   NSView *view = FRAME_NS_VIEW (f);
2030   struct face *face = FRAME_DEFAULT_FACE (f);
2032   if (!view || !face)
2033     return;
2035   NSTRACE (ns_clear_frame_area);
2037   r = NSIntersectionRect (r, [view frame]);
2038   ns_focus (f, &r, 1);
2039   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2041 #ifdef NS_IMPL_COCOA
2042   {
2043     /* clip out the resize handle */
2044     NSWindow *window = [FRAME_NS_VIEW (f) window];
2045     NSRect ir
2046       = [view convertRect: ns_resize_handle_rect (window) fromView: nil];
2048     ir = NSIntersectionRect (r, ir);
2049     if (NSIsEmptyRect (ir))
2050       {
2051 #endif
2053   NSRectFill (r);
2055 #ifdef NS_IMPL_COCOA
2056       }
2057     else
2058       {
2059         NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
2060         r1.size.height -= ir.size.height;
2061         r2.origin.y += r1.size.height;
2062         r2.size.width -= ir.size.width;
2063         r2.size.height = ir.size.height;
2064         NSRectFill (r1);
2065         NSRectFill (r2);
2066       }
2067   }
2068 #endif
2070   ns_unfocus (f);
2071   return;
2075 static void
2076 ns_scroll_run (struct window *w, struct run *run)
2077 /* --------------------------------------------------------------------------
2078     External (RIF):  Insert or delete n lines at line vpos
2079    -------------------------------------------------------------------------- */
2081   struct frame *f = XFRAME (w->frame);
2082   int x, y, width, height, from_y, to_y, bottom_y;
2084   NSTRACE (ns_scroll_run);
2086   /* begin copy from other terms */
2087   /* Get frame-relative bounding box of the text display area of W,
2088      without mode lines.  Include in this box the left and right
2089      fringe of W.  */
2090   window_box (w, -1, &x, &y, &width, &height);
2092   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2093   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2094   bottom_y = y + height;
2096   if (to_y < from_y)
2097     {
2098       /* Scrolling up.  Make sure we don't copy part of the mode
2099          line at the bottom.  */
2100       if (from_y + run->height > bottom_y)
2101         height = bottom_y - from_y;
2102       else
2103         height = run->height;
2104     }
2105   else
2106     {
2107       /* Scolling down.  Make sure we don't copy over the mode line.
2108          at the bottom.  */
2109       if (to_y + run->height > bottom_y)
2110         height = bottom_y - to_y;
2111       else
2112         height = run->height;
2113     }
2114   /* end copy from other terms */
2116   if (height == 0)
2117       return;
2119   BLOCK_INPUT;
2121   updated_window = w;
2122   x_clear_cursor (w);
2124   {
2125     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2126     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2127     NSPoint dstOrigin = NSMakePoint (x, to_y);
2129     ns_focus (f, &dstRect, 1);
2130     NSCopyBits (0, srcRect , dstOrigin);
2131     ns_unfocus (f);
2132   }
2134   UNBLOCK_INPUT;
2138 static void
2139 ns_after_update_window_line (struct glyph_row *desired_row)
2140 /* --------------------------------------------------------------------------
2141     External (RIF): preparatory to fringe update after text was updated
2142    -------------------------------------------------------------------------- */
2144   struct window *w = updated_window;
2145   struct frame *f;
2146   int width, height;
2148   NSTRACE (ns_after_update_window_line);
2150   /* begin copy from other terms */
2151   xassert (w);
2153   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2154     desired_row->redraw_fringe_bitmaps_p = 1;
2156   /* When a window has disappeared, make sure that no rest of
2157      full-width rows stays visible in the internal border.
2158      Under NS this is drawn inside the fringes. */
2159   if (windows_or_buffers_changed
2160       && (f = XFRAME (w->frame),
2161           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2162           width != 0)
2163       && (height = desired_row->visible_height,
2164           height > 0))
2165     {
2166       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2168       /* Internal border is drawn below the tool bar.  */
2169       if (WINDOWP (f->tool_bar_window)
2170           && w == XWINDOW (f->tool_bar_window))
2171         y -= width;
2172       /* end copy from other terms */
2174       BLOCK_INPUT;
2175       if (!desired_row->full_width_p)
2176         {
2177           int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2178             + WINDOW_LEFT_FRINGE_WIDTH (w);
2179           int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2180             + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
2181             - WINDOW_RIGHT_FRINGE_WIDTH (w)
2182             - FRAME_INTERNAL_BORDER_WIDTH (f);
2183           ns_clear_frame_area (f, x1, y, width, height);
2184           ns_clear_frame_area (f, x2, y, width, height);
2185         }
2186       UNBLOCK_INPUT;
2187     }
2191 static void
2192 ns_shift_glyphs_for_insert (struct frame *f,
2193                            int x, int y, int width, int height,
2194                            int shift_by)
2195 /* --------------------------------------------------------------------------
2196     External (RIF): copy an area horizontally, don't worry about clearing src
2197    -------------------------------------------------------------------------- */
2199   NSRect srcRect = NSMakeRect (x, y, width, height);
2200   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2201   NSPoint dstOrigin = dstRect.origin;
2203   NSTRACE (ns_shift_glyphs_for_insert);
2205   ns_focus (f, &dstRect, 1);
2206   NSCopyBits (0, srcRect, dstOrigin);
2207   ns_unfocus (f);
2212 /* ==========================================================================
2214     Character encoding and metrics
2216    ========================================================================== */
2219 static inline void
2220 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2221 /* --------------------------------------------------------------------------
2222      External (RIF); compute left/right overhang of whole string and set in s
2223    -------------------------------------------------------------------------- */
2225   struct face *face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2226   struct font *font = s->font; /*face->font; */
2228   if (s->char2b)
2229     {
2230       struct font_metrics metrics;
2231       unsigned int codes[2];
2232       codes[0] = *(s->char2b);
2233       codes[1] = *(s->char2b + s->nchars - 1);
2235       font->driver->text_extents (font, codes, 2, &metrics);
2236       s->left_overhang = -metrics.lbearing;
2237       s->right_overhang
2238         = metrics.rbearing > metrics.width
2239         ? metrics.rbearing - metrics.width : 0;
2240     }
2241   else
2242     {
2243       s->left_overhang = 0;
2244       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2245         FONT_HEIGHT (font) * 0.2 : 0;
2246     }
2251 /* ==========================================================================
2253     Fringe and cursor drawing
2255    ========================================================================== */
2258 extern int max_used_fringe_bitmap;
2259 static void
2260 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2261                       struct draw_fringe_bitmap_params *p)
2262 /* --------------------------------------------------------------------------
2263     External (RIF); fringe-related
2264    -------------------------------------------------------------------------- */
2266   struct frame *f = XFRAME (WINDOW_FRAME (w));
2267   struct face *face = p->face;
2268   int rowY;
2269   static EmacsImage **bimgs = NULL;
2270   static int nBimgs = 0;
2271   /* NS-specific: move internal border inside fringe */
2272   int x = p->bx < 0 ? p->x : p->bx;
2273   int wd = p->bx < 0 ? p->wd : p->nx;
2274   BOOL fringeOnVeryLeft
2275     = x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
2276       - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
2277   BOOL fringeOnVeryRight
2278     = FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
2279       - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
2280   int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
2281     (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
2283   /* grow bimgs if needed */
2284   if (nBimgs < max_used_fringe_bitmap)
2285     {
2286       EmacsImage **newBimgs
2287         = xmalloc (max_used_fringe_bitmap * sizeof (EmacsImage *));
2288       memset (newBimgs, 0, max_used_fringe_bitmap * sizeof (EmacsImage *));
2290       if (nBimgs)
2291         {
2292           memcpy (newBimgs, bimgs, nBimgs * sizeof (EmacsImage *));
2293           xfree (bimgs);
2294         }
2296       bimgs = newBimgs;
2297       nBimgs = max_used_fringe_bitmap;
2298     }
2300   /* Must clip because of partially visible lines.  */
2301   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2302   ns_clip_to_row (w, row, -1, YES);
2304   if (p->bx >= 0 && !p->overlay_p)
2305     {
2306       int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
2307         -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2308       int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
2309         FRAME_INTERNAL_BORDER_WIDTH (f) : 0
2310         + (yAdjust ? FRAME_INTERNAL_BORDER_WIDTH (f) : 0);
2311       NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
2312       NSRectClip (r);
2313       [ns_lookup_indexed_color(face->background, f) set];
2314       NSRectFill (r);
2315     }
2317   if (p->which)
2318     {
2319       NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
2320       NSPoint pt = r.origin;
2321       EmacsImage *img = bimgs[p->which - 1];
2323       if (!img)
2324         {
2325           unsigned short *bits = p->bits + p->dh;
2326           int len = 8 * p->h/8;
2327           int i;
2328           unsigned char *cbits = xmalloc (len);
2330           for (i =0; i<len; i++)
2331             cbits[i] = ~(bits[i] & 0xff);
2332           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2333                                            flip: NO];
2334           bimgs[p->which - 1] = img;
2335           xfree (cbits);
2336         }
2338       NSRectClip (r);
2339       /* Since we composite the bitmap instead of just blitting it, we need
2340          to erase the whole background. */
2341       [ns_lookup_indexed_color(face->background, f) set];
2342       NSRectFill (r);
2343       pt.y += p->h;
2344       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2345       [img compositeToPoint: pt operation: NSCompositeSourceOver];
2346     }
2347   ns_unfocus (f);
2351 void
2352 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2353                        int x, int y, int cursor_type, int cursor_width,
2354                        int on_p, int active_p)
2355 /* --------------------------------------------------------------------------
2356      External call (RIF): draw cursor.
2357      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2358    -------------------------------------------------------------------------- */
2360   NSRect r, s;
2361   int fx, fy, h, cursor_height;
2362   struct frame *f = WINDOW_XFRAME (w);
2363   struct glyph *phys_cursor_glyph;
2364   int overspill;
2365   struct glyph *cursor_glyph;
2366   struct face *face;
2367   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2369   /* If cursor is out of bounds, don't draw garbage.  This can happen
2370      in mini-buffer windows when switching between echo area glyphs
2371      and mini-buffer.  */
2373   NSTRACE (dumpcursor);
2375   if (!on_p)
2376     return;
2378   w->phys_cursor_type = cursor_type;
2379   w->phys_cursor_on_p = on_p;
2381   if (cursor_type == NO_CURSOR)
2382     {
2383       w->phys_cursor_width = 0;
2384       return;
2385     }
2387   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2388     {
2389       if (glyph_row->exact_window_width_line_p
2390           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2391         {
2392           glyph_row->cursor_in_fringe_p = 1;
2393           draw_fringe_bitmap (w, glyph_row, 0);
2394         }
2395       return;
2396     }
2398   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2399      (other terminals do it the other way round).  We must set
2400      w->phys_cursor_width to the cursor width.  For bar cursors, that
2401      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2402   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2404   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2405      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2406   if (cursor_type == BAR_CURSOR)
2407     {
2408       if (cursor_width < 1)
2409         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2410       w->phys_cursor_width = cursor_width;
2411     }
2412   /* If we have an HBAR, "cursor_width" MAY specify height. */
2413   else if (cursor_type == HBAR_CURSOR)
2414     {
2415       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2416       fy += h - cursor_height;
2417       h = cursor_height;
2418     }
2420   r.origin.x = fx, r.origin.y = fy;
2421   r.size.height = h;
2422   r.size.width = w->phys_cursor_width;
2424   /* FIXME: if we overwrite the internal border area, it does not get erased;
2425      fix by truncating cursor, but better would be to erase properly */
2426   overspill = r.origin.x + r.size.width -
2427     WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w)
2428       - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
2429   if (overspill > 0)
2430     r.size.width -= overspill;
2432   /* TODO: only needed in rare cases with last-resort font in HELLO..
2433      should we do this more efficiently? */
2434   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2437   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2438   if (face && NS_FACE_BACKGROUND (face)
2439       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2440     {
2441       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2442       hollow_color = FRAME_CURSOR_COLOR (f);
2443     }
2444   else
2445     [FRAME_CURSOR_COLOR (f) set];
2447 #ifdef NS_IMPL_COCOA
2448   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2449            atomic.  Cleaner ways of doing this should be investigated.
2450            One way would be to set a global variable DRAWING_CURSOR
2451            when making the call to draw_phys..(), don't focus in that
2452            case, then move the ns_unfocus() here after that call. */
2453   NSDisableScreenUpdates ();
2454 #endif
2456   switch (cursor_type)
2457     {
2458     case NO_CURSOR:
2459       break;
2460     case FILLED_BOX_CURSOR:
2461       NSRectFill (r);
2462       break;
2463     case HOLLOW_BOX_CURSOR:
2464       NSRectFill (r);
2465       [hollow_color set];
2466       NSRectFill (NSInsetRect (r, 1, 1));
2467       [FRAME_CURSOR_COLOR (f) set];
2468       break;
2469     case HBAR_CURSOR:
2470       NSRectFill (r);
2471       break;
2472     case BAR_CURSOR:
2473       s = r;
2474       /* If the character under cursor is R2L, draw the bar cursor
2475          on the right of its glyph, rather than on the left.  */
2476       cursor_glyph = get_phys_cursor_glyph (w);
2477       if ((cursor_glyph->resolved_level & 1) != 0)
2478         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2480       NSRectFill (s);
2481       break;
2482     }
2483   ns_unfocus (f);
2485   /* draw the character under the cursor */
2486   if (cursor_type != NO_CURSOR)
2487     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2489 #ifdef NS_IMPL_COCOA
2490   NSEnableScreenUpdates ();
2491 #endif
2496 static void
2497 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2498 /* --------------------------------------------------------------------------
2499      External (RIF): Draw a vertical line.
2500    -------------------------------------------------------------------------- */
2502   struct frame *f = XFRAME (WINDOW_FRAME (w));
2503   struct face *face;
2504   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2506   NSTRACE (ns_draw_vertical_window_border);
2508   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2509   if (face)
2510       [ns_lookup_indexed_color(face->foreground, f) set];
2512   ns_focus (f, &r, 1);
2513   NSRectFill(r);
2514   ns_unfocus (f);
2518 void
2519 show_hourglass (struct atimer *timer)
2521   if (hourglass_shown_p)
2522     return;
2524   BLOCK_INPUT;
2526   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2528   hourglass_shown_p = 1;
2529   UNBLOCK_INPUT;
2533 void
2534 hide_hourglass (void)
2536   if (!hourglass_shown_p)
2537     return;
2539   BLOCK_INPUT;
2541   /* TODO: remove NSProgressIndicator from all frames */
2543   hourglass_shown_p = 0;
2544   UNBLOCK_INPUT;
2549 /* ==========================================================================
2551     Glyph drawing operations
2553    ========================================================================== */
2556 static inline NSRect
2557 ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
2558 /* --------------------------------------------------------------------------
2559     Under NS we draw internal borders inside fringes, and want full-width
2560     rendering to go all the way to edge.  This function makes that correction.
2561    -------------------------------------------------------------------------- */
2563   if (r.origin.y <= fibw+1)
2564     {
2565       r.size.height += r.origin.y;
2566       r.origin.y = 0;
2567     }
2568   if (r.origin.x <= fibw+1)
2569     {
2570       r.size.width += r.origin.x;
2571       r.origin.x = 0;
2572     }
2573   if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
2574     r.size.width += fibw;
2576   return r;
2580 static int
2581 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2582 /* --------------------------------------------------------------------------
2583     Wrapper utility to account for internal border width on full-width lines,
2584     and allow top full-width rows to hit the frame top.  nr should be pointer
2585     to two successive NSRects.  Number of rects actually used is returned.
2586    -------------------------------------------------------------------------- */
2588   int n = get_glyph_string_clip_rects (s, nr, 2);
2589   if (s->row->full_width_p)
2590     {
2591       *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2592                             FRAME_PIXEL_WIDTH (s->f));
2593       if (n == 2)
2594         *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
2595                               FRAME_PIXEL_WIDTH (s->f));
2596     }
2597   return n;
2601 static void
2602 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2603 /* --------------------------------------------------------------------------
2604     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2605     Note we can't just use an NSDrawRect command, because of the possibility
2606     of some sides not being drawn, and because the rect will be filled.
2607    -------------------------------------------------------------------------- */
2609   NSRect s = r;
2610   [col set];
2612   /* top, bottom */
2613   s.size.height = thickness;
2614   NSRectFill (s);
2615   s.origin.y += r.size.height - thickness;
2616   NSRectFill (s);
2618   s.size.height = r.size.height;
2619   s.origin.y = r.origin.y;
2621   /* left, right (optional) */
2622   s.size.width = thickness;
2623   if (left_p)
2624     NSRectFill (s);
2625   if (right_p)
2626     {
2627       s.origin.x += r.size.width - thickness;
2628       NSRectFill (s);
2629     }
2633 static void
2634 ns_draw_relief (NSRect r, int thickness, char raised_p,
2635                char top_p, char bottom_p, char left_p, char right_p,
2636                struct glyph_string *s)
2637 /* --------------------------------------------------------------------------
2638     Draw a relief rect inside r, optionally leaving some sides open.
2639     Note we can't just use an NSDrawBezel command, because of the possibility
2640     of some sides not being drawn, and because the rect will be filled.
2641    -------------------------------------------------------------------------- */
2643   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2644   NSColor *newBaseCol = nil;
2645   NSRect sr = r;
2647   NSTRACE (ns_draw_relief);
2649   /* set up colors */
2651   if (s->face->use_box_color_for_shadows_p)
2652     {
2653       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2654     }
2655 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2656            && s->img->pixmap
2657            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2658        {
2659          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2660        } */
2661   else
2662     {
2663       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2664     }
2666   if (newBaseCol == nil)
2667     newBaseCol = [NSColor grayColor];
2669   if (newBaseCol != baseCol)  /* TODO: better check */
2670     {
2671       [baseCol release];
2672       baseCol = [newBaseCol retain];
2673       [lightCol release];
2674       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2675       [darkCol release];
2676       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2677     }
2679   [(raised_p ? lightCol : darkCol) set];
2681   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2683   /* top */
2684   sr.size.height = thickness;
2685   if (top_p) NSRectFill (sr);
2687   /* left */
2688   sr.size.height = r.size.height;
2689   sr.size.width = thickness;
2690   if (left_p) NSRectFill (sr);
2692   [(raised_p ? darkCol : lightCol) set];
2694   /* bottom */
2695   sr.size.width = r.size.width;
2696   sr.size.height = thickness;
2697   sr.origin.y += r.size.height - thickness;
2698   if (bottom_p) NSRectFill (sr);
2700   /* right */
2701   sr.size.height = r.size.height;
2702   sr.origin.y = r.origin.y;
2703   sr.size.width = thickness;
2704   sr.origin.x += r.size.width - thickness;
2705   if (right_p) NSRectFill (sr);
2709 static void
2710 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2711 /* --------------------------------------------------------------------------
2712       Function modeled after x_draw_glyph_string_box ().
2713       Sets up parameters for drawing.
2714    -------------------------------------------------------------------------- */
2716   int right_x, last_x;
2717   char left_p, right_p;
2718   struct glyph *last_glyph;
2719   NSRect r;
2720   int thickness;
2721   struct face *face;
2723   if (s->hl == DRAW_MOUSE_FACE)
2724     {
2725       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2726       if (!face)
2727         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2728     }
2729   else
2730     face = s->face;
2732   thickness = face->box_line_width;
2734   NSTRACE (ns_dumpglyphs_box_or_relief);
2736   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2737             ? WINDOW_RIGHT_EDGE_X (s->w)
2738             : window_box_right (s->w, s->area));
2739   last_glyph = (s->cmp || s->img
2740                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2742   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2743               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2745   left_p = (s->first_glyph->left_box_line_p
2746             || (s->hl == DRAW_MOUSE_FACE
2747                 && (s->prev == NULL || s->prev->hl != s->hl)));
2748   right_p = (last_glyph->right_box_line_p
2749              || (s->hl == DRAW_MOUSE_FACE
2750                  && (s->next == NULL || s->next->hl != s->hl)));
2752   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2754   /* expand full-width row over internal borders */
2755   if (s->row->full_width_p)
2756     r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2757                         FRAME_PIXEL_WIDTH (s->f));
2759   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2760   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2761     {
2762       ns_draw_box (r, abs (thickness),
2763                    ns_lookup_indexed_color (face->box_color, s->f),
2764                   left_p, right_p);
2765     }
2766   else
2767     {
2768       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2769                      1, 1, left_p, right_p, s);
2770     }
2774 static void
2775 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2776 /* --------------------------------------------------------------------------
2777       Modeled after x_draw_glyph_string_background, which draws BG in
2778       certain cases.  Others are left to the text rendering routine.
2779    -------------------------------------------------------------------------- */
2781   NSTRACE (ns_maybe_dumpglyphs_background);
2783   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2784     {
2785       int box_line_width = max (s->face->box_line_width, 0);
2786       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2787           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2788         {
2789           struct face *face;
2790           if (s->hl == DRAW_MOUSE_FACE)
2791             {
2792               face = FACE_FROM_ID (s->f,
2793                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2794               if (!face)
2795                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2796             }
2797           else
2798             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2799           if (!face->stipple)
2800             [(NS_FACE_BACKGROUND (face) != 0
2801               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2802               : FRAME_BACKGROUND_COLOR (s->f)) set];
2803           else
2804             {
2805               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2806               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2807             }
2809           if (s->hl != DRAW_CURSOR)
2810             {
2811               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2812                                     s->background_width,
2813                                     s->height-2*box_line_width);
2815               /* expand full-width row over internal borders */
2816               if (s->row->full_width_p)
2817                 {
2818                   int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2819                   if (r.origin.y <= fibw+1 + box_line_width)
2820                     {
2821                       r.size.height += r.origin.y;
2822                       r.origin.y = 0;
2823                     }
2824                   if (r.origin.x <= fibw+1)
2825                     {
2826                       r.size.width += 2*r.origin.x;
2827                       r.origin.x = 0;
2828                     }
2829                   if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2830                       <= fibw+1)
2831                     r.size.width += fibw;
2832                 }
2834               NSRectFill (r);
2835             }
2837           s->background_filled_p = 1;
2838         }
2839     }
2843 static void
2844 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2845 /* --------------------------------------------------------------------------
2846       Renders an image and associated borders.
2847    -------------------------------------------------------------------------- */
2849   EmacsImage *img = s->img->pixmap;
2850   int box_line_vwidth = max (s->face->box_line_width, 0);
2851   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2852   int bg_x, bg_y, bg_height;
2853   int th;
2854   char raised_p;
2855   NSRect br;
2856   struct face *face;
2858   NSTRACE (ns_dumpglyphs_image);
2860   if (s->face->box != FACE_NO_BOX
2861       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2862     x += abs (s->face->box_line_width);
2864   bg_x = x;
2865   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2866   bg_height = s->height;
2867   /* other terms have this, but was causing problems w/tabbar mode */
2868   /* - 2 * box_line_vwidth; */
2870   if (s->slice.x == 0) x += s->img->hmargin;
2871   if (s->slice.y == 0) y += s->img->vmargin;
2873   /* Draw BG: if we need larger area than image itself cleared, do that,
2874      otherwise, since we composite the image under NS (instead of mucking
2875      with its background color), we must clear just the image area. */
2876   if (s->hl == DRAW_MOUSE_FACE)
2877     {
2878       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2879       if (!face)
2880        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2881     }
2882   else
2883     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2885   if (s->hl == DRAW_CURSOR)
2886       [FRAME_CURSOR_COLOR (s->f) set];
2887   else
2888     [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2890   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2891       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2892     {
2893       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2894       s->background_filled_p = 1;
2895     }
2896   else
2897     {
2898       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2899     }
2901   /* expand full-width row over internal borders */
2902   if (s->row->full_width_p)
2903     {
2904       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2905       if (br.origin.y <= fibw+1 + box_line_vwidth)
2906         {
2907           br.size.height += br.origin.y;
2908           br.origin.y = 0;
2909         }
2910       if (br.origin.x <= fibw+1 + box_line_vwidth)
2911         {
2912           br.size.width += br.origin.x;
2913           br.origin.x = 0;
2914         }
2915       if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
2916         br.size.width += fibw;
2917     }
2919   NSRectFill (br);
2921   /* Draw the image.. do we need to draw placeholder if img ==nil? */
2922   if (img != nil)
2923     [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
2924                 operation: NSCompositeSourceOver];
2926   /* Draw relief, if requested */
2927   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
2928     {
2929       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
2930         {
2931           th = tool_bar_button_relief >= 0 ?
2932             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
2933           raised_p = (s->hl == DRAW_IMAGE_RAISED);
2934         }
2935       else
2936         {
2937           th = abs (s->img->relief);
2938           raised_p = (s->img->relief > 0);
2939         }
2941       r.origin.x = x - th;
2942       r.origin.y = y - th;
2943       r.size.width = s->slice.width + 2*th-1;
2944       r.size.height = s->slice.height + 2*th-1;
2945       ns_draw_relief (r, th, raised_p,
2946                       s->slice.y == 0,
2947                       s->slice.y + s->slice.height == s->img->height,
2948                       s->slice.x == 0,
2949                       s->slice.x + s->slice.width == s->img->width, s);
2950     }
2952   /* If there is no mask, the background won't be seen,
2953      so draw a rectangle on the image for the cursor.
2954      Do this for all images, getting trancparency right is not reliable.  */
2955   if (s->hl == DRAW_CURSOR)
2956     {
2957       int thickness = abs (s->img->relief);
2958       if (thickness == 0) thickness = 1;
2959       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
2960     }
2964 static void
2965 ns_dumpglyphs_stretch (struct glyph_string *s)
2967   NSRect r[2];
2968   int n, i;
2969   struct face *face;
2971   if (!s->background_filled_p)
2972     {
2973       n = ns_get_glyph_string_clip_rect (s, r);
2974       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
2976       for (i=0; i<n; i++)
2977         {
2978           if (!s->row->full_width_p)
2979             {
2980               /* truncate to avoid overwriting fringe and/or scrollbar */
2981               int overrun = max (0, (s->x + s->background_width)
2982                                   - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
2983                                     - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
2984               r[i].size.width -= overrun;
2986               /* XXX: Try to work between problem where a stretch glyph on
2987                  a partially-visible bottom row will clear part of the
2988                  modeline, and another where list-buffers headers and similar
2989                  rows erroneously have visible_height set to 0.  Not sure
2990                  where this is coming from as other terms seem not to show. */
2991               r[i].size.height = min (s->height, s->row->visible_height);
2992             }
2994           /* expand full-width rows over internal borders */
2995           else
2996             {
2997               r[i] = ns_fix_rect_ibw (r[i], FRAME_INTERNAL_BORDER_WIDTH (s->f),
2998                                       FRAME_PIXEL_WIDTH (s->f));
2999             }
3001           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3002              overwriting cursor (usually when cursor on a tab) */
3003           if (s->hl == DRAW_CURSOR)
3004             {
3005               r[i].origin.x += s->width;
3006               r[i].size.width -= s->width;
3007             }
3008         }
3010       ns_focus (s->f, r, n);
3012       if (s->hl == DRAW_MOUSE_FACE)
3013        {
3014          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3015          if (!face)
3016            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3017        }
3018       else
3019        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3021       [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3023       NSRectFill (r[0]);
3024       NSRectFill (r[1]);
3025       ns_unfocus (s->f);
3026       s->background_filled_p = 1;
3027     }
3031 static void
3032 ns_draw_glyph_string (struct glyph_string *s)
3033 /* --------------------------------------------------------------------------
3034       External (RIF): Main draw-text call.
3035    -------------------------------------------------------------------------- */
3037   /* TODO (optimize): focus for box and contents draw */
3038   NSRect r[2];
3039   int n;
3040   char box_drawn_p = 0;
3042   NSTRACE (ns_draw_glyph_string);
3044   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3045     {
3046       int width;
3047       struct glyph_string *next;
3049       for (width = 0, next = s->next;
3050            next && width < s->right_overhang;
3051            width += next->width, next = next->next)
3052         if (next->first_glyph->type != IMAGE_GLYPH)
3053           {
3054             if (next->first_glyph->type != STRETCH_GLYPH)
3055               {
3056                 n = ns_get_glyph_string_clip_rect (s->next, r);
3057                 ns_focus (s->f, r, n);
3058                 ns_maybe_dumpglyphs_background (s->next, 1);
3059                 ns_unfocus (s->f);
3060               }
3061             else
3062               {
3063                 ns_dumpglyphs_stretch (s->next);
3064               }
3065             next->num_clips = 0;
3066           }
3067     }
3069   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3070         && (s->first_glyph->type == CHAR_GLYPH
3071             || s->first_glyph->type == COMPOSITE_GLYPH))
3072     {
3073       n = ns_get_glyph_string_clip_rect (s, r);
3074       ns_focus (s->f, r, n);
3075       ns_maybe_dumpglyphs_background (s, 1);
3076       ns_dumpglyphs_box_or_relief (s);
3077       ns_unfocus (s->f);
3078       box_drawn_p = 1;
3079     }
3081   switch (s->first_glyph->type)
3082     {
3084     case IMAGE_GLYPH:
3085       n = ns_get_glyph_string_clip_rect (s, r);
3086       ns_focus (s->f, r, n);
3087       ns_dumpglyphs_image (s, r[0]);
3088       ns_unfocus (s->f);
3089       break;
3091     case STRETCH_GLYPH:
3092       ns_dumpglyphs_stretch (s);
3093       break;
3095     case CHAR_GLYPH:
3096     case COMPOSITE_GLYPH:
3097       n = ns_get_glyph_string_clip_rect (s, r);
3098       ns_focus (s->f, r, n);
3100       if (s->for_overlaps || (s->cmp_from > 0
3101                               && ! s->first_glyph->u.cmp.automatic))
3102         s->background_filled_p = 1;
3103       else
3104         ns_maybe_dumpglyphs_background
3105           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3107       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3108                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3109                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3110                       NS_DUMPGLYPH_NORMAL));
3111       ns_tmp_font = (struct nsfont_info *)s->face->font;
3112       if (ns_tmp_font == NULL)
3113           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3115       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3116         {
3117           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3118           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3119           NS_FACE_FOREGROUND (s->face) = tmp;
3120         }
3122       ns_tmp_font->font.driver->draw
3123         (s, 0, s->nchars, s->x, s->y,
3124          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3125          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3127       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3128         {
3129           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3130           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3131           NS_FACE_FOREGROUND (s->face) = tmp;
3132         }
3134       ns_unfocus (s->f);
3135       break;
3137     case GLYPHLESS_GLYPH:
3138       n = ns_get_glyph_string_clip_rect (s, r);
3139       ns_focus (s->f, r, n);
3141       if (s->for_overlaps || (s->cmp_from > 0
3142                               && ! s->first_glyph->u.cmp.automatic))
3143         s->background_filled_p = 1;
3144       else
3145         ns_maybe_dumpglyphs_background
3146           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3147       /* ... */
3148       /* Not yet implemented.  */
3149       /* ... */
3150       ns_unfocus (s->f);
3151       break;
3153     default:
3154       abort ();
3155     }
3157   /* Draw box if not done already. */
3158   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3159     {
3160       n = ns_get_glyph_string_clip_rect (s, r);
3161       ns_focus (s->f, r, n);
3162       ns_dumpglyphs_box_or_relief (s);
3163       ns_unfocus (s->f);
3164     }
3166   s->num_clips = 0;
3171 /* ==========================================================================
3173     Event loop
3175    ========================================================================== */
3178 static void
3179 ns_send_appdefined (int value)
3180 /* --------------------------------------------------------------------------
3181     Internal: post an appdefined event which EmacsApp-sendEvent will
3182               recognize and take as a command to halt the event loop.
3183    -------------------------------------------------------------------------- */
3185   /*NSTRACE (ns_send_appdefined); */
3187   /* Only post this event if we haven't already posted one.  This will end
3188        the [NXApp run] main loop after having processed all events queued at
3189        this moment.  */
3190   if (send_appdefined)
3191     {
3192       NSEvent *nxev;
3194       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3195       send_appdefined = NO;
3197       /* Don't need wakeup timer any more */
3198       if (timed_entry)
3199         {
3200           [timed_entry invalidate];
3201           [timed_entry release];
3202           timed_entry = nil;
3203         }
3205       /* Ditto for file descriptor poller */
3206       if (fd_entry)
3207         {
3208           [fd_entry invalidate];
3209           [fd_entry release];
3210           fd_entry = nil;
3211         }
3213       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3214                                 location: NSMakePoint (0, 0)
3215                            modifierFlags: 0
3216                                timestamp: 0
3217                             windowNumber: [[NSApp mainWindow] windowNumber]
3218                                  context: [NSApp context]
3219                                  subtype: 0
3220                                    data1: value
3221                                    data2: 0];
3223       /* Post an application defined event on the event queue.  When this is
3224          received the [NXApp run] will return, thus having processed all
3225          events which are currently queued.  */
3226       [NSApp postEvent: nxev atStart: NO];
3227     }
3231 static int
3232 ns_read_socket (struct terminal *terminal, int expected,
3233                 struct input_event *hold_quit)
3234 /* --------------------------------------------------------------------------
3235      External (hook): Post an event to ourself and keep reading events until
3236      we read it back again.  In effect process all events which were waiting.
3237      From 21+ we have to manage the event buffer ourselves.
3238    -------------------------------------------------------------------------- */
3240   struct input_event ev;
3241   int nevents;
3243 /* NSTRACE (ns_read_socket); */
3245   if (interrupt_input_blocked)
3246     {
3247       interrupt_input_pending = 1;
3248 #ifdef SYNC_INPUT
3249       pending_signals = 1;
3250 #endif
3251       return -1;
3252     }
3254   interrupt_input_pending = 0;
3255 #ifdef SYNC_INPUT
3256   pending_signals = pending_atimers;
3257 #endif
3259   BLOCK_INPUT;
3260   n_emacs_events_pending = 0;
3261   EVENT_INIT (ev);
3262   emacs_event = &ev;
3263   q_event_ptr = hold_quit;
3265   /* we manage autorelease pools by allocate/reallocate each time around
3266      the loop; strict nesting is occasionally violated but seems not to
3267      matter.. earlier methods using full nesting caused major memory leaks */
3268   [outerpool release];
3269   outerpool = [[NSAutoreleasePool alloc] init];
3271   /* If have pending open-file requests, attend to the next one of those. */
3272   if (ns_pending_files && [ns_pending_files count] != 0
3273       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3274     {
3275       [ns_pending_files removeObjectAtIndex: 0];
3276     }
3277   /* Deal with pending service requests. */
3278   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3279     && [(EmacsApp *)
3280          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3281                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3282     {
3283       [ns_pending_service_names removeObjectAtIndex: 0];
3284       [ns_pending_service_args removeObjectAtIndex: 0];
3285     }
3286   else
3287     {
3288       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3289          to ourself, otherwise [NXApp run] will never exit.  */
3290       send_appdefined = YES;
3292       /* If called via ns_select, this is called once with expected=1,
3293          because we expect either the timeout or file descriptor activity.
3294          In this case the first event through will either be real input or
3295          one of these.  read_avail_input() then calls once more with expected=0
3296          and in that case we need to return quickly if there is nothing.
3297          If we're being called outside of that, it's also OK to return quickly
3298          after one iteration through the event loop, since other terms do
3299          this and emacs expects it. */
3300       if (!(inNsSelect && expected))
3301         {
3302           /* Post an application defined event on the event queue.  When this is
3303              received the [NXApp run] will return, thus having processed all
3304              events which are currently queued, if any.  */
3305           ns_send_appdefined (-1);
3306         }
3308       [NSApp run];
3309     }
3311   nevents = n_emacs_events_pending;
3312   n_emacs_events_pending = 0;
3313   emacs_event = q_event_ptr = NULL;
3314   UNBLOCK_INPUT;
3316   return nevents;
3321 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3322            fd_set *exceptfds, struct timeval *timeout)
3323 /* --------------------------------------------------------------------------
3324      Replacement for select, checking for events
3325    -------------------------------------------------------------------------- */
3327   int result;
3328   double time;
3329   NSEvent *ev;
3330 /*  NSTRACE (ns_select); */
3332   if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO &&
3333                       [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
3334  inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
3335     return select (nfds, readfds, writefds, exceptfds, timeout);
3337   /* Save file descriptor set, which gets overwritten in calls to select ()
3338      Note, this is called from process.c, and only readfds is ever set */
3339   if (readfds)
3340     {
3341       memcpy (&select_readfds, readfds, sizeof (fd_set));
3342       select_nfds = nfds;
3343     }
3344   else
3345     select_nfds = 0;
3347     /* Try an initial select for pending data on input files */
3348   select_timeout.tv_sec = select_timeout.tv_usec = 0;
3349   result = select (nfds, readfds, writefds, exceptfds, &select_timeout);
3350   if (result)
3351     return result;
3353   /* if (!timeout || timed_entry || fd_entry)
3354        fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
3356     /* set a timeout and run the main AppKit event loop while continuing
3357        to monitor the files */
3358   time = ((double) timeout->tv_sec) + ((double) timeout->tv_usec)/1000000.0;
3359   timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3360                                            target: NSApp
3361                                          selector: @selector (timeout_handler:)
3362                                          userInfo: 0
3363                                           repeats: YES] /* for safe removal */
3364                                                          retain];
3366   /* set a periodic task to try the select () again */
3367   fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
3368                                                target: NSApp
3369                                              selector: @selector (fd_handler:)
3370                                              userInfo: 0
3371                                               repeats: YES]
3372                retain];
3374   /* Let Application dispatch events until it receives an event of the type
3375      NX_APPDEFINED, which should only be sent by timeout_handler.
3376      We tell read_avail_input() that input is "expected" because we do expect
3377      either the timeout or fd handler to fire, and if they don't, the original
3378      call from process.c that got us here expects us to wait until some input
3379      comes. */
3380   inNsSelect = 1;
3381   gobble_input (1);
3382   ev = last_appdefined_event;
3383   inNsSelect = 0;
3385   if (ev)
3386     {
3387       int t;
3388       if ([ev type] != NSApplicationDefined)
3389         abort ();
3391       t = [ev data1];
3392       last_appdefined_event = 0;
3394       if (t == -2)
3395         {
3396           /* The NX_APPDEFINED event we received was a timeout. */
3397           return 0;
3398         }
3399       else if (t == -1)
3400         {
3401           /* The NX_APPDEFINED event we received was the result of
3402              at least one real input event arriving.  */
3403           errno = EINTR;
3404           return -1;
3405         }
3406       else
3407         {
3408           /* Received back from select () in fd_handler; copy the results */
3409           if (readfds)
3410             memcpy (readfds, &select_readfds, sizeof (fd_set));
3411           return t;
3412         }
3413     }
3414   /* never reached, shut compiler up */
3415   return 0;
3420 /* ==========================================================================
3422     Scrollbar handling
3424    ========================================================================== */
3427 static void
3428 ns_set_vertical_scroll_bar (struct window *window,
3429                            int portion, int whole, int position)
3430 /* --------------------------------------------------------------------------
3431       External (hook): Update or add scrollbar
3432    -------------------------------------------------------------------------- */
3434   Lisp_Object win;
3435   NSRect r, v;
3436   struct frame *f = XFRAME (WINDOW_FRAME (window));
3437   EmacsView *view = FRAME_NS_VIEW (f);
3438   int window_y, window_height;
3439   BOOL barOnVeryLeft, barOnVeryRight;
3440   int top, left, height, width, sb_width, sb_left;
3441   EmacsScroller *bar;
3442 static int count = 0;
3444   /* optimization; display engine sends WAY too many of these.. */
3445   if (!NILP (window->vertical_scroll_bar))
3446     {
3447       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3448       if ([bar checkSamePosition: position portion: portion whole: whole])
3449         {
3450           if (view->scrollbarsNeedingUpdate == 0)
3451             {
3452               if (!windows_or_buffers_changed)
3453                   return;
3454             }
3455           else
3456             view->scrollbarsNeedingUpdate--;
3457         }
3458     }
3460   NSTRACE (ns_set_vertical_scroll_bar);
3462   /* Get dimensions.  */
3463   window_box (window, -1, 0, &window_y, 0, &window_height);
3464   top = window_y;
3465   height = window_height;
3466   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3467   left = WINDOW_SCROLL_BAR_AREA_X (window);
3469   if (top < 5) /* top scrollbar adjustment */
3470     {
3471       top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3472       height += FRAME_INTERNAL_BORDER_WIDTH (f);
3473     }
3475   /* allow for displaying a skinnier scrollbar than char area allotted */
3476   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3477     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3479   barOnVeryLeft = left < 5;
3480   barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3481   sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3482       * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3484   r = NSMakeRect (sb_left, top, sb_width, height);
3485   /* the parent view is flipped, so we need to flip y value */
3486   v = [view frame];
3487   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3489   XSETWINDOW (win, window);
3490   BLOCK_INPUT;
3492   /* we want at least 5 lines to display a scrollbar */
3493   if (WINDOW_TOTAL_LINES (window) < 5)
3494     {
3495       if (!NILP (window->vertical_scroll_bar))
3496         {
3497           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3498           [bar removeFromSuperview];
3499           window->vertical_scroll_bar = Qnil;
3500         }
3501       ns_clear_frame_area (f, sb_left, top, width, height);
3502       UNBLOCK_INPUT;
3503       return;
3504     }
3506   if (NILP (window->vertical_scroll_bar))
3507     {
3508       ns_clear_frame_area (f, sb_left, top, width, height);
3509       bar = [[EmacsScroller alloc] initFrame: r window: win];
3510       window->vertical_scroll_bar = make_save_value (bar, 0);
3511     }
3512   else
3513     {
3514       NSRect oldRect;
3515       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3516       oldRect = [bar frame];
3517       r.size.width = oldRect.size.width;
3518       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3519         {
3520           if (oldRect.origin.x != r.origin.x)
3521               ns_clear_frame_area (f, sb_left, top, width, height);
3522           [bar setFrame: r];
3523         }
3524     }
3526   [bar setPosition: position portion: portion whole: whole];
3527   UNBLOCK_INPUT;
3531 static void
3532 ns_condemn_scroll_bars (struct frame *f)
3533 /* --------------------------------------------------------------------------
3534      External (hook): arrange for all frame's scrollbars to be removed
3535      at next call to judge_scroll_bars, except for those redeemed.
3536    -------------------------------------------------------------------------- */
3538   int i;
3539   id view;
3540   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3542   NSTRACE (ns_condemn_scroll_bars);
3544   for (i =[subviews count]-1; i >= 0; i--)
3545     {
3546       view = [subviews objectAtIndex: i];
3547       if ([view isKindOfClass: [EmacsScroller class]])
3548         [view condemn];
3549     }
3553 static void
3554 ns_redeem_scroll_bar (struct window *window)
3555 /* --------------------------------------------------------------------------
3556      External (hook): arrange to spare this window's scrollbar
3557      at next call to judge_scroll_bars.
3558    -------------------------------------------------------------------------- */
3560   id bar;
3561   NSTRACE (ns_redeem_scroll_bar);
3562   if (!NILP (window->vertical_scroll_bar))
3563     {
3564       bar =XNS_SCROLL_BAR (window->vertical_scroll_bar);
3565       [bar reprieve];
3566     }
3570 static void
3571 ns_judge_scroll_bars (struct frame *f)
3572 /* --------------------------------------------------------------------------
3573      External (hook): destroy all scrollbars on frame that weren't
3574      redeemed after call to condemn_scroll_bars.
3575    -------------------------------------------------------------------------- */
3577   int i;
3578   id view;
3579   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3580   NSTRACE (ns_judge_scroll_bars);
3581   for (i =[subviews count]-1; i >= 0; i--)
3582     {
3583       view = [subviews objectAtIndex: i];
3584       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3585       [view judge];
3586     }
3590 void
3591 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3593   /* XXX irrelevant under NS */
3598 /* ==========================================================================
3600     Initialization
3602    ========================================================================== */
3605 x_display_pixel_height (struct ns_display_info *dpyinfo)
3607   NSScreen *screen = [NSScreen mainScreen];
3608   return [screen frame].size.height;
3612 x_display_pixel_width (struct ns_display_info *dpyinfo)
3614   NSScreen *screen = [NSScreen mainScreen];
3615   return [screen frame].size.width;
3619 static Lisp_Object ns_string_to_lispmod (const char *s)
3620 /* --------------------------------------------------------------------------
3621      Convert modifier name to lisp symbol
3622    -------------------------------------------------------------------------- */
3624   if (!strncmp (SDATA (SYMBOL_NAME (Qmeta)), s, 10))
3625     return Qmeta;
3626   else if (!strncmp (SDATA (SYMBOL_NAME (Qsuper)), s, 10))
3627     return Qsuper;
3628   else if (!strncmp (SDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3629     return Qcontrol;
3630   else if (!strncmp (SDATA (SYMBOL_NAME (Qalt)), s, 10))
3631     return Qalt;
3632   else if (!strncmp (SDATA (SYMBOL_NAME (Qhyper)), s, 10))
3633     return Qhyper;
3634   else if (!strncmp (SDATA (SYMBOL_NAME (Qnone)), s, 10))
3635     return Qnone;
3636   else
3637     return Qnil;
3641 static Lisp_Object ns_mod_to_lisp (int m)
3642 /* --------------------------------------------------------------------------
3643      Convert modifier code (see lisp.h) to lisp symbol
3644    -------------------------------------------------------------------------- */
3646   if (m == CHAR_META)
3647     return Qmeta;
3648   else if (m == CHAR_SUPER)
3649     return Qsuper;
3650   else if (m == CHAR_CTL)
3651     return Qcontrol;
3652   else if (m == CHAR_ALT)
3653     return Qalt;
3654   else if (m == CHAR_HYPER)
3655     return Qhyper;
3656   else /* if (m == 0) */
3657     return Qnone;
3661 static void
3662 ns_default (const char *parameter, Lisp_Object *result,
3663            Lisp_Object yesval, Lisp_Object noval,
3664            BOOL is_float, BOOL is_modstring)
3665 /* --------------------------------------------------------------------------
3666       Check a parameter value in user's preferences
3667    -------------------------------------------------------------------------- */
3669   const char *value;
3671   if ( (value =[[[NSUserDefaults standardUserDefaults]
3672                    stringForKey: [NSString stringWithUTF8String: parameter]]
3673                 UTF8String]) )
3674     {
3675       double f;
3676       char *pos;
3677       if (strcasecmp (value, "YES") == 0)
3678         *result = yesval;
3679       else if (strcasecmp (value, "NO") == 0)
3680         *result = noval;
3681       else if (is_float && (f = strtod (value, &pos), pos != value))
3682         *result = make_float (f);
3683       else if (is_modstring && value)
3684         *result = ns_string_to_lispmod (value);
3685       else fprintf (stderr,
3686                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3687     }
3691 void
3692 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3693 /* --------------------------------------------------------------------------
3694       Initialize global info and storage for display.
3695    -------------------------------------------------------------------------- */
3697     NSScreen *screen = [NSScreen mainScreen];
3698     NSWindowDepth depth = [screen depth];
3699     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3701     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3702     dpyinfo->resy = 72.27;
3703     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3704                                                   NSColorSpaceFromDepth (depth)]
3705                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3706                                                  NSColorSpaceFromDepth (depth)];
3707     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3708     dpyinfo->image_cache = make_image_cache ();
3709     dpyinfo->color_table
3710       = (struct ns_color_table *)xmalloc (sizeof (struct ns_color_table));
3711     dpyinfo->color_table->colors = NULL;
3712     dpyinfo->root_window = 42; /* a placeholder.. */
3714     hlinfo->mouse_face_mouse_frame = NULL;
3715     hlinfo->mouse_face_deferred_gc = 0;
3716     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3717     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3718     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3719     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3720     hlinfo->mouse_face_hidden = 0;
3722     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3723     hlinfo->mouse_face_defer = 0;
3725     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3727     dpyinfo->n_fonts = 0;
3728     dpyinfo->smallest_font_height = 1;
3729     dpyinfo->smallest_char_width = 1;
3733 /* This and next define (many of the) public functions in this file. */
3734 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3735          with using despite presence in the "system dependent" redisplay
3736          interface.  In addition, many of the ns_ methods have code that is
3737          shared with all terms, indicating need for further refactoring. */
3738 extern frame_parm_handler ns_frame_parm_handlers[];
3739 static struct redisplay_interface ns_redisplay_interface =
3741   ns_frame_parm_handlers,
3742   x_produce_glyphs,
3743   x_write_glyphs,
3744   x_insert_glyphs,
3745   x_clear_end_of_line,
3746   ns_scroll_run,
3747   ns_after_update_window_line,
3748   ns_update_window_begin,
3749   ns_update_window_end,
3750   x_cursor_to,
3751   ns_flush,
3752   0, /* flush_display_optional */
3753   x_clear_window_mouse_face,
3754   x_get_glyph_overhangs,
3755   x_fix_overlapping_area,
3756   ns_draw_fringe_bitmap,
3757   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3758   0, /* destroy_fringe_bitmap */
3759   ns_compute_glyph_string_overhangs,
3760   ns_draw_glyph_string, /* interface to nsfont.m */
3761   ns_define_frame_cursor,
3762   ns_clear_frame_area,
3763   ns_draw_window_cursor,
3764   ns_draw_vertical_window_border,
3765   ns_shift_glyphs_for_insert
3769 static void
3770 ns_delete_display (struct ns_display_info *dpyinfo)
3772   /* TODO... */
3776 /* This function is called when the last frame on a display is deleted. */
3777 static void
3778 ns_delete_terminal (struct terminal *terminal)
3780   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3781   int i;
3783   /* Protect against recursive calls.  delete_frame in
3784      delete_terminal calls us back when it deletes our last frame.  */
3785   if (!terminal->name)
3786     return;
3788   BLOCK_INPUT;
3790   x_destroy_all_bitmaps (dpyinfo);
3791   ns_delete_display (dpyinfo);
3792   UNBLOCK_INPUT;
3796 static struct terminal *
3797 ns_create_terminal (struct ns_display_info *dpyinfo)
3798 /* --------------------------------------------------------------------------
3799       Set up use of NS before we make the first connection.
3800    -------------------------------------------------------------------------- */
3802   struct terminal *terminal;
3804   NSTRACE (ns_create_terminal);
3806   terminal = create_terminal ();
3808   terminal->type = output_ns;
3809   terminal->display_info.ns = dpyinfo;
3810   dpyinfo->terminal = terminal;
3812   terminal->rif = &ns_redisplay_interface;
3814   terminal->clear_frame_hook = ns_clear_frame;
3815   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3816   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3817   terminal->ring_bell_hook = ns_ring_bell;
3818   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3819   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3820   terminal->update_begin_hook = ns_update_begin;
3821   terminal->update_end_hook = ns_update_end;
3822   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
3823   terminal->read_socket_hook = ns_read_socket;
3824   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3825   terminal->mouse_position_hook = ns_mouse_position;
3826   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3827   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3829   terminal->fullscreen_hook = 0; /* see XTfullscreen_hook */
3831   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3832   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3833   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3834   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3836   terminal->delete_frame_hook = x_destroy_window;
3837   terminal->delete_terminal_hook = ns_delete_terminal;
3839   terminal->scroll_region_ok = 1;
3840   terminal->char_ins_del_ok = 1;
3841   terminal->line_ins_del_ok = 1;
3842   terminal->fast_clear_end_of_line = 1;
3843   terminal->memory_below_frame = 0;
3845   return terminal;
3849 struct ns_display_info *
3850 ns_term_init (Lisp_Object display_name)
3851 /* --------------------------------------------------------------------------
3852      Start the Application and get things rolling.
3853    -------------------------------------------------------------------------- */
3855   struct terminal *terminal;
3856   struct ns_display_info *dpyinfo;
3857   static int ns_initialized = 0;
3858   Lisp_Object tmp;
3860   NSTRACE (ns_term_init);
3862   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
3863   /*GSDebugAllocationActive (YES); */
3864   BLOCK_INPUT;
3865   handling_signal = 0;
3867   if (!ns_initialized)
3868     {
3869       baud_rate = 38400;
3870       Fset_input_interrupt_mode (Qnil);
3871       ns_initialized = 1;
3872     }
3874   ns_pending_files = [[NSMutableArray alloc] init];
3875   ns_pending_service_names = [[NSMutableArray alloc] init];
3876   ns_pending_service_args = [[NSMutableArray alloc] init];
3878   /* Start app and create the main menu, window, view.
3879      Needs to be here because ns_initialize_display_info () uses AppKit classes.
3880      The view will then ask the NSApp to stop and return to Emacs. */
3881   [EmacsApp sharedApplication];
3882   if (NSApp == nil)
3883     return NULL;
3884   [NSApp setDelegate: NSApp];
3886   /* debugging: log all notifications */
3887   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
3888                                          selector: @selector (logNotification:)
3889                                              name: nil object: nil]; */
3891   dpyinfo = (struct ns_display_info *)xmalloc (sizeof (struct ns_display_info));
3892   memset (dpyinfo, 0, sizeof (struct ns_display_info));
3894   ns_initialize_display_info (dpyinfo);
3895   terminal = ns_create_terminal (dpyinfo);
3897   terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
3898   init_kboard (terminal->kboard);
3899   KVAR (terminal->kboard, Vwindow_system) = Qns;
3900   terminal->kboard->next_kboard = all_kboards;
3901   all_kboards = terminal->kboard;
3902   /* Don't let the initial kboard remain current longer than necessary.
3903      That would cause problems if a file loaded on startup tries to
3904      prompt in the mini-buffer.  */
3905   if (current_kboard == initial_kboard)
3906     current_kboard = terminal->kboard;
3907   terminal->kboard->reference_count++;
3909   dpyinfo->next = x_display_list;
3910   x_display_list = dpyinfo;
3912   /* Put it on ns_display_name_list */
3913   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
3914                                 ns_display_name_list);
3915   dpyinfo->name_list_element = XCAR (ns_display_name_list);
3917   /* Set the name of the terminal. */
3918   terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
3919   strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
3920   terminal->name[SBYTES (display_name)] = 0;
3922   UNBLOCK_INPUT;
3924   if (!inhibit_x_resources)
3925     {
3926       ns_default ("GSFontAntiAlias", &ns_antialias_text,
3927                  Qt, Qnil, NO, NO);
3928       tmp = Qnil;
3929       /* this is a standard variable */
3930       ns_default ("AppleAntiAliasingThreshold", &tmp,
3931                  make_float (10.0), make_float (6.0), YES, NO);
3932       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
3933     }
3935   ns_selection_color = [[NSUserDefaults standardUserDefaults]
3936                          stringForKey: @"AppleHighlightColor"];
3937   if (ns_selection_color == nil)
3938     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
3940   {
3941     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
3943     if ( cl == nil )
3944       {
3945         Lisp_Object color_file, color_map, color;
3946         int r,g,b;
3947         unsigned long c;
3948         char *name;
3950         color_file = Fexpand_file_name (build_string ("rgb.txt"),
3951                          Fsymbol_value (intern ("data-directory")));
3952         if (NILP (Ffile_readable_p (color_file)))
3953           fatal ("Could not find %s.\n", SDATA (color_file));
3955         color_map = Fx_load_color_file (color_file);
3956         if (NILP (color_map))
3957           fatal ("Could not read %s.\n", SDATA (color_file));
3959         cl = [[NSColorList alloc] initWithName: @"Emacs"];
3960         for ( ; CONSP (color_map); color_map = XCDR (color_map))
3961           {
3962             color = XCAR (color_map);
3963             name = SDATA (XCAR (color));
3964             c = XINT (XCDR (color));
3965             [cl setColor:
3966                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
3967                                             green: GREEN_FROM_ULONG (c) / 255.0
3968                                              blue: BLUE_FROM_ULONG (c) / 255.0
3969                                             alpha: 1.0]
3970                   forKey: [NSString stringWithUTF8String: name]];
3971           }
3972         [cl writeToFile: nil];
3973       }
3974   }
3976   {
3977     char c[128];
3978 #ifdef NS_IMPL_GNUSTEP
3979     strncpy (c, gnustep_base_version, sizeof (c));
3980 #else
3981     /*PSnextrelease (128, c); */
3982     snprintf (c, sizeof (c), "%g", NSAppKitVersionNumber);
3983 #endif
3984     Vwindow_system_version = build_string (c);
3985   }
3987   delete_keyboard_wait_descriptor (0);
3989   ns_app_name = [[NSProcessInfo processInfo] processName];
3991 /* Set up OS X app menu */
3992 #ifdef NS_IMPL_COCOA
3993   {
3994     NSMenu *appMenu;
3995     NSMenuItem *item;
3996     /* set up the application menu */
3997     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
3998     [svcsMenu setAutoenablesItems: NO];
3999     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4000     [appMenu setAutoenablesItems: NO];
4001     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4002     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4004     [appMenu insertItemWithTitle: @"About Emacs"
4005                           action: @selector (orderFrontStandardAboutPanel:)
4006                    keyEquivalent: @""
4007                          atIndex: 0];
4008     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4009     [appMenu insertItemWithTitle: @"Preferences..."
4010                           action: @selector (showPreferencesWindow:)
4011                    keyEquivalent: @","
4012                          atIndex: 2];
4013     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4014     item = [appMenu insertItemWithTitle: @"Services"
4015                                  action: @selector (menuDown:)
4016                           keyEquivalent: @""
4017                                 atIndex: 4];
4018     [appMenu setSubmenu: svcsMenu forItem: item];
4019     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4020     [appMenu insertItemWithTitle: @"Hide Emacs"
4021                           action: @selector (hide:)
4022                    keyEquivalent: @"h"
4023                          atIndex: 6];
4024     item =  [appMenu insertItemWithTitle: @"Hide Others"
4025                           action: @selector (hideOtherApplications:)
4026                    keyEquivalent: @"h"
4027                          atIndex: 7];
4028     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4029     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4030     [appMenu insertItemWithTitle: @"Quit Emacs"
4031                           action: @selector (terminate:)
4032                    keyEquivalent: @"q"
4033                          atIndex: 9];
4035     item = [mainMenu insertItemWithTitle: ns_app_name
4036                                   action: @selector (menuDown:)
4037                            keyEquivalent: @""
4038                                  atIndex: 0];
4039     [mainMenu setSubmenu: appMenu forItem: item];
4040     [dockMenu insertItemWithTitle: @"New Frame"
4041                            action: @selector (newFrame:)
4042                     keyEquivalent: @""
4043                           atIndex: 0];
4045     [NSApp setMainMenu: mainMenu];
4046     [NSApp setAppleMenu: appMenu];
4047     [NSApp setServicesMenu: svcsMenu];
4048     /* Needed at least on Cocoa, to get dock menu to show windows */
4049     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4050   }
4051 #endif /* MAC OS X menu setup */
4053   [NSApp run];
4055   return dpyinfo;
4059 void
4060 ns_term_shutdown (int sig)
4062   [[NSUserDefaults standardUserDefaults] synchronize];
4064   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4065   if (STRINGP (Vauto_save_list_file_name))
4066     unlink (SDATA (Vauto_save_list_file_name));
4068   if (sig == 0 || sig == SIGTERM)
4069     {
4070       [NSApp terminate: NSApp];
4071     }
4072   else // force a stack trace to happen
4073     {
4074       abort();
4075     }
4079 /* ==========================================================================
4081     EmacsApp implementation
4083    ========================================================================== */
4086 @implementation EmacsApp
4088 - (void)logNotification: (NSNotification *)notification
4090   const char *name = [[notification name] UTF8String];
4091   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4092       && !strstr (name, "WindowNumber"))
4093     NSLog (@"notification: '%@'", [notification name]);
4097 - (void)sendEvent: (NSEvent *)theEvent
4098 /* --------------------------------------------------------------------------
4099      Called when NSApp is running for each event received.  Used to stop
4100      the loop when we choose, since there's no way to just run one iteration.
4101    -------------------------------------------------------------------------- */
4103   int type = [theEvent type];
4104   NSWindow *window = [theEvent window];
4105 /*  NSTRACE (sendEvent); */
4106 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4108   if (type == NSCursorUpdate && window == nil)
4109     {
4110       fprintf (stderr, "Dropping external cursor update event.\n");
4111       return;
4112     }
4114 #ifdef NS_IMPL_COCOA
4115   /* pass mouse down in resize handle and subsequent drags directly to
4116      EmacsWindow so we can generate continuous redisplays */
4117   if (ns_in_resize)
4118     {
4119       if (type == NSLeftMouseDragged)
4120         {
4121           [window mouseDragged: theEvent];
4122           return;
4123         }
4124       else if (type == NSLeftMouseUp)
4125         {
4126           [window mouseUp: theEvent];
4127           return;
4128         }
4129     }
4130   else if (type == NSLeftMouseDown)
4131     {
4132       NSRect r = ns_resize_handle_rect (window);
4133       if (NSPointInRect ([theEvent locationInWindow], r))
4134         {
4135           ns_in_resize = YES;
4136           [window mouseDown: theEvent];
4137           return;
4138         }
4139     }
4140 #endif
4142   if (type == NSApplicationDefined)
4143     {
4144       /* Events posted by ns_send_appdefined interrupt the run loop here.
4145          But, if a modal window is up, an appdefined can still come through,
4146          (e.g., from a makeKeyWindow event) but stopping self also stops the
4147          modal loop. Just defer it until later. */
4148       if ([NSApp modalWindow] == nil)
4149         {
4150           last_appdefined_event = theEvent;
4151           [self stop: self];
4152         }
4153       else
4154         {
4155           send_appdefined = YES;
4156         }
4157     }
4159   [super sendEvent: theEvent];
4163 - (void)showPreferencesWindow: (id)sender
4165   struct frame *emacsframe = SELECTED_FRAME ();
4166   NSEvent *theEvent = [NSApp currentEvent];
4168   if (!emacs_event)
4169     return;
4170   emacs_event->kind = NS_NONKEY_EVENT;
4171   emacs_event->code = KEY_NS_SHOW_PREFS;
4172   emacs_event->modifiers = 0;
4173   EV_TRAILER (theEvent);
4177 - (void)newFrame: (id)sender
4179   struct frame *emacsframe = SELECTED_FRAME ();
4180   NSEvent *theEvent = [NSApp currentEvent];
4182   if (!emacs_event)
4183     return;
4184   emacs_event->kind = NS_NONKEY_EVENT;
4185   emacs_event->code = KEY_NS_NEW_FRAME;
4186   emacs_event->modifiers = 0;
4187   EV_TRAILER (theEvent);
4191 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4192 - (BOOL) openFile: (NSString *)fileName
4194   struct frame *emacsframe = SELECTED_FRAME ();
4195   NSEvent *theEvent = [NSApp currentEvent];
4197   if (!emacs_event)
4198     return NO;
4200   emacs_event->kind = NS_NONKEY_EVENT;
4201   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4202   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4203   ns_input_line = Qnil; /* can be start or cons start,end */
4204   emacs_event->modifiers =0;
4205   EV_TRAILER (theEvent);
4207   return YES;
4211 /* **************************************************************************
4213       EmacsApp delegate implementation
4215    ************************************************************************** */
4217 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4218 /* --------------------------------------------------------------------------
4219      When application is loaded, terminate event loop in ns_term_init
4220    -------------------------------------------------------------------------- */
4222   NSTRACE (applicationDidFinishLaunching);
4223   [NSApp setServicesProvider: NSApp];
4224   ns_send_appdefined (-2);
4228 /* Termination sequences:
4229     C-x C-c:
4230     Cmd-Q:
4231     MenuBar | File | Exit:
4232     Select Quit from App menubar:
4233         -terminate
4234         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4235         ns_term_shutdown()
4237     Select Quit from Dock menu:
4238     Logout attempt:
4239         -appShouldTerminate
4240           Cancel -> Nothing else
4241           Accept ->
4243           -terminate
4244           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4245           ns_term_shutdown()
4249 - (void) terminate: (id)sender
4251   struct frame *emacsframe = SELECTED_FRAME ();
4253   if (!emacs_event)
4254     return;
4256   emacs_event->kind = NS_NONKEY_EVENT;
4257   emacs_event->code = KEY_NS_POWER_OFF;
4258   emacs_event->arg = Qt; /* mark as non-key event */
4259   EV_TRAILER ((id)nil);
4263 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4265   int ret;
4267   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4268     return NSTerminateNow;
4270     ret = NSRunAlertPanel(ns_app_name,
4271                           [NSString stringWithUTF8String:"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?"],
4272                           @"Save Buffers and Exit", @"Cancel", nil);
4274     if (ret == NSAlertDefaultReturn)
4275         return NSTerminateNow;
4276     else if (ret == NSAlertAlternateReturn)
4277         return NSTerminateCancel;
4278     return NSTerminateNow;  /* just in case */
4282 /*   Notification from the Workspace to open a file */
4283 - (BOOL)application: sender openFile: (NSString *)file
4285   [ns_pending_files addObject: file];
4286   return YES;
4290 /*   Open a file as a temporary file */
4291 - (BOOL)application: sender openTempFile: (NSString *)file
4293   [ns_pending_files addObject: file];
4294   return YES;
4298 /*   Notification from the Workspace to open a file noninteractively (?) */
4299 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4301   [ns_pending_files addObject: file];
4302   return YES;
4306 /*   Notification from the Workspace to open multiple files */
4307 - (void)application: sender openFiles: (NSArray *)fileList
4309   NSEnumerator *files = [fileList objectEnumerator];
4310   NSString *file;
4311   while ((file = [files nextObject]) != nil)
4312     [ns_pending_files addObject: file];
4314   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4319 /* Handle dock menu requests.  */
4320 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4322   return dockMenu;
4326 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4327 - (void)applicationWillBecomeActive: (NSNotification *)notification
4329   //ns_app_active=YES;
4331 - (void)applicationDidBecomeActive: (NSNotification *)notification
4333   NSTRACE (applicationDidBecomeActive);
4335   //ns_app_active=YES;
4337   ns_update_auto_hide_menu_bar ();
4338   // No constrining takes place when the application is not active.
4339   ns_constrain_all_frames ();
4341 - (void)applicationDidResignActive: (NSNotification *)notification
4343   //ns_app_active=NO;
4344   ns_send_appdefined (-1);
4349 /* ==========================================================================
4351     EmacsApp aux handlers for managing event loop
4353    ========================================================================== */
4356 - (void)timeout_handler: (NSTimer *)timedEntry
4357 /* --------------------------------------------------------------------------
4358      The timeout specified to ns_select has passed.
4359    -------------------------------------------------------------------------- */
4361   /*NSTRACE (timeout_handler); */
4362   ns_send_appdefined (-2);
4365 - (void)fd_handler: (NSTimer *) fdEntry
4366 /* --------------------------------------------------------------------------
4367      Check data waiting on file descriptors and terminate if so
4368    -------------------------------------------------------------------------- */
4370   int result;
4371   /* NSTRACE (fd_handler); */
4373   if (select_nfds == 0)
4374     return;
4376   memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4378   select_timeout.tv_sec = select_timeout.tv_usec = 0;
4379   result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
4380                   &select_timeout);
4381   if (result)
4382     {
4383       memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4384       ns_send_appdefined (result);
4385     }
4390 /* ==========================================================================
4392     Service provision
4394    ========================================================================== */
4396 /* called from system: queue for next pass through event loop */
4397 - (void)requestService: (NSPasteboard *)pboard
4398               userData: (NSString *)userData
4399                  error: (NSString **)error
4401   [ns_pending_service_names addObject: userData];
4402   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4403       SDATA (ns_string_from_pasteboard (pboard))]];
4407 /* called from ns_read_socket to clear queue */
4408 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4410   struct frame *emacsframe = SELECTED_FRAME ();
4411   NSEvent *theEvent = [NSApp currentEvent];
4413   if (!emacs_event)
4414     return NO;
4416   emacs_event->kind = NS_NONKEY_EVENT;
4417   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4418   ns_input_spi_name = build_string ([name UTF8String]);
4419   ns_input_spi_arg = build_string ([arg UTF8String]);
4420   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4421   EV_TRAILER (theEvent);
4423   return YES;
4427 @end  /* EmacsApp */
4431 /* ==========================================================================
4433     EmacsView implementation
4435    ========================================================================== */
4438 @implementation EmacsView
4440 /* needed to inform when window closed from LISP */
4441 - (void) setWindowClosing: (BOOL)closing
4443   windowClosing = closing;
4447 - (void)dealloc
4449   NSTRACE (EmacsView_dealloc);
4450   [toolbar release];
4451   [super dealloc];
4455 /* called on font panel selection */
4456 - (void)changeFont: (id)sender
4458   NSEvent *e =[[self window] currentEvent];
4459   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4460   id newFont;
4461   float size;
4463   NSTRACE (changeFont);
4464   if (!emacs_event)
4465     return;
4467   if (newFont = [sender convertFont:
4468                            ((struct nsfont_info *)face->font)->nsfont])
4469     {
4470       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4472       emacs_event->kind = NS_NONKEY_EVENT;
4473       emacs_event->modifiers = 0;
4474       emacs_event->code = KEY_NS_CHANGE_FONT;
4476       size = [newFont pointSize];
4477       ns_input_fontsize = make_number (lrint (size));
4478       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4479       EV_TRAILER (e);
4480     }
4484 - (BOOL)acceptsFirstResponder
4486   NSTRACE (acceptsFirstResponder);
4487   return YES;
4491 - (void)resetCursorRects
4493   NSRect visible = [self visibleRect];
4494   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4495   NSTRACE (resetCursorRects);
4497   if (currentCursor == nil)
4498     currentCursor = [NSCursor arrowCursor];
4500   if (!NSIsEmptyRect (visible))
4501     [self addCursorRect: visible cursor: currentCursor];
4502   [currentCursor setOnMouseEntered: YES];
4507 /*****************************************************************************/
4508 /* Keyboard handling. */
4509 #define NS_KEYLOG 0
4511 - (void)keyDown: (NSEvent *)theEvent
4513   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4514   int code;
4515   unsigned fnKeysym = 0;
4516   int flags;
4517   static NSMutableArray *nsEvArray;
4518 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4519   static BOOL firstTime = YES;
4520 #endif
4521   int left_is_none;
4523   NSTRACE (keyDown);
4525   /* Rhapsody and OS X give up and down events for the arrow keys */
4526   if (ns_fake_keydown == YES)
4527     ns_fake_keydown = NO;
4528   else if ([theEvent type] != NSKeyDown)
4529     return;
4531   if (!emacs_event)
4532     return;
4534  if (![[self window] isKeyWindow]
4535      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4536      /* we must avoid an infinite loop here. */
4537      && (EmacsView *)[[theEvent window] delegate] != self)
4538    {
4539      /* XXX: There is an occasional condition in which, when Emacs display
4540          updates a different frame from the current one, and temporarily
4541          selects it, then processes some interrupt-driven input
4542          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4543          for some reason that window has its first responder set to the NSView
4544          most recently updated (I guess), which is not the correct one. */
4545      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4546      return;
4547    }
4549   if (nsEvArray == nil)
4550     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4552   [NSCursor setHiddenUntilMouseMoves: YES];
4554   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4555     {
4556       clear_mouse_face (hlinfo);
4557       hlinfo->mouse_face_hidden = 1;
4558     }
4560   if (!processingCompose)
4561     {
4562       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4563         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4564       /* (Carbon way: [theEvent keyCode]) */
4566       /* is it a "function key"? */
4567       fnKeysym = ns_convert_key (code);
4568       if (fnKeysym)
4569         {
4570           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4571              because Emacs treats Delete and KP-Delete same (in simple.el). */
4572           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4573             code = 0xFF08; /* backspace */
4574           else
4575             code = fnKeysym;
4576         }
4578       /* are there modifiers? */
4579       emacs_event->modifiers = 0;
4580       flags = [theEvent modifierFlags];
4582       if (flags & NSHelpKeyMask)
4583           emacs_event->modifiers |= hyper_modifier;
4585       if (flags & NSShiftKeyMask)
4586         emacs_event->modifiers |= shift_modifier;
4588       if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask)
4589         emacs_event->modifiers |= parse_solitary_modifier
4590           (EQ (ns_right_command_modifier, Qleft)
4591            ? ns_command_modifier
4592            : ns_right_command_modifier);
4594       if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask)
4595         {
4596           emacs_event->modifiers |= parse_solitary_modifier
4597             (ns_command_modifier);
4599           /* if super (default), take input manager's word so things like
4600              dvorak / qwerty layout work */
4601           if (EQ (ns_command_modifier, Qsuper)
4602               && !fnKeysym
4603               && [[theEvent characters] length] != 0)
4604             {
4605               /* XXX: the code we get will be unshifted, so if we have
4606                  a shift modifier, must convert ourselves */
4607               if (!(flags & NSShiftKeyMask))
4608                 code = [[theEvent characters] characterAtIndex: 0];
4609 #if 0
4610               /* this is ugly and also requires linking w/Carbon framework
4611                  (for LMGetKbdType) so for now leave this rare (?) case
4612                  undealt with.. in future look into CGEvent methods */
4613               else
4614                 {
4615                   long smv = GetScriptManagerVariable (smKeyScript);
4616                   Handle uchrHandle = GetResource
4617                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4618                   UInt32 dummy = 0;
4619                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4620                                  [[theEvent characters] characterAtIndex: 0],
4621                                  kUCKeyActionDisplay,
4622                                  (flags & ~NSCommandKeyMask) >> 8,
4623                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4624                                  &dummy, 1, &dummy, &code);
4625                   code &= 0xFF;
4626                 }
4627 #endif
4628             }
4629         }
4631       if ((flags & NSRightControlKeyMask) == NSRightControlKeyMask)
4632           emacs_event->modifiers |= parse_solitary_modifier
4633               (EQ (ns_right_control_modifier, Qleft)
4634                ? ns_control_modifier
4635                : ns_right_control_modifier);
4637       if ((flags & NSLeftControlKeyMask) == NSLeftControlKeyMask)
4638         emacs_event->modifiers |= parse_solitary_modifier
4639           (ns_control_modifier);
4641       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4642           emacs_event->modifiers |=
4643             parse_solitary_modifier (ns_function_modifier);
4645       left_is_none = NILP (ns_alternate_modifier)
4646         || EQ (ns_alternate_modifier, Qnone);
4648       if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask)
4649         {
4650           if ((NILP (ns_right_alternate_modifier)
4651                || EQ (ns_right_alternate_modifier, Qnone)
4652                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4653               && !fnKeysym)
4654             {   /* accept pre-interp alt comb */
4655               if ([[theEvent characters] length] > 0)
4656                 code = [[theEvent characters] characterAtIndex: 0];
4657               /*HACK: clear lone shift modifier to stop next if from firing */
4658               if (emacs_event->modifiers == shift_modifier)
4659                 emacs_event->modifiers = 0;
4660             }
4661           else
4662             emacs_event->modifiers |= parse_solitary_modifier
4663               (EQ (ns_right_alternate_modifier, Qleft)
4664                ? ns_alternate_modifier
4665                : ns_right_alternate_modifier);
4666         }
4668       if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask) /* default = meta */
4669         {
4670           if (left_is_none && !fnKeysym)
4671             {   /* accept pre-interp alt comb */
4672               if ([[theEvent characters] length] > 0)
4673                 code = [[theEvent characters] characterAtIndex: 0];
4674               /*HACK: clear lone shift modifier to stop next if from firing */
4675               if (emacs_event->modifiers == shift_modifier)
4676                 emacs_event->modifiers = 0;
4677             }
4678           else
4679               emacs_event->modifiers |=
4680                 parse_solitary_modifier (ns_alternate_modifier);
4681         }
4683   if (NS_KEYLOG)
4684     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4685              code, fnKeysym, flags, emacs_event->modifiers);
4687       /* if it was a function key or had modifiers, pass it directly to emacs */
4688       if (fnKeysym || (emacs_event->modifiers
4689                        && (emacs_event->modifiers != shift_modifier)
4690                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4691 /*[[theEvent characters] length] */
4692         {
4693           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4694           if (code < 0x20)
4695             code |= (1<<28)|(3<<16);
4696           else if (code == 0x7f)
4697             code |= (1<<28)|(3<<16);
4698           else if (!fnKeysym)
4699             emacs_event->kind = code > 0xFF
4700               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4702           emacs_event->code = code;
4703           EV_TRAILER (theEvent);
4704           return;
4705         }
4706     }
4708   
4709 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4710   /* if we get here we should send the key for input manager processing */
4711   if (firstTime && [[NSInputManager currentInputManager]
4712                      wantsToDelayTextChangeNotifications] == NO)
4713     fprintf (stderr,
4714           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4715   firstTime = NO;
4716 #endif
4717   if (NS_KEYLOG && !processingCompose)
4718     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4720   processingCompose = YES;
4721   [nsEvArray addObject: theEvent];
4722   [self interpretKeyEvents: nsEvArray];
4723   [nsEvArray removeObject: theEvent];
4727 #ifdef NS_IMPL_COCOA
4728 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4729    decided not to send key-down for.
4730    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4731    This only applies on Tiger and earlier.
4732    If it matches one of these, send it on to keyDown. */
4733 -(void)keyUp: (NSEvent *)theEvent
4735   int flags = [theEvent modifierFlags];
4736   int code = [theEvent keyCode];
4737   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
4738       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4739     {
4740       if (NS_KEYLOG)
4741         fprintf (stderr, "keyUp: passed test");
4742       ns_fake_keydown = YES;
4743       [self keyDown: theEvent];
4744     }
4746 #endif
4749 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4752 /* <NSTextInput>: called when done composing;
4753    NOTE: also called when we delete over working text, followed immed.
4754          by doCommandBySelector: deleteBackward: */
4755 - (void)insertText: (id)aString
4757   int code;
4758   int len = [(NSString *)aString length];
4759   int i;
4761   if (NS_KEYLOG)
4762     NSLog (@"insertText '%@'\tlen = %d", aString, len);
4763   processingCompose = NO;
4765   if (!emacs_event)
4766     return;
4768   /* first, clear any working text */
4769   if (workingText != nil)
4770     [self deleteWorkingText];
4772   /* now insert the string as keystrokes */
4773   for (i =0; i<len; i++)
4774     {
4775       code = [aString characterAtIndex: i];
4776       /* TODO: still need this? */
4777       if (code == 0x2DC)
4778         code = '~'; /* 0x7E */
4779       emacs_event->modifiers = 0;
4780       emacs_event->kind
4781         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4782       emacs_event->code = code;
4783       EV_TRAILER ((id)nil);
4784     }
4788 /* <NSTextInput>: inserts display of composing characters */
4789 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
4791   NSString *str = [aString respondsToSelector: @selector (string)] ?
4792     [aString string] : aString;
4793   if (NS_KEYLOG)
4794     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
4795            selRange.length, selRange.location);
4797   if (workingText != nil)
4798     [self deleteWorkingText];
4799   if ([str length] == 0)
4800     return;
4802   if (!emacs_event)
4803     return;
4805   processingCompose = YES;
4806   workingText = [str copy];
4807   ns_working_text = build_string ([workingText UTF8String]);
4809   emacs_event->kind = NS_TEXT_EVENT;
4810   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
4811   EV_TRAILER ((id)nil);
4815 /* delete display of composing characters [not in <NSTextInput>] */
4816 - (void)deleteWorkingText
4818   if (workingText == nil)
4819     return;
4820   if (NS_KEYLOG)
4821     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
4822   [workingText release];
4823   workingText = nil;
4824   processingCompose = NO;
4826   if (!emacs_event)
4827     return;
4829   emacs_event->kind = NS_TEXT_EVENT;
4830   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
4831   EV_TRAILER ((id)nil);
4835 - (BOOL)hasMarkedText
4837   return workingText != nil;
4841 - (NSRange)markedRange
4843   NSRange rng = workingText != nil
4844     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
4845   if (NS_KEYLOG)
4846     NSLog (@"markedRange request");
4847   return rng;
4851 - (void)unmarkText
4853   if (NS_KEYLOG)
4854     NSLog (@"unmark (accept) text");
4855   [self deleteWorkingText];
4856   processingCompose = NO;
4860 /* used to position char selection windows, etc. */
4861 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
4863   NSRect rect;
4864   NSPoint pt;
4865   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
4866   if (NS_KEYLOG)
4867     NSLog (@"firstRectForCharRange request");
4869   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
4870   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
4871   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
4872   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
4873                                        +FRAME_LINE_HEIGHT (emacsframe));
4875   pt = [self convertPoint: pt toView: nil];
4876   pt = [[self window] convertBaseToScreen: pt];
4877   rect.origin = pt;
4878   return rect;
4882 - (long)conversationIdentifier
4884   return (long)self;
4888 - (void)doCommandBySelector: (SEL)aSelector
4890   if (NS_KEYLOG)
4891     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
4893   if (aSelector == @selector (deleteBackward:))
4894     {
4895       /* happens when user backspaces over an ongoing composition:
4896          throw a 'delete' into the event queue */
4897       if (!emacs_event)
4898         return;
4899       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4900       emacs_event->code = 0xFF08;
4901       EV_TRAILER ((id)nil);
4902     }
4905 - (NSArray *)validAttributesForMarkedText
4907   static NSArray *arr = nil;
4908   if (arr == nil) arr = [NSArray new];
4909  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
4910   return arr;
4913 - (NSRange)selectedRange
4915   if (NS_KEYLOG)
4916     NSLog (@"selectedRange request");
4917   return NSMakeRange (NSNotFound, 0);
4920 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
4922   if (NS_KEYLOG)
4923     NSLog (@"characterIndexForPoint request");
4924   return 0;
4927 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
4929   static NSAttributedString *str = nil;
4930   if (str == nil) str = [NSAttributedString new];
4931   if (NS_KEYLOG)
4932     NSLog (@"attributedSubstringFromRange request");
4933   return str;
4936 /* End <NSTextInput> impl. */
4937 /*****************************************************************************/
4940 /* This is what happens when the user presses a mouse button.  */
4941 - (void)mouseDown: (NSEvent *)theEvent
4943   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
4944   Lisp_Object window;
4946   NSTRACE (mouseDown);
4948   [self deleteWorkingText];
4950   if (!emacs_event)
4951     return;
4953   last_mouse_frame = emacsframe;
4954   /* appears to be needed to prevent spurious movement events generated on
4955      button clicks */
4956   last_mouse_frame->mouse_moved = 0;
4958   if ([theEvent type] == NSScrollWheel)
4959     {
4960       float delta = [theEvent deltaY];
4961       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
4962       if (delta == 0)
4963         return;
4964       emacs_event->kind = WHEEL_EVENT;
4965       emacs_event->code = 0;
4966       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
4967         ((delta > 0) ? up_modifier : down_modifier);
4968     }
4969   else
4970     {
4971       emacs_event->kind = MOUSE_CLICK_EVENT;
4972       emacs_event->code = EV_BUTTON (theEvent);
4973       emacs_event->modifiers = EV_MODIFIERS (theEvent)
4974                              | EV_UDMODIFIERS (theEvent);
4975     }
4976   XSETINT (emacs_event->x, lrint (p.x));
4977   XSETINT (emacs_event->y, lrint (p.y));
4978   EV_TRAILER (theEvent);
4982 - (void)rightMouseDown: (NSEvent *)theEvent
4984   NSTRACE (rightMouseDown);
4985   [self mouseDown: theEvent];
4989 - (void)otherMouseDown: (NSEvent *)theEvent
4991   NSTRACE (otherMouseDown);
4992   [self mouseDown: theEvent];
4996 - (void)mouseUp: (NSEvent *)theEvent
4998   NSTRACE (mouseUp);
4999   [self mouseDown: theEvent];
5003 - (void)rightMouseUp: (NSEvent *)theEvent
5005   NSTRACE (rightMouseUp);
5006   [self mouseDown: theEvent];
5010 - (void)otherMouseUp: (NSEvent *)theEvent
5012   NSTRACE (otherMouseUp);
5013   [self mouseDown: theEvent];
5017 - (void) scrollWheel: (NSEvent *)theEvent
5019   NSTRACE (scrollWheel);
5020   [self mouseDown: theEvent];
5024 /* Tell emacs the mouse has moved. */
5025 - (void)mouseMoved: (NSEvent *)e
5027   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5028   Lisp_Object frame;
5030 //  NSTRACE (mouseMoved);
5032   last_mouse_movement_time = EV_TIMESTAMP (e);
5033   last_mouse_motion_position
5034     = [self convertPoint: [e locationInWindow] fromView: nil];
5036   /* update any mouse face */
5037   if (hlinfo->mouse_face_hidden)
5038     {
5039       hlinfo->mouse_face_hidden = 0;
5040       clear_mouse_face (hlinfo);
5041     }
5043   /* tooltip handling */
5044   previous_help_echo_string = help_echo_string;
5045   help_echo_string = Qnil;
5047   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5048                             last_mouse_motion_position.y))
5049     help_echo_string = previous_help_echo_string;
5051   XSETFRAME (frame, emacsframe);
5052   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5053     {
5054       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5055          (note_mouse_highlight), which is called through the
5056          note_mouse_movement () call above */
5057       gen_help_event (help_echo_string, frame, help_echo_window,
5058                       help_echo_object, help_echo_pos);
5059     }
5060   else
5061     {
5062       help_echo_string = Qnil;
5063       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5064     }
5066   if (emacsframe->mouse_moved && send_appdefined)
5067     ns_send_appdefined (-1);
5071 - (void)mouseDragged: (NSEvent *)e
5073   NSTRACE (mouseDragged);
5074   [self mouseMoved: e];
5078 - (void)rightMouseDragged: (NSEvent *)e
5080   NSTRACE (rightMouseDragged);
5081   [self mouseMoved: e];
5085 - (void)otherMouseDragged: (NSEvent *)e
5087   NSTRACE (otherMouseDragged);
5088   [self mouseMoved: e];
5092 - (BOOL)windowShouldClose: (id)sender
5094   NSEvent *e =[[self window] currentEvent];
5096   NSTRACE (windowShouldClose);
5097   windowClosing = YES;
5098   if (!emacs_event)
5099     return NO;
5100   emacs_event->kind = DELETE_WINDOW_EVENT;
5101   emacs_event->modifiers = 0;
5102   emacs_event->code = 0;
5103   EV_TRAILER (e);
5104   /* Don't close this window, let this be done from lisp code.  */
5105   return NO;
5109 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5110 /* normalize frame to gridded text size */
5112   NSTRACE (windowWillResize);
5113 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5115   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5116 #ifdef NS_IMPL_GNUSTEP
5117                                         frameSize.width + 3);
5118 #else
5119                                         frameSize.width);
5120 #endif
5121   if (cols < MINWIDTH)
5122     cols = MINWIDTH;
5124   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
5125 #ifdef NS_IMPL_GNUSTEP
5126       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
5127         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5128 #else
5129       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5130         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5131 #endif
5132   if (rows < MINHEIGHT)
5133     rows = MINHEIGHT;
5134 #ifdef NS_IMPL_COCOA
5135   {
5136     /* this sets window title to have size in it; the wm does this under GS */
5137     NSRect r = [[self window] frame];
5138     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5139       {
5140         if (old_title != 0)
5141           {
5142             xfree (old_title);
5143             old_title = 0;
5144           }
5145       }
5146     else
5147       {
5148         char *size_title;
5149         NSWindow *window = [self window];
5150         if (old_title == 0)
5151           {
5152             const char *t = [[[self window] title] UTF8String];
5153             char *pos = strstr (t, "  â€”  ");
5154             if (pos)
5155               *pos = '\0';
5156             old_title = (char *) xmalloc (strlen (t) + 1);
5157             strcpy (old_title, t);
5158           }
5159         size_title = xmalloc (strlen (old_title) + 40);
5160         sprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5161         [window setTitle: [NSString stringWithUTF8String: size_title]];
5162         [window display];
5163         xfree (size_title);
5164       }
5165   }
5166 #endif /* NS_IMPL_COCOA */
5167 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5169   return frameSize;
5173 - (void)windowDidResize: (NSNotification *)notification
5175   NSWindow *theWindow = [notification object];
5177 #ifdef NS_IMPL_GNUSTEP
5178    /* in GNUstep, at least currently, it's possible to get a didResize
5179       without getting a willResize.. therefore we need to act as if we got
5180       the willResize now */
5181   NSSize sz = [theWindow frame].size;
5182   sz = [self windowWillResize: theWindow toSize: sz];
5183 #endif /* NS_IMPL_GNUSTEP */
5185   NSTRACE (windowDidResize);
5186 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5188 #ifdef NS_IMPL_COCOA
5189   if (old_title != 0)
5190     {
5191       xfree (old_title);
5192       old_title = 0;
5193     }
5194 #endif /* NS_IMPL_COCOA */
5196   /* Avoid loop under GNUstep due to call at beginning of this function.
5197      (x_set_window_size causes a resize which causes
5198      a "windowDidResize" which calls x_set_window_size).  */
5199 #ifndef NS_IMPL_GNUSTEP
5200   if (cols > 0 && rows > 0)
5201     x_set_window_size (emacsframe, 0, cols, rows);
5202 #endif
5204   ns_send_appdefined (-1);
5208 - (void)windowDidBecomeKey: (NSNotification *)notification
5209 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5211   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5212   struct frame *old_focus = dpyinfo->x_focus_frame;
5214   NSTRACE (windowDidBecomeKey);
5216   if (emacsframe != old_focus)
5217     dpyinfo->x_focus_frame = emacsframe;
5219   ns_frame_rehighlight (emacsframe);
5221   if (emacs_event)
5222     {
5223       emacs_event->kind = FOCUS_IN_EVENT;
5224       EV_TRAILER ((id)nil);
5225     }
5229 - (void)windowDidResignKey: (NSNotification *)notification
5230 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5232   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5233   NSTRACE (windowDidResignKey);
5235   if (dpyinfo->x_focus_frame == emacsframe)
5236     dpyinfo->x_focus_frame = 0;
5238   ns_frame_rehighlight (emacsframe);
5240   /* FIXME: for some reason needed on second and subsequent clicks away
5241             from sole-frame Emacs to get hollow box to show */
5242   if (!windowClosing && [[self window] isVisible] == YES)
5243     {
5244       x_update_cursor (emacsframe, 1);
5245       x_set_frame_alpha (emacsframe);
5246     }
5248   if (emacs_event)
5249     {
5250       [self deleteWorkingText];
5251       emacs_event->kind = FOCUS_IN_EVENT;
5252       EV_TRAILER ((id)nil);
5253     }
5257 - (void)windowWillMiniaturize: sender
5259   NSTRACE (windowWillMiniaturize);
5263 - (BOOL)isFlipped
5265   return YES;
5269 - (BOOL)isOpaque
5271   return NO;
5275 - initFrameFromEmacs: (struct frame *)f
5277   NSRect r, wr;
5278   Lisp_Object tem;
5279   NSWindow *win;
5280   NSButton *toggleButton;
5281   int vbextra = NS_SCROLL_BAR_WIDTH (f);
5282   NSSize sz;
5283   NSColor *col;
5284   NSString *name;
5286   NSTRACE (initFrameFromEmacs);
5288   windowClosing = NO;
5289   processingCompose = NO;
5290   scrollbarsNeedingUpdate = 0;
5292 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5294   ns_userRect = NSMakeRect (0, 0, 0, 0);
5295   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5296                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5297   [self initWithFrame: r];
5298   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5300   FRAME_NS_VIEW (f) = self;
5301   emacsframe = f;
5302   old_title = 0;
5304   win = [[EmacsWindow alloc]
5305             initWithContentRect: r
5306                       styleMask: (NSResizableWindowMask |
5307                                   NSMiniaturizableWindowMask |
5308                                   NSClosableWindowMask)
5309                         backing: NSBackingStoreBuffered
5310                           defer: YES];
5312   wr = [win frame];
5313   f->border_width = wr.size.width - r.size.width;
5314   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5316   [win setAcceptsMouseMovedEvents: YES];
5317   [win setDelegate: self];
5318   [win useOptimizedDrawing: YES];
5320   sz.width = FRAME_COLUMN_WIDTH (f);
5321   sz.height = FRAME_LINE_HEIGHT (f);
5322   [win setResizeIncrements: sz];
5324   [[win contentView] addSubview: self];
5326   if (ns_drag_types)
5327     [self registerForDraggedTypes: ns_drag_types];
5329   tem = f->name;
5330   name = [NSString stringWithUTF8String:
5331                    NILP (tem) ? (unsigned char *)"Emacs" : SDATA (tem)];
5332   [win setTitle: name];
5334   /* toolbar support */
5335   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5336                          [NSString stringWithFormat: @"Emacs Frame %d",
5337                                    ns_window_num]];
5338   [win setToolbar: toolbar];
5339   [toolbar setVisible: NO];
5340 #ifdef NS_IMPL_COCOA
5341   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5342   [toggleButton setTarget: self];
5343   [toggleButton setAction: @selector (toggleToolbar: )];
5344 #endif
5345   FRAME_TOOLBAR_HEIGHT (f) = 0;
5347   tem = f->icon_name;
5348   if (!NILP (tem))
5349     [win setMiniwindowTitle:
5350            [NSString stringWithUTF8String: SDATA (tem)]];
5352   {
5353     NSScreen *screen = [win screen];
5355     if (screen != 0)
5356       [win setFrameTopLeftPoint: NSMakePoint
5357            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5358             IN_BOUND (-SCREENMAX,
5359                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5360   }
5362   [win makeFirstResponder: self];
5364   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5365                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5366   [win setBackgroundColor: col];
5367   if ([col alphaComponent] != 1.0)
5368     [win setOpaque: NO];
5370   [self allocateGState];
5372   [NSApp registerServicesMenuSendTypes: ns_send_types
5373                            returnTypes: nil];
5375   ns_window_num++;
5376   return self;
5380 - (void)windowDidMove: sender
5382   NSWindow *win = [self window];
5383   NSRect r = [win frame];
5384   NSArray *screens = [NSScreen screens];
5385   NSScreen *screen = [screens objectAtIndex: 0];
5387   NSTRACE (windowDidMove);
5389   if (!emacsframe->output_data.ns)
5390     return;
5391   if (screen != nil)
5392     {
5393       emacsframe->left_pos = r.origin.x;
5394       emacsframe->top_pos =
5395         [screen frame].size.height - (r.origin.y + r.size.height);
5396     }
5400 /* Called AFTER method below, but before our windowWillResize call there leads
5401    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5402    location so set_window_size moves the frame. */
5403 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5405   emacsframe->output_data.ns->zooming = 1;
5406   return YES;
5410 /* Override to do something slightly nonstandard, but nice.  First click on
5411    zoom button will zoom vertically.  Second will zoom completely.  Third
5412    returns to original. */
5413 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5414                         defaultFrame:(NSRect)defaultFrame
5416   NSRect result = [sender frame];
5418   NSTRACE (windowWillUseStandardFrame);
5420   if (abs (defaultFrame.size.height - result.size.height)
5421       > FRAME_LINE_HEIGHT (emacsframe))
5422     {
5423       /* first click */
5424       ns_userRect = result;
5425       result.size.height = defaultFrame.size.height;
5426       result.origin.y = defaultFrame.origin.y;
5427     }
5428   else
5429     {
5430       if (abs (defaultFrame.size.width - result.size.width)
5431           > FRAME_COLUMN_WIDTH (emacsframe))
5432         result = defaultFrame;  /* second click */
5433       else
5434         {
5435           /* restore */
5436           result = ns_userRect.size.height ? ns_userRect : result;
5437           ns_userRect = NSMakeRect (0, 0, 0, 0);
5438         }
5439     }
5441   [self windowWillResize: sender toSize: result.size];
5442   return result;
5446 - (void)windowDidDeminiaturize: sender
5448   NSTRACE (windowDidDeminiaturize);
5449   if (!emacsframe->output_data.ns)
5450     return;
5451   emacsframe->async_iconified = 0;
5452   emacsframe->async_visible   = 1;
5453   windows_or_buffers_changed++;
5455   if (emacs_event)
5456     {
5457       emacs_event->kind = ICONIFY_EVENT;
5458       EV_TRAILER ((id)nil);
5459     }
5463 - (void)windowDidExpose: sender
5465   NSTRACE (windowDidExpose);
5466   if (!emacsframe->output_data.ns)
5467     return;
5468   emacsframe->async_visible = 1;
5469   SET_FRAME_GARBAGED (emacsframe);
5471   if (send_appdefined)
5472     ns_send_appdefined (-1);
5476 - (void)windowDidMiniaturize: sender
5478   NSTRACE (windowDidMiniaturize);
5479   if (!emacsframe->output_data.ns)
5480     return;
5482   emacsframe->async_iconified = 1;
5483   emacsframe->async_visible = 0;
5485   if (emacs_event)
5486     {
5487       emacs_event->kind = ICONIFY_EVENT;
5488       EV_TRAILER ((id)nil);
5489     }
5493 - (void)mouseEntered: (NSEvent *)theEvent
5495   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5496   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5497   NSTRACE (mouseEntered);
5499   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5503 - (void)mouseExited: (NSEvent *)theEvent
5505   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5506   NSRect r;
5507   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
5509   NSTRACE (mouseExited);
5511   if (!hlinfo)
5512     return;
5514   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5516   if (emacsframe == hlinfo->mouse_face_mouse_frame)
5517     {
5518       clear_mouse_face (hlinfo);
5519       hlinfo->mouse_face_mouse_frame = 0;
5520     }
5524 - menuDown: sender
5526   NSTRACE (menuDown);
5527   if (context_menu_value == -1)
5528     context_menu_value = [sender tag];
5529   else
5530     find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5531                                   emacsframe->menu_bar_vector,
5532                                   (void *)[sender tag]);
5533   ns_send_appdefined (-1);
5534   return self;
5538 - (EmacsToolbar *)toolbar
5540   return toolbar;
5544 /* this gets called on toolbar button click */
5545 - toolbarClicked: (id)item
5547   NSEvent *theEvent;
5548   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5550   NSTRACE (toolbarClicked);
5552   if (!emacs_event)
5553     return self;
5555   /* send first event (for some reason two needed) */
5556   theEvent = [[self window] currentEvent];
5557   emacs_event->kind = TOOL_BAR_EVENT;
5558   XSETFRAME (emacs_event->arg, emacsframe);
5559   EV_TRAILER (theEvent);
5561   emacs_event->kind = TOOL_BAR_EVENT;
5562 /*   XSETINT (emacs_event->code, 0); */
5563   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5564                           idx + TOOL_BAR_ITEM_KEY);
5565   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5566   EV_TRAILER (theEvent);
5567   return self;
5571 - toggleToolbar: (id)sender
5573   if (!emacs_event)
5574     return self;
5576   emacs_event->kind = NS_NONKEY_EVENT;
5577   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
5578   EV_TRAILER ((id)nil);
5579   return self;
5583 - (void)drawRect: (NSRect)rect
5585   int x = NSMinX (rect), y = NSMinY (rect);
5586   int width = NSWidth (rect), height = NSHeight (rect);
5588   NSTRACE (drawRect);
5590   if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
5591     return;
5593   ns_clear_frame_area (emacsframe, x, y, width, height);
5594   expose_frame (emacsframe, x, y, width, height);
5596   /*
5597     drawRect: may be called (at least in OS X 10.5) for invisible
5598     views as well for some reason.  Thus, do not infer visibility
5599     here.
5601     emacsframe->async_visible = 1;
5602     emacsframe->async_iconified = 0;
5603   */
5607 /* NSDraggingDestination protocol methods.  Actually this is not really a
5608    protocol, but a category of Object.  O well...  */
5610 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
5612   NSTRACE (draggingEntered);
5613   return NSDragOperationGeneric;
5617 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5619   return YES;
5623 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5625   id pb;
5626   int x, y;
5627   NSString *type;
5628   NSEvent *theEvent = [[self window] currentEvent];
5629   NSPoint position;
5631   NSTRACE (performDragOperation);
5633   if (!emacs_event)
5634     return NO;
5636   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5637   x = lrint (position.x);  y = lrint (position.y);
5639   pb = [sender draggingPasteboard];
5640   type = [pb availableTypeFromArray: ns_drag_types];
5641   if (type == 0)
5642     {
5643       return NO;
5644     }
5645   else if ([type isEqualToString: NSFilenamesPboardType])
5646     {
5647       NSArray *files;
5648       NSEnumerator *fenum;
5649       NSString *file;
5651       if (!(files = [pb propertyListForType: type]))
5652         return NO;
5654       fenum = [files objectEnumerator];
5655       while ( (file = [fenum nextObject]) )
5656         {
5657           emacs_event->kind = NS_NONKEY_EVENT;
5658           emacs_event->code = KEY_NS_DRAG_FILE;
5659           XSETINT (emacs_event->x, x);
5660           XSETINT (emacs_event->y, y);
5661           ns_input_file = append2 (ns_input_file,
5662                                    build_string ([file UTF8String]));
5663           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5664           EV_TRAILER (theEvent);
5665         }
5666       return YES;
5667     }
5668   else if ([type isEqualToString: NSURLPboardType])
5669     {
5670       NSString *file;
5671       NSURL *fileURL;
5673       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5674           [fileURL isFileURL] == NO)
5675         return NO;
5677       file = [fileURL path];
5678       emacs_event->kind = NS_NONKEY_EVENT;
5679       emacs_event->code = KEY_NS_DRAG_FILE;
5680       XSETINT (emacs_event->x, x);
5681       XSETINT (emacs_event->y, y);
5682       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5683       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5684       EV_TRAILER (theEvent);
5685       return YES;
5686     }
5687   else if ([type isEqualToString: NSStringPboardType]
5688            || [type isEqualToString: NSTabularTextPboardType])
5689     {
5690       NSString *data;
5692       if (! (data = [pb stringForType: type]))
5693         return NO;
5695       emacs_event->kind = NS_NONKEY_EVENT;
5696       emacs_event->code = KEY_NS_DRAG_TEXT;
5697       XSETINT (emacs_event->x, x);
5698       XSETINT (emacs_event->y, y);
5699       ns_input_text = build_string ([data UTF8String]);
5700       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5701       EV_TRAILER (theEvent);
5702       return YES;
5703     }
5704   else if ([type isEqualToString: NSColorPboardType])
5705     {
5706       NSColor *c = [NSColor colorFromPasteboard: pb];
5707       emacs_event->kind = NS_NONKEY_EVENT;
5708       emacs_event->code = KEY_NS_DRAG_COLOR;
5709       XSETINT (emacs_event->x, x);
5710       XSETINT (emacs_event->y, y);
5711       ns_input_color = ns_color_to_lisp (c);
5712       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5713       EV_TRAILER (theEvent);
5714       return YES;
5715     }
5716   else if ([type isEqualToString: NSFontPboardType])
5717     {
5718       /* impl based on GNUstep NSTextView.m */
5719       NSData *data = [pb dataForType: NSFontPboardType];
5720       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5721       NSFont *font = [dict objectForKey: NSFontAttributeName];
5722       char fontSize[10];
5724       if (font == nil)
5725         return NO;
5727       emacs_event->kind = NS_NONKEY_EVENT;
5728       emacs_event->code = KEY_NS_CHANGE_FONT;
5729       XSETINT (emacs_event->x, x);
5730       XSETINT (emacs_event->y, y);
5731       ns_input_font = build_string ([[font fontName] UTF8String]);
5732       snprintf (fontSize, 10, "%f", [font pointSize]);
5733       ns_input_fontsize = build_string (fontSize);
5734       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5735       EV_TRAILER (theEvent);
5736       return YES;
5737     }
5738   else
5739     {
5740       error ("Invalid data type in dragging pasteboard.");
5741       return NO;
5742     }
5746 - (id) validRequestorForSendType: (NSString *)typeSent
5747                       returnType: (NSString *)typeReturned
5749   NSTRACE (validRequestorForSendType);
5750   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
5751       && typeReturned == nil)
5752     {
5753       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
5754         return self;
5755     }
5757   return [super validRequestorForSendType: typeSent
5758                                returnType: typeReturned];
5762 /* The next two methods are part of NSServicesRequests informal protocol,
5763    supposedly called when a services menu item is chosen from this app.
5764    But this should not happen because we override the services menu with our
5765    own entries which call ns-perform-service.
5766    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
5767    So let's at least stub them out until further investigation can be done. */
5769 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
5771   /* we could call ns_string_from_pasteboard(pboard) here but then it should
5772      be written into the buffer in place of the existing selection..
5773      ordinary service calls go through functions defined in ns-win.el */
5774   return NO;
5777 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
5779   NSArray *typesDeclared;
5780   Lisp_Object val;
5782   /* We only support NSStringPboardType */
5783   if ([types containsObject:NSStringPboardType] == NO) {
5784     return NO;
5785   }
5787   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
5788   if (CONSP (val) && SYMBOLP (XCAR (val)))
5789     {
5790       val = XCDR (val);
5791       if (CONSP (val) && NILP (XCDR (val)))
5792         val = XCAR (val);
5793     }
5794   if (! STRINGP (val))
5795     return NO;
5797   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
5798   [pb declareTypes:typesDeclared owner:nil];
5799   ns_string_to_pasteboard (pb, val);
5800   return YES;
5804 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
5805    (gives a miniaturized version of the window); currently we use the latter for
5806    frames whose active buffer doesn't correspond to any file
5807    (e.g., '*scratch*') */
5808 - setMiniwindowImage: (BOOL) setMini
5810   id image = [[self window] miniwindowImage];
5811   NSTRACE (setMiniwindowImage);
5813   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
5814      about "AppleDockIconEnabled" notwithstanding, however the set message
5815      below has its effect nonetheless. */
5816   if (image != emacsframe->output_data.ns->miniimage)
5817     {
5818       if (image && [image isKindOfClass: [EmacsImage class]])
5819         [image release];
5820       [[self window] setMiniwindowImage:
5821                        setMini ? emacsframe->output_data.ns->miniimage : nil];
5822     }
5824   return self;
5828 - (void) setRows: (int) r andColumns: (int) c
5830   rows = r;
5831   cols = c;
5834 @end  /* EmacsView */
5838 /* ==========================================================================
5840     EmacsWindow implementation
5842    ========================================================================== */
5844 @implementation EmacsWindow
5846 /* If we have multiple monitors, one above the other, we don't want to
5847    restrict the height to just one monitor.  So we override this.  */
5848 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
5850   /* When making the frame visible for the first time, we want to
5851      constrain.  Other times not.  */
5852   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
5853   NSTRACE (constrainFrameRect);
5855   if (f->output_data.ns->dont_constrain
5856       || ns_menu_bar_should_be_hidden ())
5857     return frameRect;
5859   f->output_data.ns->dont_constrain = 1;
5860   return [super constrainFrameRect:frameRect toScreen:screen];
5864 /* called only on resize clicks by special case in EmacsApp-sendEvent */
5865 - (void)mouseDown: (NSEvent *)theEvent
5867   if (ns_in_resize)
5868     {
5869       NSSize size = [[theEvent window] frame].size;
5870       grabOffset = [theEvent locationInWindow];
5871       grabOffset.x = size.width - grabOffset.x;
5872     }
5873   else
5874     [super mouseDown: theEvent];
5878 /* stop resizing */
5879 - (void)mouseUp: (NSEvent *)theEvent
5881   if (ns_in_resize)
5882     {
5883       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
5884       ns_in_resize = NO;
5885       ns_set_name_as_filename (f);
5886       [self display];
5887       ns_send_appdefined (-1);
5888     }
5889   else
5890     [super mouseUp: theEvent];
5894 /* send resize events */
5895 - (void)mouseDragged: (NSEvent *)theEvent
5897   if (ns_in_resize)
5898     {
5899       NSPoint p = [theEvent locationInWindow];
5900       NSSize size, vettedSize, origSize = [self frame].size;
5902       size.width = p.x + grabOffset.x;
5903       size.height = origSize.height - p.y + grabOffset.y;
5905       if (size.width == origSize.width && size.height == origSize.height)
5906         return;
5908       vettedSize = [[self delegate] windowWillResize: self toSize: size];
5909       [[NSNotificationCenter defaultCenter]
5910             postNotificationName: NSWindowDidResizeNotification
5911                           object: self];
5912     }
5913   else
5914     [super mouseDragged: theEvent];
5917 @end /* EmacsWindow */
5920 /* ==========================================================================
5922     EmacsScroller implementation
5924    ========================================================================== */
5927 @implementation EmacsScroller
5929 /* for repeat button push */
5930 #define SCROLL_BAR_FIRST_DELAY 0.5
5931 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
5933 + (CGFloat) scrollerWidth
5935   /* TODO: if we want to allow variable widths, this is the place to do it,
5936            however neither GNUstep nor Cocoa support it very well */
5937   return [NSScroller scrollerWidth];
5941 - initFrame: (NSRect )r window: (Lisp_Object)nwin
5943   NSTRACE (EmacsScroller_initFrame);
5945   r.size.width = [EmacsScroller scrollerWidth];
5946   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
5947   [self setContinuous: YES];
5948   [self setEnabled: YES];
5950   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
5951      locked against the top and bottom edges, and right edge on OS X, where
5952      scrollers are on right. */
5953 #ifdef NS_IMPL_GNUSTEP
5954   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
5955 #else
5956   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
5957 #endif
5959   win = nwin;
5960   condemned = NO;
5961   pixel_height = NSHeight (r);
5962   if (pixel_height == 0) pixel_height = 1;
5963   min_portion = 20 / pixel_height;
5965   frame = XFRAME (XWINDOW (win)->frame);
5966   if (FRAME_LIVE_P (frame))
5967     {
5968       int i;
5969       EmacsView *view = FRAME_NS_VIEW (frame);
5970       NSView *sview = [[view window] contentView];
5971       NSArray *subs = [sview subviews];
5973       /* disable optimization stopping redraw of other scrollbars */
5974       view->scrollbarsNeedingUpdate = 0;
5975       for (i =[subs count]-1; i >= 0; i--)
5976         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
5977           view->scrollbarsNeedingUpdate++;
5978       [sview addSubview: self];
5979     }
5981 /*  [self setFrame: r]; */
5983   return self;
5987 - (void)setFrame: (NSRect)newRect
5989   NSTRACE (EmacsScroller_setFrame);
5990 /*  BLOCK_INPUT; */
5991   pixel_height = NSHeight (newRect);
5992   if (pixel_height == 0) pixel_height = 1;
5993   min_portion = 20 / pixel_height;
5994   [super setFrame: newRect];
5995   [self display];
5996 /*  UNBLOCK_INPUT; */
6000 - (void)dealloc
6002   NSTRACE (EmacsScroller_dealloc);
6003   if (!NILP (win))
6004     XWINDOW (win)->vertical_scroll_bar = Qnil;
6005   [super dealloc];
6009 - condemn
6011   NSTRACE (condemn);
6012   condemned =YES;
6013   return self;
6017 - reprieve
6019   NSTRACE (reprieve);
6020   condemned =NO;
6021   return self;
6025 - judge
6027   NSTRACE (judge);
6028   if (condemned)
6029     {
6030       EmacsView *view;
6031       BLOCK_INPUT;
6032       /* ensure other scrollbar updates after deletion */
6033       view = (EmacsView *)FRAME_NS_VIEW (frame);
6034       if (view != nil)
6035         view->scrollbarsNeedingUpdate++;
6036       [self removeFromSuperview];
6037       [self release];
6038       UNBLOCK_INPUT;
6039     }
6040   return self;
6044 - (void)resetCursorRects
6046   NSRect visible = [self visibleRect];
6047   NSTRACE (resetCursorRects);
6049   if (!NSIsEmptyRect (visible))
6050     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6051   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6055 - (int) checkSamePosition: (int) position portion: (int) portion
6056                     whole: (int) whole
6058   return em_position ==position && em_portion ==portion && em_whole ==whole
6059     && portion != whole; /* needed for resize empty buf */
6063 - setPosition: (int)position portion: (int)portion whole: (int)whole
6065   NSTRACE (setPosition);
6067   em_position = position;
6068   em_portion = portion;
6069   em_whole = whole;
6071   if (portion >= whole)
6072     {
6073 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6074       [self setKnobProportion: 1.0];
6075       [self setDoubleValue: 1.0];
6076 #else
6077       [self setFloatValue: 0.0 knobProportion: 1.0];
6078 #endif
6079     }
6080   else
6081     {
6082       float pos, por;
6083       portion = max ((float)whole*min_portion/pixel_height, portion);
6084       pos = (float)position / (whole - portion);
6085       por = (float)portion/whole;
6086 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6087       [self setKnobProportion: por];
6088       [self setDoubleValue: pos];
6089 #else
6090       [self setFloatValue: pos knobProportion: por];
6091 #endif
6092     }
6093   return self;
6096 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6097      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6098 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6099                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6101   *part = last_hit_part;
6102   *window = win;
6103   XSETINT (*y, pixel_height);
6104   if ([self floatValue] > 0.999)
6105     XSETINT (*x, pixel_height);
6106   else
6107     XSETINT (*x, pixel_height * [self floatValue]);
6111 /* set up emacs_event */
6112 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6114   if (!emacs_event)
6115     return;
6117   emacs_event->part = last_hit_part;
6118   emacs_event->code = 0;
6119   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6120   emacs_event->frame_or_window = win;
6121   emacs_event->timestamp = EV_TIMESTAMP (e);
6122   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6123   emacs_event->arg = Qnil;
6124   XSETINT (emacs_event->x, loc * pixel_height);
6125   XSETINT (emacs_event->y, pixel_height-20);
6127   n_emacs_events_pending++;
6128   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6129   EVENT_INIT (*emacs_event);
6130   ns_send_appdefined (-1);
6134 /* called manually thru timer to implement repeated button action w/hold-down */
6135 - repeatScroll: (NSTimer *)scrollEntry
6137   NSEvent *e = [[self window] currentEvent];
6138   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6139   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6141   /* clear timer if need be */
6142   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6143     {
6144         [scroll_repeat_entry invalidate];
6145         [scroll_repeat_entry release];
6146         scroll_repeat_entry = nil;
6148         if (inKnob)
6149           return self;
6151         scroll_repeat_entry
6152           = [[NSTimer scheduledTimerWithTimeInterval:
6153                         SCROLL_BAR_CONTINUOUS_DELAY
6154                                             target: self
6155                                           selector: @selector (repeatScroll:)
6156                                           userInfo: 0
6157                                            repeats: YES]
6158               retain];
6159     }
6161   [self sendScrollEventAtLoc: 0 fromEvent: e];
6162   return self;
6166 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6167    mouseDragged events without going into a modal loop. */
6168 - (void)mouseDown: (NSEvent *)e
6170   NSRect sr, kr;
6171   /* hitPart is only updated AFTER event is passed on */
6172   NSScrollerPart part = [self testPart: [e locationInWindow]];
6173   double inc = 0.0, loc, kloc, pos;
6174   int edge = 0;
6176   NSTRACE (EmacsScroller_mouseDown);
6178   switch (part)
6179     {
6180     case NSScrollerDecrementPage:
6181         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6182     case NSScrollerIncrementPage:
6183         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6184     case NSScrollerDecrementLine:
6185       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6186     case NSScrollerIncrementLine:
6187       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6188     case NSScrollerKnob:
6189       last_hit_part = scroll_bar_handle; break;
6190     case NSScrollerKnobSlot:  /* GNUstep-only */
6191       last_hit_part = scroll_bar_move_ratio; break;
6192     default:  /* NSScrollerNoPart? */
6193       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6194                (long) part);
6195       return;
6196     }
6198   if (inc != 0.0)
6199     {
6200       pos = 0;      /* ignored */
6202       /* set a timer to repeat, as we can't let superclass do this modally */
6203       scroll_repeat_entry
6204         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6205                                             target: self
6206                                           selector: @selector (repeatScroll:)
6207                                           userInfo: 0
6208                                            repeats: YES]
6209             retain];
6210     }
6211   else
6212     {
6213       /* handle, or on GNUstep possibly slot */
6214       NSEvent *fake_event;
6216       /* compute float loc in slot and mouse offset on knob */
6217       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6218                       toView: nil];
6219       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6220       if (loc <= 0.0)
6221         {
6222           loc = 0.0;
6223           edge = -1;
6224         }
6225       else if (loc >= NSHeight (sr))
6226         {
6227           loc = NSHeight (sr);
6228           edge = 1;
6229         }
6231       if (edge)
6232         kloc = 0.5 * edge;
6233       else
6234         {
6235           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6236                           toView: nil];
6237           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6238         }
6239       last_mouse_offset = kloc;
6241       /* if knob, tell emacs a location offset by knob pos
6242          (to indicate top of handle) */
6243       if (part == NSScrollerKnob)
6244           pos = (loc - last_mouse_offset) / NSHeight (sr);
6245       else
6246         /* else this is a slot click on GNUstep: go straight there */
6247         pos = loc / NSHeight (sr);
6249       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6250       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6251                                       location: [e locationInWindow]
6252                                  modifierFlags: [e modifierFlags]
6253                                      timestamp: [e timestamp]
6254                                   windowNumber: [e windowNumber]
6255                                        context: [e context]
6256                                    eventNumber: [e eventNumber]
6257                                     clickCount: [e clickCount]
6258                                       pressure: [e pressure]];
6259       [super mouseUp: fake_event];
6260     }
6262   if (part != NSScrollerKnob)
6263     [self sendScrollEventAtLoc: pos fromEvent: e];
6267 /* Called as we manually track scroller drags, rather than superclass. */
6268 - (void)mouseDragged: (NSEvent *)e
6270     NSRect sr;
6271     double loc, pos;
6272     int edge = 0;
6274     NSTRACE (EmacsScroller_mouseDragged);
6276       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6277                       toView: nil];
6278       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6280       if (loc <= 0.0)
6281         {
6282           loc = 0.0;
6283           edge = -1;
6284         }
6285       else if (loc >= NSHeight (sr) + last_mouse_offset)
6286         {
6287           loc = NSHeight (sr) + last_mouse_offset;
6288           edge = 1;
6289         }
6291       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6292       [self sendScrollEventAtLoc: pos fromEvent: e];
6296 - (void)mouseUp: (NSEvent *)e
6298   if (scroll_repeat_entry)
6299     {
6300       [scroll_repeat_entry invalidate];
6301       [scroll_repeat_entry release];
6302       scroll_repeat_entry = nil;
6303     }
6304   last_hit_part = 0;
6308 /* treat scrollwheel events in the bar as though they were in the main window */
6309 - (void) scrollWheel: (NSEvent *)theEvent
6311   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6312   [view mouseDown: theEvent];
6315 @end  /* EmacsScroller */
6320 /* ==========================================================================
6322    Font-related functions; these used to be in nsfaces.m
6324    ========================================================================== */
6327 Lisp_Object
6328 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6330   struct font *font = XFONT_OBJECT (font_object);
6332   if (fontset < 0)
6333     fontset = fontset_from_font (font_object);
6334   FRAME_FONTSET (f) = fontset;
6336   if (FRAME_FONT (f) == font)
6337     /* This font is already set in frame F.  There's nothing more to
6338        do.  */
6339     return font_object;
6341   FRAME_FONT (f) = font;
6343   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6344   FRAME_COLUMN_WIDTH (f) = font->average_width;
6345   FRAME_SPACE_WIDTH (f) = font->space_width;
6346   FRAME_LINE_HEIGHT (f) = font->height;
6348   compute_fringe_widths (f, 1);
6350   /* Compute the scroll bar width in character columns.  */
6351   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6352     {
6353       int wid = FRAME_COLUMN_WIDTH (f);
6354       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6355         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6356     }
6357   else
6358     {
6359       int wid = FRAME_COLUMN_WIDTH (f);
6360       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6361     }
6363   /* Now make the frame display the given font.  */
6364   if (FRAME_NS_WINDOW (f) != 0)
6365         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6367   return font_object;
6371 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6372 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6373          in 1.43. */
6375 const char *
6376 ns_xlfd_to_fontname (const char *xlfd)
6377 /* --------------------------------------------------------------------------
6378     Convert an X font name (XLFD) to an NS font name.
6379     Only family is used.
6380     The string returned is temporarily allocated.
6381    -------------------------------------------------------------------------- */
6383   char *name = xmalloc (180);
6384   int i, len;
6385   const char *ret;
6387   if (!strncmp (xlfd, "--", 2))
6388     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6389   else
6390     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6392   /* stopgap for malformed XLFD input */
6393   if (strlen (name) == 0)
6394     strcpy (name, "Monaco");
6396   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6397      also uppercase after '-' or ' ' */
6398   name[0] = toupper (name[0]);
6399   for (len =strlen (name), i =0; i<len; i++)
6400     {
6401       if (name[i] == '$')
6402         {
6403           name[i] = '-';
6404           if (i+1<len)
6405             name[i+1] = toupper (name[i+1]);
6406         }
6407       else if (name[i] == '_')
6408         {
6409           name[i] = ' ';
6410           if (i+1<len)
6411             name[i+1] = toupper (name[i+1]);
6412         }
6413     }
6414 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6415   ret = [[NSString stringWithUTF8String: name] UTF8String];
6416   xfree (name);
6417   return ret;
6421 void
6422 syms_of_nsterm (void)
6424   NSTRACE (syms_of_nsterm);
6426   ns_antialias_threshold = 10.0;
6428   /* from 23+ we need to tell emacs what modifiers there are.. */
6429   DEFSYM (Qmodifier_value, "modifier-value");
6430   DEFSYM (Qalt, "alt");
6431   DEFSYM (Qhyper, "hyper");
6432   DEFSYM (Qmeta, "meta");
6433   DEFSYM (Qsuper, "super");
6434   DEFSYM (Qcontrol, "control");
6435   DEFSYM (Qnone, "none");
6436   DEFSYM (QUTF8_STRING, "UTF8_STRING");
6438   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6439   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6440   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6441   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6442   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6444   DEFVAR_LISP ("ns-input-file", ns_input_file,
6445               "The file specified in the last NS event.");
6446   ns_input_file =Qnil;
6448   DEFVAR_LISP ("ns-input-text", ns_input_text,
6449               "The data received in the last NS text drag event.");
6450   ns_input_text =Qnil;
6452   DEFVAR_LISP ("ns-working-text", ns_working_text,
6453               "String for visualizing working composition sequence.");
6454   ns_working_text =Qnil;
6456   DEFVAR_LISP ("ns-input-font", ns_input_font,
6457               "The font specified in the last NS event.");
6458   ns_input_font =Qnil;
6460   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
6461               "The fontsize specified in the last NS event.");
6462   ns_input_fontsize =Qnil;
6464   DEFVAR_LISP ("ns-input-line", ns_input_line,
6465                "The line specified in the last NS event.");
6466   ns_input_line =Qnil;
6468   DEFVAR_LISP ("ns-input-color", ns_input_color,
6469                "The color specified in the last NS event.");
6470   ns_input_color =Qnil;
6472   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
6473                "The service name specified in the last NS event.");
6474   ns_input_spi_name =Qnil;
6476   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
6477                "The service argument specified in the last NS event.");
6478   ns_input_spi_arg =Qnil;
6480   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
6481                "This variable describes the behavior of the alternate or option key.\n\
6482 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6483 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6484 at all, allowing it to be used at a lower level for accented character entry.");
6485   ns_alternate_modifier = Qmeta;
6487   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
6488                "This variable describes the behavior of the right alternate or option key.\n\
6489 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6490 Set to left means be the same key as `ns-alternate-modifier'.\n\
6491 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6492 at all, allowing it to be used at a lower level for accented character entry.");
6493   ns_right_alternate_modifier = Qleft;
6495   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
6496                "This variable describes the behavior of the command key.\n\
6497 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6498   ns_command_modifier = Qsuper;
6500   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
6501                "This variable describes the behavior of the right command key.\n\
6502 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6503 Set to left means be the same key as `ns-command-modifier'.\n\
6504 Set to none means that the command / option key is not interpreted by Emacs\n\
6505 at all, allowing it to be used at a lower level for accented character entry.");
6506   ns_right_command_modifier = Qleft;
6508   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
6509                "This variable describes the behavior of the control key.\n\
6510 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6511   ns_control_modifier = Qcontrol;
6513   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
6514                "This variable describes the behavior of the right control key.\n\
6515 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6516 Set to left means be the same key as `ns-control-modifier'.\n\
6517 Set to none means that the control / option key is not interpreted by Emacs\n\
6518 at all, allowing it to be used at a lower level for accented character entry.");
6519   ns_right_control_modifier = Qleft;
6521   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
6522                "This variable describes the behavior of the function key (on laptops).\n\
6523 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6524 Set to none means that the function key is not interpreted by Emacs at all,\n\
6525 allowing it to be used at a lower level for accented character entry.");
6526   ns_function_modifier = Qnone;
6528   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
6529                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6530   ns_antialias_text = Qt;
6532   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
6533                "Whether to confirm application quit using dialog.");
6534   ns_confirm_quit = Qnil;
6536   staticpro (&ns_display_name_list);
6537   ns_display_name_list = Qnil;
6539   staticpro (&last_mouse_motion_frame);
6540   last_mouse_motion_frame = Qnil;
6542   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
6543                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
6544 Only works on OSX 10.6 or later.  */);
6545   ns_auto_hide_menu_bar = Qnil;
6547   /* TODO: move to common code */
6548   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
6549                doc: /* If not nil, Emacs uses toolkit scroll bars.  */);
6550 #ifdef USE_TOOLKIT_SCROLL_BARS
6551   Vx_toolkit_scroll_bars = Qt;
6552 #else
6553   Vx_toolkit_scroll_bars = Qnil;
6554 #endif
6556   /* these are unsupported but we need the declarations to avoid whining
6557      messages from cus-start.el */
6558   DEFVAR_BOOL ("x-use-underline-position-properties",
6559                x_use_underline_position_properties,
6560      doc: /* NOT SUPPORTED UNDER NS.
6561 *Non-nil means make use of UNDERLINE_POSITION font properties.
6562 A value of nil means ignore them.  If you encounter fonts with bogus
6563 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6564 to 4.1, set this to nil.
6566 NOTE: Not supported on Mac yet.  */);
6567   x_use_underline_position_properties = 0;
6569   DEFVAR_BOOL ("x-underline-at-descent-line",
6570                x_underline_at_descent_line,
6571      doc: /* NOT SUPPORTED UNDER NS.
6572 *Non-nil means to draw the underline at the same place as the descent line.
6573 A value of nil means to draw the underline according to the value of the
6574 variable `x-use-underline-position-properties', which is usually at the
6575 baseline level.  The default value is nil.  */);
6576   x_underline_at_descent_line = 0;
6578   /* Tell emacs about this window system. */
6579   Fprovide (intern ("ns"), Qnil);