* m4/lstat.m4: Merge from gnulib (Bug#8878).
[emacs.git] / src / nsterm.m
blob52e0dc6c2a874956b8d79259b43182a8d4c86c31
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 */
138 static Lisp_Object Qmodifier_value;
139 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper, Qnone;
140 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
142 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
143    the maximum font size to NOT antialias.  On GNUstep there is currently
144    no way to control this behavior. */
145 float ns_antialias_threshold;
147 /* Used to pick up AppleHighlightColor on OS X */
148 NSString *ns_selection_color;
150 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
151 NSString *ns_app_name = @"Emacs";  /* default changed later */
153 /* Display variables */
154 struct ns_display_info *x_display_list; /* Chain of existing displays */
155 Lisp_Object ns_display_name_list;
156 long context_menu_value = 0;
158 /* display update */
159 NSPoint last_mouse_motion_position;
160 static NSRect last_mouse_glyph;
161 static Time last_mouse_movement_time = 0;
162 static Lisp_Object last_mouse_motion_frame;
163 static EmacsScroller *last_mouse_scroll_bar = nil;
164 static struct frame *ns_updating_frame;
165 static NSView *focus_view = NULL;
166 static int ns_window_num =0;
167 static NSRect uRect;
168 static BOOL gsaved = NO;
169 BOOL ns_in_resize = NO;
170 static BOOL ns_fake_keydown = NO;
171 int ns_tmp_flags; /* FIXME */
172 struct nsfont_info *ns_tmp_font; /* FIXME */
173 static BOOL ns_menu_bar_is_hidden = NO;
174 /*static int debug_lock = 0; */
176 /* event loop */
177 static BOOL send_appdefined = YES;
178 static NSEvent *last_appdefined_event = 0;
179 static NSTimer *timed_entry = 0;
180 static NSTimer *fd_entry = nil;
181 static NSTimer *scroll_repeat_entry = nil;
182 static fd_set select_readfds, t_readfds;
183 static struct timeval select_timeout;
184 static int select_nfds;
185 static NSAutoreleasePool *outerpool;
186 static struct input_event *emacs_event = NULL;
187 static struct input_event *q_event_ptr = NULL;
188 static int n_emacs_events_pending = 0;
189 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
190   *ns_pending_service_args;
191 static BOOL inNsSelect = 0;
193 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
194 #define NS_FUNCTION_KEY_MASK 0x800000
195 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
196 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
197 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
198 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
199 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
200 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
201 #define EV_MODIFIERS(e)                               \
202     ((([e modifierFlags] & NSHelpKeyMask) ?           \
203            hyper_modifier : 0)                        \
204      | (!EQ (ns_right_alternate_modifier, Qleft) && \
205         (([e modifierFlags] & NSRightAlternateKeyMask) \
206          == NSRightAlternateKeyMask) ? \
207            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
208      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
209            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
210      | (([e modifierFlags] & NSShiftKeyMask) ?     \
211            shift_modifier : 0)                        \
212      | (!EQ (ns_right_control_modifier, Qleft) && \
213         (([e modifierFlags] & NSRightControlKeyMask) \
214          == NSRightControlKeyMask) ? \
215            parse_solitary_modifier (ns_right_control_modifier) : 0) \
216      | (([e modifierFlags] & NSControlKeyMask) ?      \
217            parse_solitary_modifier (ns_control_modifier) : 0)     \
218      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
219            parse_solitary_modifier (ns_function_modifier) : 0)    \
220      | (!EQ (ns_right_command_modifier, Qleft) && \
221         (([e modifierFlags] & NSRightCommandKeyMask) \
222          == NSRightCommandKeyMask) ? \
223            parse_solitary_modifier (ns_right_command_modifier) : 0) \
224      | (([e modifierFlags] & NSCommandKeyMask) ?      \
225            parse_solitary_modifier (ns_command_modifier):0))
227 #define EV_UDMODIFIERS(e)                                      \
228     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
229      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
230      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
231      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
232      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
233      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
234      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
235      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
236      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
238 #define EV_BUTTON(e)                                                         \
239     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
240       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
241      [e buttonNumber] - 1)
243 /* Convert the time field to a timestamp in milliseconds. */
244 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
246 /* This is a piece of code which is common to all the event handling
247    methods.  Maybe it should even be a function.  */
248 #define EV_TRAILER(e)                                         \
249   {                                                           \
250   XSETFRAME (emacs_event->frame_or_window, emacsframe);       \
251   if (e) emacs_event->timestamp = EV_TIMESTAMP (e);           \
252   n_emacs_events_pending++;                                   \
253   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);     \
254   EVENT_INIT (*emacs_event);                                  \
255   ns_send_appdefined (-1);                                    \
256   }
258 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
260 /* TODO: get rid of need for these forward declarations */
261 static void ns_condemn_scroll_bars (struct frame *f);
262 static void ns_judge_scroll_bars (struct frame *f);
263 void x_set_frame_alpha (struct frame *f);
265 /* FIXME: figure out what to do with underline_minimum_offset. */
268 /* ==========================================================================
270     Utilities
272    ========================================================================== */
275 static Lisp_Object
276 append2 (Lisp_Object list, Lisp_Object item)
277 /* --------------------------------------------------------------------------
278    Utility to append to a list
279    -------------------------------------------------------------------------- */
281   Lisp_Object array[2];
282   array[0] = list;
283   array[1] = Fcons (item, Qnil);
284   return Fnconc (2, &array[0]);
288 void
289 ns_init_paths (void)
290 /* --------------------------------------------------------------------------
291    Used to allow emacs to find its resources under Emacs.app
292    Called from emacs.c at startup.
293    -------------------------------------------------------------------------- */
295   NSBundle *bundle = [NSBundle mainBundle];
296   NSString *binDir = [bundle bundlePath], *resourceDir = [bundle resourcePath];
297   NSString *resourcePath, *resourcePaths;
298   NSRange range;
299   BOOL onWindows = NO; /* how do I determine this? */
300   NSString *pathSeparator = onWindows ? @";" : @":";
301   NSFileManager *fileManager = [NSFileManager defaultManager];
302   BOOL isDir;
303 /*NSLog (@"ns_init_paths: '%@'\n%@\n", [[NSBundle mainBundle] bundlePath], [[NSBundle mainBundle] resourcePath]); */
305   /* get bindir from base */
306   range = [resourceDir rangeOfString: @"Contents"];
307   if (range.location != NSNotFound)
308     {
309       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
310 #ifdef NS_IMPL_COCOA
311       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
312 #endif
313     }
315   /* the following based on Andrew Choi's init_mac_osx_environment () */
316   if (!getenv ("EMACSLOADPATH"))
317     {
318       NSArray *paths = [resourceDir stringsByAppendingPaths:
319                                   [NSArray arrayWithObjects:
320                                          @"site-lisp", @"lisp", @"leim", nil]];
321       NSEnumerator *pathEnum = [paths objectEnumerator];
322       resourcePaths = @"";
323       while (resourcePath = [pathEnum nextObject])
324         {
325           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
326             if (isDir)
327               {
328                 if ([resourcePaths length] > 0)
329                   resourcePaths
330                     = [resourcePaths stringByAppendingString: pathSeparator];
331                 resourcePaths
332                   = [resourcePaths stringByAppendingString: resourcePath];
333               }
334         }
335       if ([resourcePaths length] > 0)
336         setenv ("EMACSLOADPATH", [resourcePaths UTF8String], 1);
337 /*NSLog (@"loadPath: '%@'\n", resourcePaths); */
338     }
340   if (!getenv ("EMACSPATH"))
341     {
342       NSArray *paths = [binDir stringsByAppendingPaths:
343                                   [NSArray arrayWithObjects: @"bin",
344                                                              @"lib-exec", nil]];
345       NSEnumerator *pathEnum = [paths objectEnumerator];
346       resourcePaths = @"";
347       while (resourcePath = [pathEnum nextObject])
348         {
349           if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
350             if (isDir)
351               {
352                 if ([resourcePaths length] > 0)
353                   resourcePaths
354                     = [resourcePaths stringByAppendingString: pathSeparator];
355                 resourcePaths
356                   = [resourcePaths stringByAppendingString: resourcePath];
357               }
358         }
359       if ([resourcePaths length] > 0)
360         setenv ("EMACSPATH", [resourcePaths UTF8String], 1);
361     }
363   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
364   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
365     {
366       if (isDir)
367         {
368           if (!getenv ("EMACSDATA"))
369             setenv ("EMACSDATA", [resourcePath UTF8String], 1);
370           if (!getenv ("EMACSDOC"))
371             setenv ("EMACSDOC", [resourcePath UTF8String], 1);
372         }
373     }
375   if (!getenv ("INFOPATH"))
376     {
377       resourcePath = [resourceDir stringByAppendingPathComponent: @"info"];
378       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
379         if (isDir)
380           setenv ("INFOPATH", [[resourcePath stringByAppendingString: @":"]
381                                              UTF8String], 1);
382       /* Note, extra colon needed to cause merge w/later user additions. */
383     }
387 static int
388 timeval_subtract (struct timeval *result, struct timeval x, struct timeval y)
389 /* --------------------------------------------------------------------------
390    Subtract the `struct timeval' values X and Y, storing the result in RESULT.
391    Return 1 if the difference is negative, otherwise 0.
392    -------------------------------------------------------------------------- */
394   /* Perform the carry for the later subtraction by updating y.
395      This is safer because on some systems
396      the tv_sec member is unsigned.  */
397   if (x.tv_usec < y.tv_usec)
398     {
399       int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
400       y.tv_usec -= 1000000 * nsec;
401       y.tv_sec += nsec;
402     }
403   if (x.tv_usec - y.tv_usec > 1000000)
404     {
405       int nsec = (y.tv_usec - x.tv_usec) / 1000000;
406       y.tv_usec += 1000000 * nsec;
407       y.tv_sec -= nsec;
408     }
410   /* Compute the time remaining to wait.  tv_usec is certainly positive.  */
411   result->tv_sec = x.tv_sec - y.tv_sec;
412   result->tv_usec = x.tv_usec - y.tv_usec;
414   /* Return indication of whether the result should be considered negative.  */
415   return x.tv_sec < y.tv_sec;
418 static void
419 ns_timeout (int usecs)
420 /* --------------------------------------------------------------------------
421      Blocking timer utility used by ns_ring_bell
422    -------------------------------------------------------------------------- */
424   struct timeval wakeup;
426   EMACS_GET_TIME (wakeup);
428   /* Compute time to wait until, propagating carry from usecs.  */
429   wakeup.tv_usec += usecs;
430   wakeup.tv_sec += (wakeup.tv_usec / 1000000);
431   wakeup.tv_usec %= 1000000;
433   /* Keep waiting until past the time wakeup.  */
434   while (1)
435     {
436       struct timeval timeout;
438       EMACS_GET_TIME (timeout);
440       /* In effect, timeout = wakeup - timeout.
441          Break if result would be negative.  */
442       if (timeval_subtract (&timeout, wakeup, timeout))
443         break;
445       /* Try to wait that long--but we might wake up sooner.  */
446       select (0, NULL, NULL, NULL, &timeout);
447     }
451 void
452 ns_release_object (void *obj)
453 /* --------------------------------------------------------------------------
454     Release an object (callable from C)
455    -------------------------------------------------------------------------- */
457     [(id)obj release];
461 void
462 ns_retain_object (void *obj)
463 /* --------------------------------------------------------------------------
464     Retain an object (callable from C)
465    -------------------------------------------------------------------------- */
467     [(id)obj retain];
471 void *
472 ns_alloc_autorelease_pool (void)
473 /* --------------------------------------------------------------------------
474      Allocate a pool for temporary objects (callable from C)
475    -------------------------------------------------------------------------- */
477   return [[NSAutoreleasePool alloc] init];
481 void
482 ns_release_autorelease_pool (void *pool)
483 /* --------------------------------------------------------------------------
484      Free a pool and temporary objects it refers to (callable from C)
485    -------------------------------------------------------------------------- */
487   ns_release_object (pool);
492 /* ==========================================================================
494     Focus (clipping) and screen update
496    ========================================================================== */
498 static NSRect
499 ns_resize_handle_rect (NSWindow *window)
501   NSRect r = [window frame];
502   r.origin.x = r.size.width - RESIZE_HANDLE_SIZE;
503   r.origin.y = 0;
504   r.size.width = r.size.height = RESIZE_HANDLE_SIZE;
505   return r;
510 // Window constraining
511 // -------------------
513 // To ensure that the windows are not placed under the menu bar, they
514 // are typically moved by the call-back constrainFrameRect. However,
515 // by overriding it, it's possible to inhibit this, leaving the window
516 // in it's original position.
518 // It's possible to hide the menu bar. However, technically, it's only
519 // possible to hide it when the application is active. To ensure that
520 // this work properly, the menu bar and window constraining are
521 // deferred until the application becomes active.
523 // Even though it's not possible to manually move a window above the
524 // top of the screen, it is allowed if it's done programmatically,
525 // when the menu is hidden. This allows the editable area to cover the
526 // full screen height.
528 // Test cases
529 // ----------
531 // Use the following extra files:
533 //    init.el:
534 //       ;; Hide menu and place frame slightly above the top of the screen.
535 //       (setq ns-auto-hide-menu-bar t)
536 //       (set-frame-position (selected-frame) 0 -20)
538 // Test 1:
540 //    emacs -Q -l init.el
542 //    Result: No menu bar, and the title bar should be above the screen.
544 // Test 2:
546 //    emacs -Q
548 //    Result: Menu bar visible, frame placed immediately below the menu.
551 static void
552 ns_constrain_all_frames (void)
554   Lisp_Object tail, frame;
556   FOR_EACH_FRAME (tail, frame)
557     {
558       struct frame *f = XFRAME (frame);
559       if (FRAME_NS_P (f))
560         {
561           NSView *view = FRAME_NS_VIEW (f);
562           /* This no-op will trigger the default window placing
563            * constriant system. */
564           f->output_data.ns->dont_constrain = 0;
565           [[view window] setFrameOrigin:[[view window] frame].origin];
566         }
567     }
571 /* True, if the menu bar should be hidden.  */
573 static BOOL
574 ns_menu_bar_should_be_hidden (void)
576   return !NILP (ns_auto_hide_menu_bar)
577     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
581 /* Show or hide the menu bar, based on user setting.  */
583 static void
584 ns_update_auto_hide_menu_bar (void)
586 #ifndef MAC_OS_X_VERSION_10_6
587 #define MAC_OS_X_VERSION_10_6 1060
588 #endif
589 #ifdef NS_IMPL_COCOA
590 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
591   BLOCK_INPUT;
593   NSTRACE (ns_update_auto_hide_menu_bar);
595   if (NSApp != nil
596       && [NSApp isActive]
597       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
598     {
599       // Note, "setPresentationOptions" triggers an error unless the
600       // application is active.
601       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
603       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
604         {
605           NSApplicationPresentationOptions options
606             = NSApplicationPresentationAutoHideDock;
608           if (menu_bar_should_be_hidden)
609             options |= NSApplicationPresentationAutoHideMenuBar;
611           [NSApp setPresentationOptions: options];
613           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
615           if (!ns_menu_bar_is_hidden)
616             {
617               ns_constrain_all_frames ();
618             }
619         }
620     }
622   UNBLOCK_INPUT;
623 #endif
624 #endif
628 static void
629 ns_update_begin (struct frame *f)
630 /* --------------------------------------------------------------------------
631    Prepare for a grouped sequence of drawing calls
632    external (RIF) call; whole frame, called before update_window_begin
633    -------------------------------------------------------------------------- */
635   NSView *view = FRAME_NS_VIEW (f);
636   NSTRACE (ns_update_begin);
638   ns_update_auto_hide_menu_bar ();
640   ns_updating_frame = f;
641   [view lockFocus];
643 #ifdef NS_IMPL_GNUSTEP
644   uRect = NSMakeRect (0, 0, 0, 0);
645 #endif
649 static void
650 ns_update_window_begin (struct window *w)
651 /* --------------------------------------------------------------------------
652    Prepare for a grouped sequence of drawing calls
653    external (RIF) call; for one window, called after update_begin
654    -------------------------------------------------------------------------- */
656   struct frame *f = XFRAME (WINDOW_FRAME (w));
657  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
658   NSTRACE (ns_update_window_begin);
660   updated_window = w;
661   set_output_cursor (&w->cursor);
663   BLOCK_INPUT;
665   if (f == hlinfo->mouse_face_mouse_frame)
666     {
667       /* Don't do highlighting for mouse motion during the update.  */
668       hlinfo->mouse_face_defer = 1;
670         /* If the frame needs to be redrawn,
671            simply forget about any prior mouse highlighting.  */
672       if (FRAME_GARBAGED_P (f))
673         hlinfo->mouse_face_window = Qnil;
675       /* (further code for mouse faces ifdef'd out in other terms elided) */
676     }
678   UNBLOCK_INPUT;
682 static void
683 ns_update_window_end (struct window *w, int cursor_on_p,
684                       int mouse_face_overwritten_p)
685 /* --------------------------------------------------------------------------
686    Finished a grouped sequence of drawing calls
687    external (RIF) call; for one window called before update_end
688    -------------------------------------------------------------------------- */
690   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
692   /* note: this fn is nearly identical in all terms */
693   if (!w->pseudo_window_p)
694     {
695       BLOCK_INPUT;
697       if (cursor_on_p)
698         display_and_set_cursor (w, 1,
699                                 output_cursor.hpos, output_cursor.vpos,
700                                 output_cursor.x, output_cursor.y);
702       if (draw_window_fringes (w, 1))
703         x_draw_vertical_border (w);
705       UNBLOCK_INPUT;
706     }
708   /* If a row with mouse-face was overwritten, arrange for
709      frame_up_to_date to redisplay the mouse highlight.  */
710   if (mouse_face_overwritten_p)
711     {
712       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
713       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
714       hlinfo->mouse_face_window = Qnil;
715     }
717   updated_window = NULL;
718   NSTRACE (update_window_end);
722 static void
723 ns_update_end (struct frame *f)
724 /* --------------------------------------------------------------------------
725    Finished a grouped sequence of drawing calls
726    external (RIF) call; for whole frame, called after update_window_end
727    -------------------------------------------------------------------------- */
729   NSView *view = FRAME_NS_VIEW (f);
731 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
732     MOUSE_HL_INFO (f)->mouse_face_defer = 0;
734   BLOCK_INPUT;
736 #ifdef NS_IMPL_GNUSTEP
737   /* trigger flush only in the rectangle we tracked as being drawn */
738   [view unlockFocusNeedsFlush: NO];
739 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
740   [view lockFocusInRect: uRect];
741 #endif
743   [view unlockFocus];
744   [[view window] flushWindow];
746   UNBLOCK_INPUT;
747   ns_updating_frame = NULL;
748   NSTRACE (ns_update_end);
752 static void
753 ns_flush (struct frame *f)
754 /* --------------------------------------------------------------------------
755    external (RIF) call
756    NS impl is no-op since currently we flush in ns_update_end and elsewhere
757    -------------------------------------------------------------------------- */
759     NSTRACE (ns_flush);
763 static void
764 ns_focus (struct frame *f, NSRect *r, int n)
765 /* --------------------------------------------------------------------------
766    Internal: Focus on given frame.  During small local updates this is used to
767      draw, however during large updates, ns_update_begin and ns_update_end are
768      called to wrap the whole thing, in which case these calls are stubbed out.
769      Except, on GNUstep, we accumulate the rectangle being drawn into, because
770      the back end won't do this automatically, and will just end up flushing
771      the entire window.
772    -------------------------------------------------------------------------- */
774 //  NSTRACE (ns_focus);
775 #ifdef NS_IMPL_GNUSTEP
776   NSRect u;
777     if (n == 2)
778       u = NSUnionRect (r[0], r[1]);
779     else if (r)
780       u = *r;
781 #endif
782 /* static int c =0;
783    fprintf (stderr, "focus: %d", c++);
784    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
785    fprintf (stderr, "\n"); */
787   if (f != ns_updating_frame)
788     {
789       NSView *view = FRAME_NS_VIEW (f);
790       if (view != focus_view)
791         {
792           if (focus_view != NULL)
793             {
794               [focus_view unlockFocus];
795               [[focus_view window] flushWindow];
796 /*debug_lock--; */
797             }
799           if (view)
800 #ifdef NS_IMPL_GNUSTEP
801             r ? [view lockFocusInRect: u] : [view lockFocus];
802 #else
803             [view lockFocus];
804 #endif
805           focus_view = view;
806 /*if (view) debug_lock++; */
807         }
808 #ifdef NS_IMPL_GNUSTEP
809       else
810         {
811           /* more than one rect being drawn into */
812           if (view && r)
813             {
814               [view unlockFocus]; /* add prev rect to redraw list */
815               [view lockFocusInRect: u]; /* focus for draw in new rect */
816             }
817         }
818 #endif
819     }
820 #ifdef NS_IMPL_GNUSTEP
821   else
822     {
823       /* in batch mode, but in GNUstep must still track rectangles explicitly */
824       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
825     }
826 #endif
828   /* clipping */
829   if (r)
830     {
831       [[NSGraphicsContext currentContext] saveGraphicsState];
832       if (n == 2)
833         NSRectClipList (r, 2);
834       else
835         NSRectClip (*r);
836       gsaved = YES;
837     }
841 static void
842 ns_unfocus (struct frame *f)
843 /* --------------------------------------------------------------------------
844      Internal: Remove focus on given frame
845    -------------------------------------------------------------------------- */
847 //  NSTRACE (ns_unfocus);
849   if (gsaved)
850     {
851       [[NSGraphicsContext currentContext] restoreGraphicsState];
852       gsaved = NO;
853     }
855   if (f != ns_updating_frame)
856     {
857       if (focus_view != NULL)
858         {
859           [focus_view unlockFocus];
860           [[focus_view window] flushWindow];
861           focus_view = NULL;
862 /*debug_lock--; */
863         }
864     }
868 static void
869 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
870 /* --------------------------------------------------------------------------
871      Internal (but parallels other terms): Focus drawing on given row
872    -------------------------------------------------------------------------- */
874   struct frame *f = XFRAME (WINDOW_FRAME (w));
875   NSRect clip_rect;
876   int window_x, window_y, window_width;
878   window_box (w, area, &window_x, &window_y, &window_width, 0);
880   clip_rect.origin.x = window_x - FRAME_INTERNAL_BORDER_WIDTH (f);
881   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
882   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
883   clip_rect.size.width = window_width + 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
884   clip_rect.size.height = row->visible_height;
886   /* allow a full-height row at the top when requested
887      (used to draw fringe all the way through internal border area) */
888   if (gc && clip_rect.origin.y < 5)
889     {
890       clip_rect.origin.y -= FRAME_INTERNAL_BORDER_WIDTH (f);
891       clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
892     }
894   /* likewise at bottom */
895   if (gc &&
896       FRAME_PIXEL_HEIGHT (f) - (clip_rect.origin.y + clip_rect.size.height) < 5)
897     clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
899   ns_focus (f, &clip_rect, 1);
903 static void
904 ns_ring_bell (struct frame *f)
905 /* --------------------------------------------------------------------------
906      "Beep" routine
907    -------------------------------------------------------------------------- */
909   NSTRACE (ns_ring_bell);
910   if (visible_bell)
911     {
912       NSAutoreleasePool *pool;
913       struct frame *frame = SELECTED_FRAME ();
914       NSView *view;
916       BLOCK_INPUT;
917       pool = [[NSAutoreleasePool alloc] init];
919       view = FRAME_NS_VIEW (frame);
920       if (view != nil)
921         {
922           NSRect r, surr;
923           NSPoint dim = NSMakePoint (128, 128);
925           r = [view bounds];
926           r.origin.x += (r.size.width - dim.x) / 2;
927           r.origin.y += (r.size.height - dim.y) / 2;
928           r.size.width = dim.x;
929           r.size.height = dim.y;
930           surr = NSInsetRect (r, -2, -2);
931           ns_focus (frame, &surr, 1);
932           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
933           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
934                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
935           NSRectFill (r);
936           [[view window] flushWindow];
937           ns_timeout (150000);
938           [[view window] restoreCachedImage];
939           [[view window] flushWindow];
940           ns_unfocus (frame);
941         }
942       [pool release];
943       UNBLOCK_INPUT;
944     }
945   else
946     {
947       NSBeep ();
948     }
952 static void
953 ns_reset_terminal_modes (struct terminal *terminal)
954 /*  Externally called as hook */
956   NSTRACE (ns_reset_terminal_modes);
960 static void
961 ns_set_terminal_modes (struct terminal *terminal)
962 /*  Externally called as hook */
964   NSTRACE (ns_set_terminal_modes);
969 /* ==========================================================================
971     Frame / window manager related functions
973    ========================================================================== */
976 static void
977 ns_raise_frame (struct frame *f)
978 /* --------------------------------------------------------------------------
979      Bring window to foreground and make it active
980    -------------------------------------------------------------------------- */
982   NSView *view = FRAME_NS_VIEW (f);
983   check_ns ();
984   BLOCK_INPUT;
985   FRAME_SAMPLE_VISIBILITY (f);
986   if (FRAME_VISIBLE_P (f))
987     {
988       [[view window] makeKeyAndOrderFront: NSApp];
989     }
990   UNBLOCK_INPUT;
994 static void
995 ns_lower_frame (struct frame *f)
996 /* --------------------------------------------------------------------------
997      Send window to back
998    -------------------------------------------------------------------------- */
1000   NSView *view = FRAME_NS_VIEW (f);
1001   check_ns ();
1002   BLOCK_INPUT;
1003   [[view window] orderBack: NSApp];
1004   UNBLOCK_INPUT;
1008 static void
1009 ns_frame_raise_lower (struct frame *f, int raise)
1010 /* --------------------------------------------------------------------------
1011      External (hook)
1012    -------------------------------------------------------------------------- */
1014   NSTRACE (ns_frame_raise_lower);
1016   if (raise)
1017     ns_raise_frame (f);
1018   else
1019     ns_lower_frame (f);
1023 static void
1024 ns_frame_rehighlight (struct frame *frame)
1025 /* --------------------------------------------------------------------------
1026      External (hook): called on things like window switching within frame
1027    -------------------------------------------------------------------------- */
1029   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1030   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1032   NSTRACE (ns_frame_rehighlight);
1033   if (dpyinfo->x_focus_frame)
1034     {
1035       dpyinfo->x_highlight_frame
1036         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1037            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1038            : dpyinfo->x_focus_frame);
1039       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1040         {
1041           FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame) = Qnil;
1042           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1043         }
1044     }
1045   else
1046       dpyinfo->x_highlight_frame = 0;
1048   if (dpyinfo->x_highlight_frame &&
1049          dpyinfo->x_highlight_frame != old_highlight)
1050     {
1051       if (old_highlight)
1052         {
1053           x_update_cursor (old_highlight, 1);
1054           x_set_frame_alpha (old_highlight);
1055         }
1056       if (dpyinfo->x_highlight_frame)
1057         {
1058           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1059           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1060         }
1061     }
1065 void
1066 x_make_frame_visible (struct frame *f)
1067 /* --------------------------------------------------------------------------
1068      External: Show the window (X11 semantics)
1069    -------------------------------------------------------------------------- */
1071   NSTRACE (x_make_frame_visible);
1072   /* XXX: at some points in past this was not needed, as the only place that
1073      called this (frame.c:Fraise_frame ()) also called raise_lower;
1074      if this ends up the case again, comment this out again. */
1075   if (!FRAME_VISIBLE_P (f))
1076     {
1077       f->async_visible = 1;
1078       ns_raise_frame (f);
1079     }
1083 void
1084 x_make_frame_invisible (struct frame *f)
1085 /* --------------------------------------------------------------------------
1086      External: Hide the window (X11 semantics)
1087    -------------------------------------------------------------------------- */
1089   NSView * view = FRAME_NS_VIEW (f);
1090   NSTRACE (x_make_frame_invisible);
1091   check_ns ();
1092   [[view window] orderOut: NSApp];
1093   f->async_visible = 0;
1094   f->async_iconified = 0;
1098 void
1099 x_iconify_frame (struct frame *f)
1100 /* --------------------------------------------------------------------------
1101      External: Iconify window
1102    -------------------------------------------------------------------------- */
1104   NSView * view = FRAME_NS_VIEW (f);
1105   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1106   NSTRACE (x_iconify_frame);
1107   check_ns ();
1109   if (dpyinfo->x_highlight_frame == f)
1110     dpyinfo->x_highlight_frame = 0;
1112   if ([[view window] windowNumber] <= 0)
1113     {
1114       /* the window is still deferred.  Make it very small, bring it
1115          on screen and order it out. */
1116       NSRect s = { { 100, 100}, {0, 0} };
1117       NSRect t;
1118       t = [[view window] frame];
1119       [[view window] setFrame: s display: NO];
1120       [[view window] orderBack: NSApp];
1121       [[view window] orderOut: NSApp];
1122       [[view window] setFrame: t display: NO];
1123     }
1124   [[view window] miniaturize: NSApp];
1128 void
1129 x_destroy_window (struct frame *f)
1130 /* --------------------------------------------------------------------------
1131      External: Delete the window
1132    -------------------------------------------------------------------------- */
1134   NSView *view = FRAME_NS_VIEW (f);
1135   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1136   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1137   NSTRACE (x_destroy_window);
1138   check_ns ();
1140   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1142   BLOCK_INPUT;
1144   free_frame_menubar (f);
1146   if (FRAME_FACE_CACHE (f))
1147     free_frame_faces (f);
1149   if (f == dpyinfo->x_focus_frame)
1150     dpyinfo->x_focus_frame = 0;
1151   if (f == dpyinfo->x_highlight_frame)
1152     dpyinfo->x_highlight_frame = 0;
1153   if (f == hlinfo->mouse_face_mouse_frame)
1154     {
1155       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1156       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1157       hlinfo->mouse_face_window = Qnil;
1158       hlinfo->mouse_face_deferred_gc = 0;
1159       hlinfo->mouse_face_mouse_frame = 0;
1160     }
1162   xfree (f->output_data.ns);
1164   [[view window] close];
1165   [view release];
1167   ns_window_num--;
1168   UNBLOCK_INPUT;
1172 void
1173 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1174 /* --------------------------------------------------------------------------
1175      External: Position the window
1176    -------------------------------------------------------------------------- */
1178   NSView *view = FRAME_NS_VIEW (f);
1179   NSArray *screens = [NSScreen screens];
1180   NSScreen *fscreen = [screens objectAtIndex: 0];
1181   NSScreen *screen = [[view window] screen];
1183   NSTRACE (x_set_offset);
1185   BLOCK_INPUT;
1187   f->left_pos = xoff;
1188   f->top_pos = yoff;
1190   if (view != nil && screen && fscreen)
1191     {
1192       f->left_pos = f->size_hint_flags & XNegative
1193         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1194         : f->left_pos;
1195       /* We use visibleFrame here to take menu bar into account.
1196          Ideally we should also adjust left/top with visibleFrame.origin.  */
1198       f->top_pos = f->size_hint_flags & YNegative
1199         ? ([screen visibleFrame].size.height + f->top_pos
1200            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1201            - FRAME_TOOLBAR_HEIGHT (f))
1202         : f->top_pos;
1203 #ifdef NS_IMPL_GNUSTEP
1204       if (f->left_pos < 100)
1205         f->left_pos = 100;  /* don't overlap menu */
1206 #endif
1207       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1208          menu bar.  */
1209       f->output_data.ns->dont_constrain = 0;
1210       [[view window] setFrameTopLeftPoint:
1211                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1212                                     SCREENMAXBOUND ([fscreen frame].size.height
1213                                                     - NS_TOP_POS (f)))];
1214       f->size_hint_flags &= ~(XNegative|YNegative);
1215     }
1217   UNBLOCK_INPUT;
1221 void
1222 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1223 /* --------------------------------------------------------------------------
1224      Adjust window pixel size based on given character grid size
1225      Impl is a bit more complex than other terms, need to do some
1226      internal clipping.
1227    -------------------------------------------------------------------------- */
1229   EmacsView *view = FRAME_NS_VIEW (f);
1230   EmacsToolbar *toolbar = [view toolbar];
1231   NSWindow *window = [view window];
1232   NSRect wr = [window frame];
1233   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1234   int pixelwidth, pixelheight;
1235   static int oldRows, oldCols, oldFontWidth, oldFontHeight;
1236   static int oldTB;
1237   static struct frame *oldF;
1239   NSTRACE (x_set_window_size);
1241   if (view == nil ||
1242       (f == oldF
1243        && rows == oldRows && cols == oldCols
1244        && oldFontWidth == FRAME_COLUMN_WIDTH (f)
1245        && oldFontHeight == FRAME_LINE_HEIGHT (f)
1246        && oldTB == tb))
1247     return;
1249 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1251   BLOCK_INPUT;
1253   check_frame_size (f, &rows, &cols);
1254   oldF = f;
1255   oldRows = rows;
1256   oldCols = cols;
1257   oldFontWidth = FRAME_COLUMN_WIDTH (f);
1258   oldFontHeight = FRAME_LINE_HEIGHT (f);
1259   oldTB = tb;
1261   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1262   compute_fringe_widths (f, 0);
1264   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1265   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1267   /* If we have a toolbar, take its height into account. */
1268   if (tb)
1269     /* NOTE: previously this would generate wrong result if toolbar not
1270              yet displayed and fixing toolbar_height=32 helped, but
1271              now (200903) seems no longer needed */
1272     FRAME_TOOLBAR_HEIGHT (f) =
1273       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1274         - FRAME_NS_TITLEBAR_HEIGHT (f);
1275   else
1276     FRAME_TOOLBAR_HEIGHT (f) = 0;
1278   wr.size.width = pixelwidth + f->border_width;
1279   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f)
1280                   + FRAME_TOOLBAR_HEIGHT (f);
1282   /* Do not try to constrain to this screen.  We may have multiple
1283      screens, and want Emacs to span those.  Constraining to screen
1284      prevents that, and that is not nice to the user.  */
1285  if (f->output_data.ns->zooming)
1286    f->output_data.ns->zooming = 0;
1287  else
1288    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1290   [view setRows: rows andColumns: cols];
1291   [window setFrame: wr display: YES];
1293 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1295   /* This is a trick to compensate for Emacs' managing the scrollbar area
1296      as a fixed number of standard character columns.  Instead of leaving
1297      blank space for the extra, we chopped it off above.  Now for
1298      left-hand scrollbars, we shift all rendering to the left by the
1299      difference between the real width and Emacs' imagined one.  For
1300      right-hand bars, don't worry about it since the extra is never used.
1301      (Obviously doesn't work for vertically split windows tho..) */
1302   {
1303     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1304       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1305                      - NS_SCROLL_BAR_WIDTH (f), 0)
1306       : NSMakePoint (0, 0);
1307     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1308     [view setBoundsOrigin: origin];
1309   }
1311   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1312   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1313   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1314 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1316   mark_window_cursors_off (XWINDOW (f->root_window));
1317   cancel_mouse_face (f);
1319   UNBLOCK_INPUT;
1324 /* ==========================================================================
1326     Color management
1328    ========================================================================== */
1331 NSColor *
1332 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1334   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1335   if (idx < 1 || idx >= color_table->avail)
1336     return nil;
1337   return color_table->colors[idx];
1341 unsigned long
1342 ns_index_color (NSColor *color, struct frame *f)
1344   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1345   int idx;
1346   NSNumber *index;
1348   if (!color_table->colors)
1349     {
1350       color_table->size = NS_COLOR_CAPACITY;
1351       color_table->avail = 1; /* skip idx=0 as marker */
1352       color_table->colors
1353         = (NSColor **)xmalloc (color_table->size * sizeof (NSColor *));
1354       color_table->colors[0] = nil;
1355       color_table->empty_indices = [[NSMutableSet alloc] init];
1356     }
1358   /* do we already have this color ? */
1359   {
1360     int i;
1361     for (i = 1; i < color_table->avail; i++)
1362       {
1363         if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1364           {
1365             [color_table->colors[i] retain];
1366             return i;
1367           }
1368       }
1369   }
1371   if ([color_table->empty_indices count] > 0)
1372     {
1373       index = [color_table->empty_indices anyObject];
1374       [color_table->empty_indices removeObject: index];
1375       idx = [index unsignedIntValue];
1376     }
1377   else
1378     {
1379       if (color_table->avail == color_table->size)
1380         {
1381           color_table->size += NS_COLOR_CAPACITY;
1382           color_table->colors
1383             = (NSColor **)xrealloc (color_table->colors,
1384                                     color_table->size * sizeof (NSColor *));
1385         }
1386       idx = color_table->avail++;
1387     }
1389   color_table->colors[idx] = color;
1390   [color retain];
1391 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1392   return idx;
1396 void
1397 ns_free_indexed_color (unsigned long idx, struct frame *f)
1399   struct ns_color_table *color_table;
1400   NSColor *color;
1401   NSNumber *index;
1403   if (!f)
1404     return;
1406   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1408   if (idx <= 0 || idx >= color_table->size) {
1409     message1("ns_free_indexed_color: Color index out of range.\n");
1410     return;
1411   }
1413   index = [NSNumber numberWithUnsignedInt: idx];
1414   if ([color_table->empty_indices containsObject: index]) {
1415     message1("ns_free_indexed_color: attempt to free already freed color.\n");
1416     return;
1417   }
1419   color = color_table->colors[idx];
1420   [color release];
1421   color_table->colors[idx] = nil;
1422   [color_table->empty_indices addObject: [NSNumber numberWithUnsignedInt: idx]];
1423 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1427 static int
1428 ns_get_color (const char *name, NSColor **col)
1429 /* --------------------------------------------------------------------------
1430      Parse a color name
1431    -------------------------------------------------------------------------- */
1432 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1433    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1434    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1436   NSColor *new = nil;
1437   static char hex[20];
1438   int scaling;
1439   float r = -1.0, g, b;
1440   NSString *nsname = [NSString stringWithUTF8String: name];
1442 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1443   BLOCK_INPUT;
1445   if ([nsname isEqualToString: @"ns_selection_color"])
1446     {
1447       nsname = ns_selection_color;
1448       name = [ns_selection_color UTF8String];
1449     }
1451   /* First, check for some sort of numeric specification. */
1452   hex[0] = '\0';
1454   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1455     {
1456       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1457       [scanner scanFloat: &r];
1458       [scanner scanFloat: &g];
1459       [scanner scanFloat: &b];
1460     }
1461   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1462     {
1463       strncpy (hex, name + 4, 19);
1464       hex[19] = '\0';
1465       scaling = (strlen(hex) - 2) / 3;
1466     }
1467   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1468     {
1469       int len = (strlen(name) - 1);
1470       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1471       int i;
1472       scaling = strlen(name+start) / 3;
1473       for (i=0; i<3; i++) {
1474         strncpy(hex + i * (scaling + 1), name + start + i * scaling, scaling);
1475         hex[(i+1) * (scaling + 1) - 1] = '/';
1476       }
1477       hex[3 * (scaling + 1) - 1] = '\0';
1478     }
1480   if (hex[0])
1481     {
1482       int rr, gg, bb;
1483       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1484       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1485         {
1486           r = rr / fscale;
1487           g = gg / fscale;
1488           b = bb / fscale;
1489         }
1490     }
1492   if (r >= 0.0)
1493     {
1494       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1495       UNBLOCK_INPUT;
1496       return 0;
1497     }
1499   /* Otherwise, color is expected to be from a list */
1500   {
1501     NSEnumerator *lenum, *cenum;
1502     NSString *name;
1503     NSColorList *clist;
1505 #ifdef NS_IMPL_GNUSTEP
1506     /* XXX: who is wrong, the requestor or the implementation? */
1507     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1508         == NSOrderedSame)
1509       nsname = @"highlightColor";
1510 #endif
1512     lenum = [[NSColorList availableColorLists] objectEnumerator];
1513     while ( (clist = [lenum nextObject]) && new == nil)
1514       {
1515         cenum = [[clist allKeys] objectEnumerator];
1516         while ( (name = [cenum nextObject]) && new == nil )
1517           {
1518             if ([name compare: nsname
1519                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1520               new = [clist colorWithKey: name];
1521           }
1522       }
1523   }
1525   if (new)
1526     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1527   UNBLOCK_INPUT;
1528   return new ? 0 : 1;
1532 static NSColor *
1533 ns_get_color_default (const char *name, NSColor *dflt)
1534 /* --------------------------------------------------------------------------
1535      Parse a color or use a default value
1536    -------------------------------------------------------------------------- */
1538   NSColor * col;
1540   if (ns_get_color (name, &col))
1541     return dflt;
1542   else
1543     return col;
1548 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1549 /* --------------------------------------------------------------------------
1550      Convert a Lisp string object to a NS color
1551    -------------------------------------------------------------------------- */
1553   NSTRACE (ns_lisp_to_color);
1554   if (STRINGP (color))
1555     return ns_get_color (SDATA (color), col);
1556   else if (SYMBOLP (color))
1557     return ns_get_color (SDATA (SYMBOL_NAME (color)), col);
1558   return 1;
1562 Lisp_Object
1563 ns_color_to_lisp (NSColor *col)
1564 /* --------------------------------------------------------------------------
1565      Convert a color to a lisp string with the RGB equivalent
1566    -------------------------------------------------------------------------- */
1568   CGFloat red, green, blue, alpha, gray;
1569   char buf[1024];
1570   const char *str;
1571   NSTRACE (ns_color_to_lisp);
1573   BLOCK_INPUT;
1574   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1576       if ((str =[[col colorNameComponent] UTF8String]))
1577         {
1578           UNBLOCK_INPUT;
1579           return build_string ((char *)str);
1580         }
1582     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1583         getRed: &red green: &green blue: &blue alpha: &alpha];
1584   if (red ==green && red ==blue)
1585     {
1586       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1587             getWhite: &gray alpha: &alpha];
1588       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1589                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1590       UNBLOCK_INPUT;
1591       return build_string (buf);
1592     }
1594   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1595             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1597   UNBLOCK_INPUT;
1598   return build_string (buf);
1602 void
1603 ns_query_color(void *col, XColor *color_def, int setPixel)
1604 /* --------------------------------------------------------------------------
1605          Get ARGB values out of NSColor col and put them into color_def.
1606          If setPixel, set the pixel to a concatenated version.
1607          and set color_def pixel to the resulting index.
1608    -------------------------------------------------------------------------- */
1610   CGFloat r, g, b, a;
1612   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1613   color_def->red   = r * 65535;
1614   color_def->green = g * 65535;
1615   color_def->blue  = b * 65535;
1617   if (setPixel == YES)
1618     color_def->pixel
1619       = ARGB_TO_ULONG((int)(a*255),
1620                       (int)(r*255), (int)(g*255), (int)(b*255));
1625 ns_defined_color (struct frame *f,
1626                   const char *name,
1627                   XColor *color_def,
1628                   int alloc,
1629                   char makeIndex)
1630 /* --------------------------------------------------------------------------
1631          Return 1 if named color found, and set color_def rgb accordingly.
1632          If makeIndex and alloc are nonzero put the color in the color_table,
1633          and set color_def pixel to the resulting index.
1634          If makeIndex is zero, set color_def pixel to ARGB.
1635          Return 0 if not found
1636    -------------------------------------------------------------------------- */
1638   NSColor *col;
1639   NSTRACE (ns_defined_color);
1641   BLOCK_INPUT;
1642   if (ns_get_color (name, &col) != 0) /* Color not found  */
1643     {
1644       UNBLOCK_INPUT;
1645       return 0;
1646     }
1647   if (makeIndex && alloc)
1648     color_def->pixel = ns_index_color (col, f);
1649   ns_query_color (col, color_def, !makeIndex);
1650   UNBLOCK_INPUT;
1651   return 1;
1655 unsigned long
1656 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1657 /* --------------------------------------------------------------------------
1658     return an autoreleased RGB color
1659    -------------------------------------------------------------------------- */
1661 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1662   if (r < 0.0) r = 0.0;
1663   else if (r > 1.0) r = 1.0;
1664   if (g < 0.0) g = 0.0;
1665   else if (g > 1.0) g = 1.0;
1666   if (b < 0.0) b = 0.0;
1667   else if (b > 1.0) b = 1.0;
1668   if (a < 0.0) a = 0.0;
1669   else if (a > 1.0) a = 1.0;
1670   return (unsigned long) ns_index_color(
1671     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1675 void
1676 x_set_frame_alpha (struct frame *f)
1677 /* --------------------------------------------------------------------------
1678      change the entire-frame transparency
1679    -------------------------------------------------------------------------- */
1681   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1682   EmacsView *view = FRAME_NS_VIEW (f);
1683   double alpha = 1.0;
1684   double alpha_min = 1.0;
1686   if (dpyinfo->x_highlight_frame == f)
1687     alpha = f->alpha[0];
1688   else
1689     alpha = f->alpha[1];
1691   if (FLOATP (Vframe_alpha_lower_limit))
1692     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1693   else if (INTEGERP (Vframe_alpha_lower_limit))
1694     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1696   if (alpha < 0.0)
1697     return;
1698   else if (1.0 < alpha)
1699     alpha = 1.0;
1700   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1701     alpha = alpha_min;
1703 #ifdef NS_IMPL_COCOA
1704   [[view window] setAlphaValue: alpha];
1705 #endif
1709 /* ==========================================================================
1711     Mouse handling
1713    ========================================================================== */
1716 void
1717 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1718 /* --------------------------------------------------------------------------
1719      Programmatically reposition mouse pointer in pixel coordinates
1720    -------------------------------------------------------------------------- */
1722   NSTRACE (x_set_mouse_pixel_position);
1723   ns_raise_frame (f);
1724 #if 0
1725   /* FIXME: this does not work, and what about GNUstep? */
1726 #ifdef NS_IMPL_COCOA
1727   [FRAME_NS_VIEW (f) lockFocus];
1728   PSsetmouse ((float)pix_x, (float)pix_y);
1729   [FRAME_NS_VIEW (f) unlockFocus];
1730 #endif
1731 #endif
1735 void
1736 x_set_mouse_position (struct frame *f, int h, int v)
1737 /* --------------------------------------------------------------------------
1738      Programmatically reposition mouse pointer in character coordinates
1739    -------------------------------------------------------------------------- */
1741   int pix_x, pix_y;
1743   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1744   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1746   if (pix_x < 0) pix_x = 0;
1747   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1749   if (pix_y < 0) pix_y = 0;
1750   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1752   x_set_mouse_pixel_position (f, pix_x, pix_y);
1756 static int
1757 note_mouse_movement (struct frame *frame, float x, float y)
1758 /*   ------------------------------------------------------------------------
1759      Called by EmacsView on mouseMovement events.  Passes on
1760      to emacs mainstream code if we moved off of a rect of interest
1761      known as last_mouse_glyph.
1762      ------------------------------------------------------------------------ */
1764 //  NSTRACE (note_mouse_movement);
1766   XSETFRAME (last_mouse_motion_frame, frame);
1768   /* Note, this doesn't get called for enter/leave, since we don't have a
1769      position.  Those are taken care of in the corresponding NSView methods. */
1771   /* has movement gone beyond last rect we were tracking? */
1772   if (x < last_mouse_glyph.origin.x ||
1773       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1774       y < last_mouse_glyph.origin.y ||
1775       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1776     {
1777       ns_update_begin(frame);
1778       frame->mouse_moved = 1;
1779       note_mouse_highlight (frame, x, y);
1780       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1781       ns_update_end(frame);
1782       return 1;
1783     }
1785   return 0;
1789 static void
1790 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1791                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1792                    Time *time)
1793 /* --------------------------------------------------------------------------
1794     External (hook): inform emacs about mouse position and hit parts.
1795     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1796     x & y should be position in the scrollbar (the whole bar, not the handle)
1797     and length of scrollbar respectively
1798    -------------------------------------------------------------------------- */
1800   id view;
1801   NSPoint position;
1802   int xchar, ychar;
1803   Lisp_Object frame, tail;
1804   struct frame *f;
1805   struct ns_display_info *dpyinfo;
1807   NSTRACE (ns_mouse_position);
1809   if (*fp == NULL)
1810     {
1811       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1812       return;
1813     }
1815   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1817   BLOCK_INPUT;
1819   if (last_mouse_scroll_bar != nil && insist == 0)
1820     {
1821       /* TODO: we do not use this path at the moment because drag events will
1822            go directly to the EmacsScroller.  Leaving code in for now. */
1823       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1824                                               x: x y: y];
1825       if (time) *time = last_mouse_movement_time;
1826       last_mouse_scroll_bar = nil;
1827     }
1828   else
1829     {
1830       /* Clear the mouse-moved flag for every frame on this display.  */
1831       FOR_EACH_FRAME (tail, frame)
1832         if (FRAME_NS_P (XFRAME (frame))
1833             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1834           XFRAME (frame)->mouse_moved = 0;
1836       last_mouse_scroll_bar = nil;
1837       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1838         f = last_mouse_frame;
1839       else
1840         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1841                                     : SELECTED_FRAME ();
1843       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1844         {
1845           view = FRAME_NS_VIEW (*fp);
1847           position = [[view window] mouseLocationOutsideOfEventStream];
1848           position = [view convertPoint: position fromView: nil];
1849           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1850 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1852           if (bar_window) *bar_window = Qnil;
1853           if (part) *part = 0; /*scroll_bar_handle; */
1855           if (x) XSETINT (*x, lrint (position.x));
1856           if (y) XSETINT (*y, lrint (position.y));
1857           if (time) *time = last_mouse_movement_time;
1858           *fp = f;
1859         }
1860     }
1862   UNBLOCK_INPUT;
1866 static void
1867 ns_frame_up_to_date (struct frame *f)
1868 /* --------------------------------------------------------------------------
1869     External (hook): Fix up mouse highlighting right after a full update.
1870     Some highlighting was deferred if GC was happening during
1871     note_mouse_highlight (), while other highlighting was deferred for update.
1872    -------------------------------------------------------------------------- */
1874   NSTRACE (ns_frame_up_to_date);
1876   if (FRAME_NS_P (f))
1877     {
1878       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1879       if ((hlinfo->mouse_face_deferred_gc || f ==hlinfo->mouse_face_mouse_frame)
1880       /*&& hlinfo->mouse_face_mouse_frame*/)
1881         {
1882           BLOCK_INPUT;
1883           ns_update_begin(f);
1884           if (hlinfo->mouse_face_mouse_frame)
1885             note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1886                                   hlinfo->mouse_face_mouse_x,
1887                                   hlinfo->mouse_face_mouse_y);
1888           hlinfo->mouse_face_deferred_gc = 0;
1889           ns_update_end(f);
1890           UNBLOCK_INPUT;
1891         }
1892     }
1896 void
1897 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1898 /* --------------------------------------------------------------------------
1899     External (RIF): set frame mouse pointer type.
1900    -------------------------------------------------------------------------- */
1902   NSTRACE (ns_define_frame_cursor);
1903   if (FRAME_POINTER_TYPE (f) != cursor)
1904     {
1905       EmacsView *view = FRAME_NS_VIEW (f);
1906       FRAME_POINTER_TYPE (f) = cursor;
1907       [[view window] invalidateCursorRectsForView: view];
1908       /* Redisplay assumes this function also draws the changed frame
1909          cursor, but this function doesn't, so do it explicitly.  */
1910       x_update_cursor (f, 1);
1911     }
1916 /* ==========================================================================
1918     Keyboard handling
1920    ========================================================================== */
1923 static unsigned
1924 ns_convert_key (unsigned code)
1925 /* --------------------------------------------------------------------------
1926     Internal call used by NSView-keyDown.
1927    -------------------------------------------------------------------------- */
1929   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1930                                 / sizeof (convert_ns_to_X_keysym[0]));
1931   unsigned keysym;
1932   /* An array would be faster, but less easy to read. */
1933   for (keysym = 0; keysym < last_keysym; keysym += 2)
1934     if (code == convert_ns_to_X_keysym[keysym])
1935       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1936   return 0;
1937 /* if decide to use keyCode and Carbon table, use this line:
1938      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1942 char *
1943 x_get_keysym_name (int keysym)
1944 /* --------------------------------------------------------------------------
1945     Called by keyboard.c.  Not sure if the return val is important, except
1946     that it be unique.
1947    -------------------------------------------------------------------------- */
1949   static char value[16];
1950   NSTRACE (x_get_keysym_name);
1951   sprintf (value, "%d", keysym);
1952   return value;
1957 /* ==========================================================================
1959     Block drawing operations
1961    ========================================================================== */
1964 static void
1965 ns_redraw_scroll_bars (struct frame *f)
1967   int i;
1968   id view;
1969   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1970   NSTRACE (ns_judge_scroll_bars);
1971   for (i =[subviews count]-1; i >= 0; i--)
1972     {
1973       view = [subviews objectAtIndex: i];
1974       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1975       [view display];
1976     }
1980 void
1981 ns_clear_frame (struct frame *f)
1982 /* --------------------------------------------------------------------------
1983       External (hook): Erase the entire frame
1984    -------------------------------------------------------------------------- */
1986   NSView *view = FRAME_NS_VIEW (f);
1987   NSRect r;
1989   NSTRACE (ns_clear_frame);
1990   if (ns_in_resize)
1991     return;
1993  /* comes on initial frame because we have
1994     after-make-frame-functions = select-frame */
1995  if (!FRAME_DEFAULT_FACE (f))
1996    return;
1998   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2000   output_cursor.hpos = output_cursor.vpos = 0;
2001   output_cursor.x = -1;
2003   r = [view bounds];
2005   BLOCK_INPUT;
2006   ns_focus (f, &r, 1);
2007   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2008   NSRectFill (r);
2009   ns_unfocus (f);
2011 #ifdef NS_IMPL_COCOA
2012   [[view window] display];  /* redraw resize handle */
2013 #endif
2015   /* as of 2006/11 or so this is now needed */
2016   ns_redraw_scroll_bars (f);
2017   UNBLOCK_INPUT;
2021 void
2022 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2023 /* --------------------------------------------------------------------------
2024     External (RIF):  Clear section of frame
2025    -------------------------------------------------------------------------- */
2027   NSRect r = NSMakeRect (x, y, width, height);
2028   NSView *view = FRAME_NS_VIEW (f);
2029   struct face *face = FRAME_DEFAULT_FACE (f);
2031   if (!view || !face)
2032     return;
2034   NSTRACE (ns_clear_frame_area);
2036   r = NSIntersectionRect (r, [view frame]);
2037   ns_focus (f, &r, 1);
2038   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2040 #ifdef NS_IMPL_COCOA
2041   {
2042     /* clip out the resize handle */
2043     NSWindow *window = [FRAME_NS_VIEW (f) window];
2044     NSRect ir
2045       = [view convertRect: ns_resize_handle_rect (window) fromView: nil];
2047     ir = NSIntersectionRect (r, ir);
2048     if (NSIsEmptyRect (ir))
2049       {
2050 #endif
2052   NSRectFill (r);
2054 #ifdef NS_IMPL_COCOA
2055       }
2056     else
2057       {
2058         NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
2059         r1.size.height -= ir.size.height;
2060         r2.origin.y += r1.size.height;
2061         r2.size.width -= ir.size.width;
2062         r2.size.height = ir.size.height;
2063         NSRectFill (r1);
2064         NSRectFill (r2);
2065       }
2066   }
2067 #endif
2069   ns_unfocus (f);
2070   return;
2074 static void
2075 ns_scroll_run (struct window *w, struct run *run)
2076 /* --------------------------------------------------------------------------
2077     External (RIF):  Insert or delete n lines at line vpos
2078    -------------------------------------------------------------------------- */
2080   struct frame *f = XFRAME (w->frame);
2081   int x, y, width, height, from_y, to_y, bottom_y;
2083   NSTRACE (ns_scroll_run);
2085   /* begin copy from other terms */
2086   /* Get frame-relative bounding box of the text display area of W,
2087      without mode lines.  Include in this box the left and right
2088      fringe of W.  */
2089   window_box (w, -1, &x, &y, &width, &height);
2091   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2092   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2093   bottom_y = y + height;
2095   if (to_y < from_y)
2096     {
2097       /* Scrolling up.  Make sure we don't copy part of the mode
2098          line at the bottom.  */
2099       if (from_y + run->height > bottom_y)
2100         height = bottom_y - from_y;
2101       else
2102         height = run->height;
2103     }
2104   else
2105     {
2106       /* Scolling down.  Make sure we don't copy over the mode line.
2107          at the bottom.  */
2108       if (to_y + run->height > bottom_y)
2109         height = bottom_y - to_y;
2110       else
2111         height = run->height;
2112     }
2113   /* end copy from other terms */
2115   if (height == 0)
2116       return;
2118   BLOCK_INPUT;
2120   updated_window = w;
2121   x_clear_cursor (w);
2123   {
2124     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2125     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2126     NSPoint dstOrigin = NSMakePoint (x, to_y);
2128     ns_focus (f, &dstRect, 1);
2129     NSCopyBits (0, srcRect , dstOrigin);
2130     ns_unfocus (f);
2131   }
2133   UNBLOCK_INPUT;
2137 static void
2138 ns_after_update_window_line (struct glyph_row *desired_row)
2139 /* --------------------------------------------------------------------------
2140     External (RIF): preparatory to fringe update after text was updated
2141    -------------------------------------------------------------------------- */
2143   struct window *w = updated_window;
2144   struct frame *f;
2145   int width, height;
2147   NSTRACE (ns_after_update_window_line);
2149   /* begin copy from other terms */
2150   xassert (w);
2152   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2153     desired_row->redraw_fringe_bitmaps_p = 1;
2155   /* When a window has disappeared, make sure that no rest of
2156      full-width rows stays visible in the internal border.
2157      Under NS this is drawn inside the fringes. */
2158   if (windows_or_buffers_changed
2159       && (f = XFRAME (w->frame),
2160           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2161           width != 0)
2162       && (height = desired_row->visible_height,
2163           height > 0))
2164     {
2165       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2167       /* Internal border is drawn below the tool bar.  */
2168       if (WINDOWP (f->tool_bar_window)
2169           && w == XWINDOW (f->tool_bar_window))
2170         y -= width;
2171       /* end copy from other terms */
2173       BLOCK_INPUT;
2174       if (!desired_row->full_width_p)
2175         {
2176           int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2177             + WINDOW_LEFT_FRINGE_WIDTH (w);
2178           int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2179             + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
2180             - WINDOW_RIGHT_FRINGE_WIDTH (w)
2181             - FRAME_INTERNAL_BORDER_WIDTH (f);
2182           ns_clear_frame_area (f, x1, y, width, height);
2183           ns_clear_frame_area (f, x2, y, width, height);
2184         }
2185       UNBLOCK_INPUT;
2186     }
2190 static void
2191 ns_shift_glyphs_for_insert (struct frame *f,
2192                            int x, int y, int width, int height,
2193                            int shift_by)
2194 /* --------------------------------------------------------------------------
2195     External (RIF): copy an area horizontally, don't worry about clearing src
2196    -------------------------------------------------------------------------- */
2198   NSRect srcRect = NSMakeRect (x, y, width, height);
2199   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2200   NSPoint dstOrigin = dstRect.origin;
2202   NSTRACE (ns_shift_glyphs_for_insert);
2204   ns_focus (f, &dstRect, 1);
2205   NSCopyBits (0, srcRect, dstOrigin);
2206   ns_unfocus (f);
2211 /* ==========================================================================
2213     Character encoding and metrics
2215    ========================================================================== */
2218 static inline void
2219 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2220 /* --------------------------------------------------------------------------
2221      External (RIF); compute left/right overhang of whole string and set in s
2222    -------------------------------------------------------------------------- */
2224   struct face *face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2225   struct font *font = s->font; /*face->font; */
2227   if (s->char2b)
2228     {
2229       struct font_metrics metrics;
2230       unsigned int codes[2];
2231       codes[0] = *(s->char2b);
2232       codes[1] = *(s->char2b + s->nchars - 1);
2234       font->driver->text_extents (font, codes, 2, &metrics);
2235       s->left_overhang = -metrics.lbearing;
2236       s->right_overhang
2237         = metrics.rbearing > metrics.width
2238         ? metrics.rbearing - metrics.width : 0;
2239     }
2240   else
2241     {
2242       s->left_overhang = 0;
2243       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2244         FONT_HEIGHT (font) * 0.2 : 0;
2245     }
2250 /* ==========================================================================
2252     Fringe and cursor drawing
2254    ========================================================================== */
2257 extern int max_used_fringe_bitmap;
2258 static void
2259 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2260                       struct draw_fringe_bitmap_params *p)
2261 /* --------------------------------------------------------------------------
2262     External (RIF); fringe-related
2263    -------------------------------------------------------------------------- */
2265   struct frame *f = XFRAME (WINDOW_FRAME (w));
2266   struct face *face = p->face;
2267   int rowY;
2268   static EmacsImage **bimgs = NULL;
2269   static int nBimgs = 0;
2270   /* NS-specific: move internal border inside fringe */
2271   int x = p->bx < 0 ? p->x : p->bx;
2272   int wd = p->bx < 0 ? p->wd : p->nx;
2273   BOOL fringeOnVeryLeft
2274     = x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
2275       - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
2276   BOOL fringeOnVeryRight
2277     = FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
2278       - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
2279   int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
2280     (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
2282   /* grow bimgs if needed */
2283   if (nBimgs < max_used_fringe_bitmap)
2284     {
2285       EmacsImage **newBimgs
2286         = xmalloc (max_used_fringe_bitmap * sizeof (EmacsImage *));
2287       memset (newBimgs, 0, max_used_fringe_bitmap * sizeof (EmacsImage *));
2289       if (nBimgs)
2290         {
2291           memcpy (newBimgs, bimgs, nBimgs * sizeof (EmacsImage *));
2292           xfree (bimgs);
2293         }
2295       bimgs = newBimgs;
2296       nBimgs = max_used_fringe_bitmap;
2297     }
2299   /* Must clip because of partially visible lines.  */
2300   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2301   ns_clip_to_row (w, row, -1, YES);
2303   if (p->bx >= 0 && !p->overlay_p)
2304     {
2305       int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
2306         -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2307       int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
2308         FRAME_INTERNAL_BORDER_WIDTH (f) : 0
2309         + (yAdjust ? FRAME_INTERNAL_BORDER_WIDTH (f) : 0);
2310       NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
2311       NSRectClip (r);
2312       [ns_lookup_indexed_color(face->background, f) set];
2313       NSRectFill (r);
2314     }
2316   if (p->which)
2317     {
2318       NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
2319       NSPoint pt = r.origin;
2320       EmacsImage *img = bimgs[p->which - 1];
2322       if (!img)
2323         {
2324           unsigned short *bits = p->bits + p->dh;
2325           int len = 8 * p->h/8;
2326           int i;
2327           unsigned char *cbits = xmalloc (len);
2329           for (i =0; i<len; i++)
2330             cbits[i] = ~(bits[i] & 0xff);
2331           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2332                                            flip: NO];
2333           bimgs[p->which - 1] = img;
2334           xfree (cbits);
2335         }
2337       NSRectClip (r);
2338       /* Since we composite the bitmap instead of just blitting it, we need
2339          to erase the whole background. */
2340       [ns_lookup_indexed_color(face->background, f) set];
2341       NSRectFill (r);
2342       pt.y += p->h;
2343       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2344       [img compositeToPoint: pt operation: NSCompositeSourceOver];
2345     }
2346   ns_unfocus (f);
2350 void
2351 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2352                        int x, int y, int cursor_type, int cursor_width,
2353                        int on_p, int active_p)
2354 /* --------------------------------------------------------------------------
2355      External call (RIF): draw cursor.
2356      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2357    -------------------------------------------------------------------------- */
2359   NSRect r, s;
2360   int fx, fy, h, cursor_height;
2361   struct frame *f = WINDOW_XFRAME (w);
2362   struct glyph *phys_cursor_glyph;
2363   int overspill;
2364   struct glyph *cursor_glyph;
2365   struct face *face;
2366   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2368   /* If cursor is out of bounds, don't draw garbage.  This can happen
2369      in mini-buffer windows when switching between echo area glyphs
2370      and mini-buffer.  */
2372   NSTRACE (dumpcursor);
2374   if (!on_p)
2375     return;
2377   w->phys_cursor_type = cursor_type;
2378   w->phys_cursor_on_p = on_p;
2380   if (cursor_type == NO_CURSOR)
2381     {
2382       w->phys_cursor_width = 0;
2383       return;
2384     }
2386   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2387     {
2388       if (glyph_row->exact_window_width_line_p
2389           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2390         {
2391           glyph_row->cursor_in_fringe_p = 1;
2392           draw_fringe_bitmap (w, glyph_row, 0);
2393         }
2394       return;
2395     }
2397   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2398      (other terminals do it the other way round).  We must set
2399      w->phys_cursor_width to the cursor width.  For bar cursors, that
2400      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2401   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2403   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2404      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2405   if (cursor_type == BAR_CURSOR)
2406     {
2407       if (cursor_width < 1)
2408         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2409       w->phys_cursor_width = cursor_width;
2410     }
2411   /* If we have an HBAR, "cursor_width" MAY specify height. */
2412   else if (cursor_type == HBAR_CURSOR)
2413     {
2414       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2415       fy += h - cursor_height;
2416       h = cursor_height;
2417     }
2419   r.origin.x = fx, r.origin.y = fy;
2420   r.size.height = h;
2421   r.size.width = w->phys_cursor_width;
2423   /* FIXME: if we overwrite the internal border area, it does not get erased;
2424      fix by truncating cursor, but better would be to erase properly */
2425   overspill = r.origin.x + r.size.width -
2426     WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w)
2427       - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
2428   if (overspill > 0)
2429     r.size.width -= overspill;
2431   /* TODO: only needed in rare cases with last-resort font in HELLO..
2432      should we do this more efficiently? */
2433   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2436   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2437   if (face && NS_FACE_BACKGROUND (face)
2438       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2439     {
2440       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2441       hollow_color = FRAME_CURSOR_COLOR (f);
2442     }
2443   else
2444     [FRAME_CURSOR_COLOR (f) set];
2446 #ifdef NS_IMPL_COCOA
2447   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2448            atomic.  Cleaner ways of doing this should be investigated.
2449            One way would be to set a global variable DRAWING_CURSOR
2450            when making the call to draw_phys..(), don't focus in that
2451            case, then move the ns_unfocus() here after that call. */
2452   NSDisableScreenUpdates ();
2453 #endif
2455   switch (cursor_type)
2456     {
2457     case NO_CURSOR:
2458       break;
2459     case FILLED_BOX_CURSOR:
2460       NSRectFill (r);
2461       break;
2462     case HOLLOW_BOX_CURSOR:
2463       NSRectFill (r);
2464       [hollow_color set];
2465       NSRectFill (NSInsetRect (r, 1, 1));
2466       [FRAME_CURSOR_COLOR (f) set];
2467       break;
2468     case HBAR_CURSOR:
2469       NSRectFill (r);
2470       break;
2471     case BAR_CURSOR:
2472       s = r;
2473       /* If the character under cursor is R2L, draw the bar cursor
2474          on the right of its glyph, rather than on the left.  */
2475       cursor_glyph = get_phys_cursor_glyph (w);
2476       if ((cursor_glyph->resolved_level & 1) != 0)
2477         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2479       NSRectFill (s);
2480       break;
2481     }
2482   ns_unfocus (f);
2484   /* draw the character under the cursor */
2485   if (cursor_type != NO_CURSOR)
2486     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2488 #ifdef NS_IMPL_COCOA
2489   NSEnableScreenUpdates ();
2490 #endif
2495 static void
2496 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2497 /* --------------------------------------------------------------------------
2498      External (RIF): Draw a vertical line.
2499    -------------------------------------------------------------------------- */
2501   struct frame *f = XFRAME (WINDOW_FRAME (w));
2502   struct face *face;
2503   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2505   NSTRACE (ns_draw_vertical_window_border);
2507   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2508   if (face)
2509       [ns_lookup_indexed_color(face->foreground, f) set];
2511   ns_focus (f, &r, 1);
2512   NSRectFill(r);
2513   ns_unfocus (f);
2517 void
2518 show_hourglass (struct atimer *timer)
2520   if (hourglass_shown_p)
2521     return;
2523   BLOCK_INPUT;
2525   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2527   hourglass_shown_p = 1;
2528   UNBLOCK_INPUT;
2532 void
2533 hide_hourglass (void)
2535   if (!hourglass_shown_p)
2536     return;
2538   BLOCK_INPUT;
2540   /* TODO: remove NSProgressIndicator from all frames */
2542   hourglass_shown_p = 0;
2543   UNBLOCK_INPUT;
2548 /* ==========================================================================
2550     Glyph drawing operations
2552    ========================================================================== */
2555 static inline NSRect
2556 ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
2557 /* --------------------------------------------------------------------------
2558     Under NS we draw internal borders inside fringes, and want full-width
2559     rendering to go all the way to edge.  This function makes that correction.
2560    -------------------------------------------------------------------------- */
2562   if (r.origin.y <= fibw+1)
2563     {
2564       r.size.height += r.origin.y;
2565       r.origin.y = 0;
2566     }
2567   if (r.origin.x <= fibw+1)
2568     {
2569       r.size.width += r.origin.x;
2570       r.origin.x = 0;
2571     }
2572   if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
2573     r.size.width += fibw;
2575   return r;
2579 static int
2580 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2581 /* --------------------------------------------------------------------------
2582     Wrapper utility to account for internal border width on full-width lines,
2583     and allow top full-width rows to hit the frame top.  nr should be pointer
2584     to two successive NSRects.  Number of rects actually used is returned.
2585    -------------------------------------------------------------------------- */
2587   int n = get_glyph_string_clip_rects (s, nr, 2);
2588   if (s->row->full_width_p)
2589     {
2590       *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2591                             FRAME_PIXEL_WIDTH (s->f));
2592       if (n == 2)
2593         *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
2594                               FRAME_PIXEL_WIDTH (s->f));
2595     }
2596   return n;
2600 static void
2601 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2602 /* --------------------------------------------------------------------------
2603     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2604     Note we can't just use an NSDrawRect command, because of the possibility
2605     of some sides not being drawn, and because the rect will be filled.
2606    -------------------------------------------------------------------------- */
2608   NSRect s = r;
2609   [col set];
2611   /* top, bottom */
2612   s.size.height = thickness;
2613   NSRectFill (s);
2614   s.origin.y += r.size.height - thickness;
2615   NSRectFill (s);
2617   s.size.height = r.size.height;
2618   s.origin.y = r.origin.y;
2620   /* left, right (optional) */
2621   s.size.width = thickness;
2622   if (left_p)
2623     NSRectFill (s);
2624   if (right_p)
2625     {
2626       s.origin.x += r.size.width - thickness;
2627       NSRectFill (s);
2628     }
2632 static void
2633 ns_draw_relief (NSRect r, int thickness, char raised_p,
2634                char top_p, char bottom_p, char left_p, char right_p,
2635                struct glyph_string *s)
2636 /* --------------------------------------------------------------------------
2637     Draw a relief rect inside r, optionally leaving some sides open.
2638     Note we can't just use an NSDrawBezel command, because of the possibility
2639     of some sides not being drawn, and because the rect will be filled.
2640    -------------------------------------------------------------------------- */
2642   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2643   NSColor *newBaseCol = nil;
2644   NSRect sr = r;
2646   NSTRACE (ns_draw_relief);
2648   /* set up colors */
2650   if (s->face->use_box_color_for_shadows_p)
2651     {
2652       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2653     }
2654 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2655            && s->img->pixmap
2656            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2657        {
2658          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2659        } */
2660   else
2661     {
2662       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2663     }
2665   if (newBaseCol == nil)
2666     newBaseCol = [NSColor grayColor];
2668   if (newBaseCol != baseCol)  /* TODO: better check */
2669     {
2670       [baseCol release];
2671       baseCol = [newBaseCol retain];
2672       [lightCol release];
2673       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2674       [darkCol release];
2675       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2676     }
2678   [(raised_p ? lightCol : darkCol) set];
2680   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2682   /* top */
2683   sr.size.height = thickness;
2684   if (top_p) NSRectFill (sr);
2686   /* left */
2687   sr.size.height = r.size.height;
2688   sr.size.width = thickness;
2689   if (left_p) NSRectFill (sr);
2691   [(raised_p ? darkCol : lightCol) set];
2693   /* bottom */
2694   sr.size.width = r.size.width;
2695   sr.size.height = thickness;
2696   sr.origin.y += r.size.height - thickness;
2697   if (bottom_p) NSRectFill (sr);
2699   /* right */
2700   sr.size.height = r.size.height;
2701   sr.origin.y = r.origin.y;
2702   sr.size.width = thickness;
2703   sr.origin.x += r.size.width - thickness;
2704   if (right_p) NSRectFill (sr);
2708 static void
2709 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2710 /* --------------------------------------------------------------------------
2711       Function modeled after x_draw_glyph_string_box ().
2712       Sets up parameters for drawing.
2713    -------------------------------------------------------------------------- */
2715   int right_x, last_x;
2716   char left_p, right_p;
2717   struct glyph *last_glyph;
2718   NSRect r;
2719   int thickness;
2720   struct face *face;
2722   if (s->hl == DRAW_MOUSE_FACE)
2723     {
2724       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2725       if (!face)
2726         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2727     }
2728   else
2729     face = s->face;
2731   thickness = face->box_line_width;
2733   NSTRACE (ns_dumpglyphs_box_or_relief);
2735   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2736             ? WINDOW_RIGHT_EDGE_X (s->w)
2737             : window_box_right (s->w, s->area));
2738   last_glyph = (s->cmp || s->img
2739                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2741   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2742               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2744   left_p = (s->first_glyph->left_box_line_p
2745             || (s->hl == DRAW_MOUSE_FACE
2746                 && (s->prev == NULL || s->prev->hl != s->hl)));
2747   right_p = (last_glyph->right_box_line_p
2748              || (s->hl == DRAW_MOUSE_FACE
2749                  && (s->next == NULL || s->next->hl != s->hl)));
2751   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2753   /* expand full-width row over internal borders */
2754   if (s->row->full_width_p)
2755     r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2756                         FRAME_PIXEL_WIDTH (s->f));
2758   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2759   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2760     {
2761       ns_draw_box (r, abs (thickness),
2762                    ns_lookup_indexed_color (face->box_color, s->f),
2763                   left_p, right_p);
2764     }
2765   else
2766     {
2767       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2768                      1, 1, left_p, right_p, s);
2769     }
2773 static void
2774 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2775 /* --------------------------------------------------------------------------
2776       Modeled after x_draw_glyph_string_background, which draws BG in
2777       certain cases.  Others are left to the text rendering routine.
2778    -------------------------------------------------------------------------- */
2780   NSTRACE (ns_maybe_dumpglyphs_background);
2782   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2783     {
2784       int box_line_width = max (s->face->box_line_width, 0);
2785       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2786           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2787         {
2788           struct face *face;
2789           if (s->hl == DRAW_MOUSE_FACE)
2790             {
2791               face = FACE_FROM_ID (s->f,
2792                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2793               if (!face)
2794                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2795             }
2796           else
2797             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2798           if (!face->stipple)
2799             [(NS_FACE_BACKGROUND (face) != 0
2800               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2801               : FRAME_BACKGROUND_COLOR (s->f)) set];
2802           else
2803             {
2804               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2805               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2806             }
2808           if (s->hl != DRAW_CURSOR)
2809             {
2810               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2811                                     s->background_width,
2812                                     s->height-2*box_line_width);
2814               /* expand full-width row over internal borders */
2815               if (s->row->full_width_p)
2816                 {
2817                   int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2818                   if (r.origin.y <= fibw+1 + box_line_width)
2819                     {
2820                       r.size.height += r.origin.y;
2821                       r.origin.y = 0;
2822                     }
2823                   if (r.origin.x <= fibw+1)
2824                     {
2825                       r.size.width += 2*r.origin.x;
2826                       r.origin.x = 0;
2827                     }
2828                   if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2829                       <= fibw+1)
2830                     r.size.width += fibw;
2831                 }
2833               NSRectFill (r);
2834             }
2836           s->background_filled_p = 1;
2837         }
2838     }
2842 static void
2843 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2844 /* --------------------------------------------------------------------------
2845       Renders an image and associated borders.
2846    -------------------------------------------------------------------------- */
2848   EmacsImage *img = s->img->pixmap;
2849   int box_line_vwidth = max (s->face->box_line_width, 0);
2850   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2851   int bg_x, bg_y, bg_height;
2852   int th;
2853   char raised_p;
2854   NSRect br;
2855   struct face *face;
2857   NSTRACE (ns_dumpglyphs_image);
2859   if (s->face->box != FACE_NO_BOX
2860       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2861     x += abs (s->face->box_line_width);
2863   bg_x = x;
2864   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2865   bg_height = s->height;
2866   /* other terms have this, but was causing problems w/tabbar mode */
2867   /* - 2 * box_line_vwidth; */
2869   if (s->slice.x == 0) x += s->img->hmargin;
2870   if (s->slice.y == 0) y += s->img->vmargin;
2872   /* Draw BG: if we need larger area than image itself cleared, do that,
2873      otherwise, since we composite the image under NS (instead of mucking
2874      with its background color), we must clear just the image area. */
2875   if (s->hl == DRAW_MOUSE_FACE)
2876     {
2877       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2878       if (!face)
2879        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2880     }
2881   else
2882     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2884   if (s->hl == DRAW_CURSOR)
2885       [FRAME_CURSOR_COLOR (s->f) set];
2886   else
2887     [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2889   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2890       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2891     {
2892       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2893       s->background_filled_p = 1;
2894     }
2895   else
2896     {
2897       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2898     }
2900   /* expand full-width row over internal borders */
2901   if (s->row->full_width_p)
2902     {
2903       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2904       if (br.origin.y <= fibw+1 + box_line_vwidth)
2905         {
2906           br.size.height += br.origin.y;
2907           br.origin.y = 0;
2908         }
2909       if (br.origin.x <= fibw+1 + box_line_vwidth)
2910         {
2911           br.size.width += br.origin.x;
2912           br.origin.x = 0;
2913         }
2914       if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
2915         br.size.width += fibw;
2916     }
2918   NSRectFill (br);
2920   /* Draw the image.. do we need to draw placeholder if img ==nil? */
2921   if (img != nil)
2922     [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
2923                 operation: NSCompositeSourceOver];
2925   /* Draw relief, if requested */
2926   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
2927     {
2928       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
2929         {
2930           th = tool_bar_button_relief >= 0 ?
2931             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
2932           raised_p = (s->hl == DRAW_IMAGE_RAISED);
2933         }
2934       else
2935         {
2936           th = abs (s->img->relief);
2937           raised_p = (s->img->relief > 0);
2938         }
2940       r.origin.x = x - th;
2941       r.origin.y = y - th;
2942       r.size.width = s->slice.width + 2*th-1;
2943       r.size.height = s->slice.height + 2*th-1;
2944       ns_draw_relief (r, th, raised_p,
2945                       s->slice.y == 0,
2946                       s->slice.y + s->slice.height == s->img->height,
2947                       s->slice.x == 0,
2948                       s->slice.x + s->slice.width == s->img->width, s);
2949     }
2951   /* If there is no mask, the background won't be seen,
2952      so draw a rectangle on the image for the cursor.
2953      Do this for all images, getting trancparency right is not reliable.  */
2954   if (s->hl == DRAW_CURSOR)
2955     {
2956       int thickness = abs (s->img->relief);
2957       if (thickness == 0) thickness = 1;
2958       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
2959     }
2963 static void
2964 ns_dumpglyphs_stretch (struct glyph_string *s)
2966   NSRect r[2];
2967   int n, i;
2968   struct face *face;
2970   if (!s->background_filled_p)
2971     {
2972       n = ns_get_glyph_string_clip_rect (s, r);
2973       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
2975       for (i=0; i<n; i++)
2976         {
2977           if (!s->row->full_width_p)
2978             {
2979               /* truncate to avoid overwriting fringe and/or scrollbar */
2980               int overrun = max (0, (s->x + s->background_width)
2981                                   - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
2982                                     - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
2983               r[i].size.width -= overrun;
2985               /* XXX: Try to work between problem where a stretch glyph on
2986                  a partially-visible bottom row will clear part of the
2987                  modeline, and another where list-buffers headers and similar
2988                  rows erroneously have visible_height set to 0.  Not sure
2989                  where this is coming from as other terms seem not to show. */
2990               r[i].size.height = min (s->height, s->row->visible_height);
2991             }
2993           /* expand full-width rows over internal borders */
2994           else
2995             {
2996               r[i] = ns_fix_rect_ibw (r[i], FRAME_INTERNAL_BORDER_WIDTH (s->f),
2997                                       FRAME_PIXEL_WIDTH (s->f));
2998             }
3000           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3001              overwriting cursor (usually when cursor on a tab) */
3002           if (s->hl == DRAW_CURSOR)
3003             {
3004               r[i].origin.x += s->width;
3005               r[i].size.width -= s->width;
3006             }
3007         }
3009       ns_focus (s->f, r, n);
3011       if (s->hl == DRAW_MOUSE_FACE)
3012        {
3013          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3014          if (!face)
3015            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3016        }
3017       else
3018        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3020       [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3022       NSRectFill (r[0]);
3023       NSRectFill (r[1]);
3024       ns_unfocus (s->f);
3025       s->background_filled_p = 1;
3026     }
3030 static void
3031 ns_draw_glyph_string (struct glyph_string *s)
3032 /* --------------------------------------------------------------------------
3033       External (RIF): Main draw-text call.
3034    -------------------------------------------------------------------------- */
3036   /* TODO (optimize): focus for box and contents draw */
3037   NSRect r[2];
3038   int n;
3039   char box_drawn_p = 0;
3041   NSTRACE (ns_draw_glyph_string);
3043   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3044     {
3045       int width;
3046       struct glyph_string *next;
3048       for (width = 0, next = s->next;
3049            next && width < s->right_overhang;
3050            width += next->width, next = next->next)
3051         if (next->first_glyph->type != IMAGE_GLYPH)
3052           {
3053             if (next->first_glyph->type != STRETCH_GLYPH)
3054               {
3055                 n = ns_get_glyph_string_clip_rect (s->next, r);
3056                 ns_focus (s->f, r, n);
3057                 ns_maybe_dumpglyphs_background (s->next, 1);
3058                 ns_unfocus (s->f);
3059               }
3060             else
3061               {
3062                 ns_dumpglyphs_stretch (s->next);
3063               }
3064             next->num_clips = 0;
3065           }
3066     }
3068   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3069         && (s->first_glyph->type == CHAR_GLYPH
3070             || s->first_glyph->type == COMPOSITE_GLYPH))
3071     {
3072       n = ns_get_glyph_string_clip_rect (s, r);
3073       ns_focus (s->f, r, n);
3074       ns_maybe_dumpglyphs_background (s, 1);
3075       ns_dumpglyphs_box_or_relief (s);
3076       ns_unfocus (s->f);
3077       box_drawn_p = 1;
3078     }
3080   switch (s->first_glyph->type)
3081     {
3083     case IMAGE_GLYPH:
3084       n = ns_get_glyph_string_clip_rect (s, r);
3085       ns_focus (s->f, r, n);
3086       ns_dumpglyphs_image (s, r[0]);
3087       ns_unfocus (s->f);
3088       break;
3090     case STRETCH_GLYPH:
3091       ns_dumpglyphs_stretch (s);
3092       break;
3094     case CHAR_GLYPH:
3095     case COMPOSITE_GLYPH:
3096       n = ns_get_glyph_string_clip_rect (s, r);
3097       ns_focus (s->f, r, n);
3099       if (s->for_overlaps || (s->cmp_from > 0
3100                               && ! s->first_glyph->u.cmp.automatic))
3101         s->background_filled_p = 1;
3102       else
3103         ns_maybe_dumpglyphs_background
3104           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3106       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3107                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3108                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3109                       NS_DUMPGLYPH_NORMAL));
3110       ns_tmp_font = (struct nsfont_info *)s->face->font;
3111       if (ns_tmp_font == NULL)
3112           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3114       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3115         {
3116           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3117           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3118           NS_FACE_FOREGROUND (s->face) = tmp;
3119         }
3121       ns_tmp_font->font.driver->draw
3122         (s, 0, s->nchars, s->x, s->y,
3123          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3124          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3126       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3127         {
3128           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3129           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3130           NS_FACE_FOREGROUND (s->face) = tmp;
3131         }
3133       ns_unfocus (s->f);
3134       break;
3136     case GLYPHLESS_GLYPH:
3137       n = ns_get_glyph_string_clip_rect (s, r);
3138       ns_focus (s->f, r, n);
3140       if (s->for_overlaps || (s->cmp_from > 0
3141                               && ! s->first_glyph->u.cmp.automatic))
3142         s->background_filled_p = 1;
3143       else
3144         ns_maybe_dumpglyphs_background
3145           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3146       /* ... */
3147       /* Not yet implemented.  */
3148       /* ... */
3149       ns_unfocus (s->f);
3150       break;
3152     default:
3153       abort ();
3154     }
3156   /* Draw box if not done already. */
3157   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3158     {
3159       n = ns_get_glyph_string_clip_rect (s, r);
3160       ns_focus (s->f, r, n);
3161       ns_dumpglyphs_box_or_relief (s);
3162       ns_unfocus (s->f);
3163     }
3165   s->num_clips = 0;
3170 /* ==========================================================================
3172     Event loop
3174    ========================================================================== */
3177 static void
3178 ns_send_appdefined (int value)
3179 /* --------------------------------------------------------------------------
3180     Internal: post an appdefined event which EmacsApp-sendEvent will
3181               recognize and take as a command to halt the event loop.
3182    -------------------------------------------------------------------------- */
3184   /*NSTRACE (ns_send_appdefined); */
3186   /* Only post this event if we haven't already posted one.  This will end
3187        the [NXApp run] main loop after having processed all events queued at
3188        this moment.  */
3189   if (send_appdefined)
3190     {
3191       NSEvent *nxev;
3193       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3194       send_appdefined = NO;
3196       /* Don't need wakeup timer any more */
3197       if (timed_entry)
3198         {
3199           [timed_entry invalidate];
3200           [timed_entry release];
3201           timed_entry = nil;
3202         }
3204       /* Ditto for file descriptor poller */
3205       if (fd_entry)
3206         {
3207           [fd_entry invalidate];
3208           [fd_entry release];
3209           fd_entry = nil;
3210         }
3212       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3213                                 location: NSMakePoint (0, 0)
3214                            modifierFlags: 0
3215                                timestamp: 0
3216                             windowNumber: [[NSApp mainWindow] windowNumber]
3217                                  context: [NSApp context]
3218                                  subtype: 0
3219                                    data1: value
3220                                    data2: 0];
3222       /* Post an application defined event on the event queue.  When this is
3223          received the [NXApp run] will return, thus having processed all
3224          events which are currently queued.  */
3225       [NSApp postEvent: nxev atStart: NO];
3226     }
3230 static int
3231 ns_read_socket (struct terminal *terminal, int expected,
3232                 struct input_event *hold_quit)
3233 /* --------------------------------------------------------------------------
3234      External (hook): Post an event to ourself and keep reading events until
3235      we read it back again.  In effect process all events which were waiting.
3236      From 21+ we have to manage the event buffer ourselves.
3237    -------------------------------------------------------------------------- */
3239   struct input_event ev;
3240   int nevents;
3242 /* NSTRACE (ns_read_socket); */
3244   if (interrupt_input_blocked)
3245     {
3246       interrupt_input_pending = 1;
3247 #ifdef SYNC_INPUT
3248       pending_signals = 1;
3249 #endif
3250       return -1;
3251     }
3253   interrupt_input_pending = 0;
3254 #ifdef SYNC_INPUT
3255   pending_signals = pending_atimers;
3256 #endif
3258   BLOCK_INPUT;
3259   n_emacs_events_pending = 0;
3260   EVENT_INIT (ev);
3261   emacs_event = &ev;
3262   q_event_ptr = hold_quit;
3264   /* we manage autorelease pools by allocate/reallocate each time around
3265      the loop; strict nesting is occasionally violated but seems not to
3266      matter.. earlier methods using full nesting caused major memory leaks */
3267   [outerpool release];
3268   outerpool = [[NSAutoreleasePool alloc] init];
3270   /* If have pending open-file requests, attend to the next one of those. */
3271   if (ns_pending_files && [ns_pending_files count] != 0
3272       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3273     {
3274       [ns_pending_files removeObjectAtIndex: 0];
3275     }
3276   /* Deal with pending service requests. */
3277   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3278     && [(EmacsApp *)
3279          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3280                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3281     {
3282       [ns_pending_service_names removeObjectAtIndex: 0];
3283       [ns_pending_service_args removeObjectAtIndex: 0];
3284     }
3285   else
3286     {
3287       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3288          to ourself, otherwise [NXApp run] will never exit.  */
3289       send_appdefined = YES;
3291       /* If called via ns_select, this is called once with expected=1,
3292          because we expect either the timeout or file descriptor activity.
3293          In this case the first event through will either be real input or
3294          one of these.  read_avail_input() then calls once more with expected=0
3295          and in that case we need to return quickly if there is nothing.
3296          If we're being called outside of that, it's also OK to return quickly
3297          after one iteration through the event loop, since other terms do
3298          this and emacs expects it. */
3299       if (!(inNsSelect && expected))
3300         {
3301           /* Post an application defined event on the event queue.  When this is
3302              received the [NXApp run] will return, thus having processed all
3303              events which are currently queued, if any.  */
3304           ns_send_appdefined (-1);
3305         }
3307       [NSApp run];
3308     }
3310   nevents = n_emacs_events_pending;
3311   n_emacs_events_pending = 0;
3312   emacs_event = q_event_ptr = NULL;
3313   UNBLOCK_INPUT;
3315   return nevents;
3320 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3321            fd_set *exceptfds, struct timeval *timeout)
3322 /* --------------------------------------------------------------------------
3323      Replacement for select, checking for events
3324    -------------------------------------------------------------------------- */
3326   int result;
3327   double time;
3328   NSEvent *ev;
3329 /*  NSTRACE (ns_select); */
3331   if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO &&
3332                       [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
3333  inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
3334     return select (nfds, readfds, writefds, exceptfds, timeout);
3336   /* Save file descriptor set, which gets overwritten in calls to select ()
3337      Note, this is called from process.c, and only readfds is ever set */
3338   if (readfds)
3339     {
3340       memcpy (&select_readfds, readfds, sizeof (fd_set));
3341       select_nfds = nfds;
3342     }
3343   else
3344     select_nfds = 0;
3346     /* Try an initial select for pending data on input files */
3347   select_timeout.tv_sec = select_timeout.tv_usec = 0;
3348   result = select (nfds, readfds, writefds, exceptfds, &select_timeout);
3349   if (result)
3350     return result;
3352   /* if (!timeout || timed_entry || fd_entry)
3353        fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
3355     /* set a timeout and run the main AppKit event loop while continuing
3356        to monitor the files */
3357   time = ((double) timeout->tv_sec) + ((double) timeout->tv_usec)/1000000.0;
3358   timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3359                                            target: NSApp
3360                                          selector: @selector (timeout_handler:)
3361                                          userInfo: 0
3362                                           repeats: YES] /* for safe removal */
3363                                                          retain];
3365   /* set a periodic task to try the select () again */
3366   fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
3367                                                target: NSApp
3368                                              selector: @selector (fd_handler:)
3369                                              userInfo: 0
3370                                               repeats: YES]
3371                retain];
3373   /* Let Application dispatch events until it receives an event of the type
3374      NX_APPDEFINED, which should only be sent by timeout_handler.
3375      We tell read_avail_input() that input is "expected" because we do expect
3376      either the timeout or fd handler to fire, and if they don't, the original
3377      call from process.c that got us here expects us to wait until some input
3378      comes. */
3379   inNsSelect = 1;
3380   gobble_input (1);
3381   ev = last_appdefined_event;
3382   inNsSelect = 0;
3384   if (ev)
3385     {
3386       int t;
3387       if ([ev type] != NSApplicationDefined)
3388         abort ();
3390       t = [ev data1];
3391       last_appdefined_event = 0;
3393       if (t == -2)
3394         {
3395           /* The NX_APPDEFINED event we received was a timeout. */
3396           return 0;
3397         }
3398       else if (t == -1)
3399         {
3400           /* The NX_APPDEFINED event we received was the result of
3401              at least one real input event arriving.  */
3402           errno = EINTR;
3403           return -1;
3404         }
3405       else
3406         {
3407           /* Received back from select () in fd_handler; copy the results */
3408           if (readfds)
3409             memcpy (readfds, &select_readfds, sizeof (fd_set));
3410           return t;
3411         }
3412     }
3413   /* never reached, shut compiler up */
3414   return 0;
3419 /* ==========================================================================
3421     Scrollbar handling
3423    ========================================================================== */
3426 static void
3427 ns_set_vertical_scroll_bar (struct window *window,
3428                            int portion, int whole, int position)
3429 /* --------------------------------------------------------------------------
3430       External (hook): Update or add scrollbar
3431    -------------------------------------------------------------------------- */
3433   Lisp_Object win;
3434   NSRect r, v;
3435   struct frame *f = XFRAME (WINDOW_FRAME (window));
3436   EmacsView *view = FRAME_NS_VIEW (f);
3437   int window_y, window_height;
3438   BOOL barOnVeryLeft, barOnVeryRight;
3439   int top, left, height, width, sb_width, sb_left;
3440   EmacsScroller *bar;
3441 static int count = 0;
3443   /* optimization; display engine sends WAY too many of these.. */
3444   if (!NILP (window->vertical_scroll_bar))
3445     {
3446       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3447       if ([bar checkSamePosition: position portion: portion whole: whole])
3448         {
3449           if (view->scrollbarsNeedingUpdate == 0)
3450             {
3451               if (!windows_or_buffers_changed)
3452                   return;
3453             }
3454           else
3455             view->scrollbarsNeedingUpdate--;
3456         }
3457     }
3459   NSTRACE (ns_set_vertical_scroll_bar);
3461   /* Get dimensions.  */
3462   window_box (window, -1, 0, &window_y, 0, &window_height);
3463   top = window_y;
3464   height = window_height;
3465   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3466   left = WINDOW_SCROLL_BAR_AREA_X (window);
3468   if (top < 5) /* top scrollbar adjustment */
3469     {
3470       top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3471       height += FRAME_INTERNAL_BORDER_WIDTH (f);
3472     }
3474   /* allow for displaying a skinnier scrollbar than char area allotted */
3475   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3476     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3478   barOnVeryLeft = left < 5;
3479   barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3480   sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3481       * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3483   r = NSMakeRect (sb_left, top, sb_width, height);
3484   /* the parent view is flipped, so we need to flip y value */
3485   v = [view frame];
3486   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3488   XSETWINDOW (win, window);
3489   BLOCK_INPUT;
3491   /* we want at least 5 lines to display a scrollbar */
3492   if (WINDOW_TOTAL_LINES (window) < 5)
3493     {
3494       if (!NILP (window->vertical_scroll_bar))
3495         {
3496           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3497           [bar removeFromSuperview];
3498           window->vertical_scroll_bar = Qnil;
3499         }
3500       ns_clear_frame_area (f, sb_left, top, width, height);
3501       UNBLOCK_INPUT;
3502       return;
3503     }
3505   if (NILP (window->vertical_scroll_bar))
3506     {
3507       ns_clear_frame_area (f, sb_left, top, width, height);
3508       bar = [[EmacsScroller alloc] initFrame: r window: win];
3509       window->vertical_scroll_bar = make_save_value (bar, 0);
3510     }
3511   else
3512     {
3513       NSRect oldRect;
3514       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3515       oldRect = [bar frame];
3516       r.size.width = oldRect.size.width;
3517       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3518         {
3519           if (oldRect.origin.x != r.origin.x)
3520               ns_clear_frame_area (f, sb_left, top, width, height);
3521           [bar setFrame: r];
3522         }
3523     }
3525   [bar setPosition: position portion: portion whole: whole];
3526   UNBLOCK_INPUT;
3530 static void
3531 ns_condemn_scroll_bars (struct frame *f)
3532 /* --------------------------------------------------------------------------
3533      External (hook): arrange for all frame's scrollbars to be removed
3534      at next call to judge_scroll_bars, except for those redeemed.
3535    -------------------------------------------------------------------------- */
3537   int i;
3538   id view;
3539   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3541   NSTRACE (ns_condemn_scroll_bars);
3543   for (i =[subviews count]-1; i >= 0; i--)
3544     {
3545       view = [subviews objectAtIndex: i];
3546       if ([view isKindOfClass: [EmacsScroller class]])
3547         [view condemn];
3548     }
3552 static void
3553 ns_redeem_scroll_bar (struct window *window)
3554 /* --------------------------------------------------------------------------
3555      External (hook): arrange to spare this window's scrollbar
3556      at next call to judge_scroll_bars.
3557    -------------------------------------------------------------------------- */
3559   id bar;
3560   NSTRACE (ns_redeem_scroll_bar);
3561   if (!NILP (window->vertical_scroll_bar))
3562     {
3563       bar =XNS_SCROLL_BAR (window->vertical_scroll_bar);
3564       [bar reprieve];
3565     }
3569 static void
3570 ns_judge_scroll_bars (struct frame *f)
3571 /* --------------------------------------------------------------------------
3572      External (hook): destroy all scrollbars on frame that weren't
3573      redeemed after call to condemn_scroll_bars.
3574    -------------------------------------------------------------------------- */
3576   int i;
3577   id view;
3578   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3579   NSTRACE (ns_judge_scroll_bars);
3580   for (i =[subviews count]-1; i >= 0; i--)
3581     {
3582       view = [subviews objectAtIndex: i];
3583       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3584       [view judge];
3585     }
3589 void
3590 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3592   /* XXX irrelevant under NS */
3597 /* ==========================================================================
3599     Initialization
3601    ========================================================================== */
3604 x_display_pixel_height (struct ns_display_info *dpyinfo)
3606   NSScreen *screen = [NSScreen mainScreen];
3607   return [screen frame].size.height;
3611 x_display_pixel_width (struct ns_display_info *dpyinfo)
3613   NSScreen *screen = [NSScreen mainScreen];
3614   return [screen frame].size.width;
3618 static Lisp_Object ns_string_to_lispmod (const char *s)
3619 /* --------------------------------------------------------------------------
3620      Convert modifier name to lisp symbol
3621    -------------------------------------------------------------------------- */
3623   if (!strncmp (SDATA (SYMBOL_NAME (Qmeta)), s, 10))
3624     return Qmeta;
3625   else if (!strncmp (SDATA (SYMBOL_NAME (Qsuper)), s, 10))
3626     return Qsuper;
3627   else if (!strncmp (SDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3628     return Qcontrol;
3629   else if (!strncmp (SDATA (SYMBOL_NAME (Qalt)), s, 10))
3630     return Qalt;
3631   else if (!strncmp (SDATA (SYMBOL_NAME (Qhyper)), s, 10))
3632     return Qhyper;
3633   else if (!strncmp (SDATA (SYMBOL_NAME (Qnone)), s, 10))
3634     return Qnone;
3635   else
3636     return Qnil;
3640 static Lisp_Object ns_mod_to_lisp (int m)
3641 /* --------------------------------------------------------------------------
3642      Convert modifier code (see lisp.h) to lisp symbol
3643    -------------------------------------------------------------------------- */
3645   if (m == CHAR_META)
3646     return Qmeta;
3647   else if (m == CHAR_SUPER)
3648     return Qsuper;
3649   else if (m == CHAR_CTL)
3650     return Qcontrol;
3651   else if (m == CHAR_ALT)
3652     return Qalt;
3653   else if (m == CHAR_HYPER)
3654     return Qhyper;
3655   else /* if (m == 0) */
3656     return Qnone;
3660 static void
3661 ns_default (const char *parameter, Lisp_Object *result,
3662            Lisp_Object yesval, Lisp_Object noval,
3663            BOOL is_float, BOOL is_modstring)
3664 /* --------------------------------------------------------------------------
3665       Check a parameter value in user's preferences
3666    -------------------------------------------------------------------------- */
3668   const char *value;
3670   if ( (value =[[[NSUserDefaults standardUserDefaults]
3671                    stringForKey: [NSString stringWithUTF8String: parameter]]
3672                 UTF8String]) )
3673     {
3674       double f;
3675       char *pos;
3676       if (strcasecmp (value, "YES") == 0)
3677         *result = yesval;
3678       else if (strcasecmp (value, "NO") == 0)
3679         *result = noval;
3680       else if (is_float && (f = strtod (value, &pos), pos != value))
3681         *result = make_float (f);
3682       else if (is_modstring && value)
3683         *result = ns_string_to_lispmod (value);
3684       else fprintf (stderr,
3685                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3686     }
3690 void
3691 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3692 /* --------------------------------------------------------------------------
3693       Initialize global info and storage for display.
3694    -------------------------------------------------------------------------- */
3696     NSScreen *screen = [NSScreen mainScreen];
3697     NSWindowDepth depth = [screen depth];
3698     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3700     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3701     dpyinfo->resy = 72.27;
3702     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3703                                                   NSColorSpaceFromDepth (depth)]
3704                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3705                                                  NSColorSpaceFromDepth (depth)];
3706     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3707     dpyinfo->image_cache = make_image_cache ();
3708     dpyinfo->color_table
3709       = (struct ns_color_table *)xmalloc (sizeof (struct ns_color_table));
3710     dpyinfo->color_table->colors = NULL;
3711     dpyinfo->root_window = 42; /* a placeholder.. */
3713     hlinfo->mouse_face_mouse_frame = NULL;
3714     hlinfo->mouse_face_deferred_gc = 0;
3715     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3716     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3717     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3718     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3719     hlinfo->mouse_face_hidden = 0;
3721     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3722     hlinfo->mouse_face_defer = 0;
3724     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3726     dpyinfo->n_fonts = 0;
3727     dpyinfo->smallest_font_height = 1;
3728     dpyinfo->smallest_char_width = 1;
3732 /* This and next define (many of the) public functions in this file. */
3733 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3734          with using despite presence in the "system dependent" redisplay
3735          interface.  In addition, many of the ns_ methods have code that is
3736          shared with all terms, indicating need for further refactoring. */
3737 extern frame_parm_handler ns_frame_parm_handlers[];
3738 static struct redisplay_interface ns_redisplay_interface =
3740   ns_frame_parm_handlers,
3741   x_produce_glyphs,
3742   x_write_glyphs,
3743   x_insert_glyphs,
3744   x_clear_end_of_line,
3745   ns_scroll_run,
3746   ns_after_update_window_line,
3747   ns_update_window_begin,
3748   ns_update_window_end,
3749   x_cursor_to,
3750   ns_flush,
3751   0, /* flush_display_optional */
3752   x_clear_window_mouse_face,
3753   x_get_glyph_overhangs,
3754   x_fix_overlapping_area,
3755   ns_draw_fringe_bitmap,
3756   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3757   0, /* destroy_fringe_bitmap */
3758   ns_compute_glyph_string_overhangs,
3759   ns_draw_glyph_string, /* interface to nsfont.m */
3760   ns_define_frame_cursor,
3761   ns_clear_frame_area,
3762   ns_draw_window_cursor,
3763   ns_draw_vertical_window_border,
3764   ns_shift_glyphs_for_insert
3768 static void
3769 ns_delete_display (struct ns_display_info *dpyinfo)
3771   /* TODO... */
3775 /* This function is called when the last frame on a display is deleted. */
3776 static void
3777 ns_delete_terminal (struct terminal *terminal)
3779   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3780   int i;
3782   /* Protect against recursive calls.  delete_frame in
3783      delete_terminal calls us back when it deletes our last frame.  */
3784   if (!terminal->name)
3785     return;
3787   BLOCK_INPUT;
3789   x_destroy_all_bitmaps (dpyinfo);
3790   ns_delete_display (dpyinfo);
3791   UNBLOCK_INPUT;
3795 static struct terminal *
3796 ns_create_terminal (struct ns_display_info *dpyinfo)
3797 /* --------------------------------------------------------------------------
3798       Set up use of NS before we make the first connection.
3799    -------------------------------------------------------------------------- */
3801   struct terminal *terminal;
3803   NSTRACE (ns_create_terminal);
3805   terminal = create_terminal ();
3807   terminal->type = output_ns;
3808   terminal->display_info.ns = dpyinfo;
3809   dpyinfo->terminal = terminal;
3811   terminal->rif = &ns_redisplay_interface;
3813   terminal->clear_frame_hook = ns_clear_frame;
3814   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3815   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3816   terminal->ring_bell_hook = ns_ring_bell;
3817   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3818   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3819   terminal->update_begin_hook = ns_update_begin;
3820   terminal->update_end_hook = ns_update_end;
3821   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
3822   terminal->read_socket_hook = ns_read_socket;
3823   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3824   terminal->mouse_position_hook = ns_mouse_position;
3825   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3826   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3828   terminal->fullscreen_hook = 0; /* see XTfullscreen_hook */
3830   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3831   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3832   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3833   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3835   terminal->delete_frame_hook = x_destroy_window;
3836   terminal->delete_terminal_hook = ns_delete_terminal;
3838   terminal->scroll_region_ok = 1;
3839   terminal->char_ins_del_ok = 1;
3840   terminal->line_ins_del_ok = 1;
3841   terminal->fast_clear_end_of_line = 1;
3842   terminal->memory_below_frame = 0;
3844   return terminal;
3848 struct ns_display_info *
3849 ns_term_init (Lisp_Object display_name)
3850 /* --------------------------------------------------------------------------
3851      Start the Application and get things rolling.
3852    -------------------------------------------------------------------------- */
3854   struct terminal *terminal;
3855   struct ns_display_info *dpyinfo;
3856   static int ns_initialized = 0;
3857   Lisp_Object tmp;
3859   NSTRACE (ns_term_init);
3861   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
3862   /*GSDebugAllocationActive (YES); */
3863   BLOCK_INPUT;
3864   handling_signal = 0;
3866   if (!ns_initialized)
3867     {
3868       baud_rate = 38400;
3869       Fset_input_interrupt_mode (Qnil);
3870       ns_initialized = 1;
3871     }
3873   ns_pending_files = [[NSMutableArray alloc] init];
3874   ns_pending_service_names = [[NSMutableArray alloc] init];
3875   ns_pending_service_args = [[NSMutableArray alloc] init];
3877   /* Start app and create the main menu, window, view.
3878      Needs to be here because ns_initialize_display_info () uses AppKit classes.
3879      The view will then ask the NSApp to stop and return to Emacs. */
3880   [EmacsApp sharedApplication];
3881   if (NSApp == nil)
3882     return NULL;
3883   [NSApp setDelegate: NSApp];
3885   /* debugging: log all notifications */
3886   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
3887                                          selector: @selector (logNotification:)
3888                                              name: nil object: nil]; */
3890   dpyinfo = (struct ns_display_info *)xmalloc (sizeof (struct ns_display_info));
3891   memset (dpyinfo, 0, sizeof (struct ns_display_info));
3893   ns_initialize_display_info (dpyinfo);
3894   terminal = ns_create_terminal (dpyinfo);
3896   terminal->kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
3897   init_kboard (terminal->kboard);
3898   KVAR (terminal->kboard, Vwindow_system) = Qns;
3899   terminal->kboard->next_kboard = all_kboards;
3900   all_kboards = terminal->kboard;
3901   /* Don't let the initial kboard remain current longer than necessary.
3902      That would cause problems if a file loaded on startup tries to
3903      prompt in the mini-buffer.  */
3904   if (current_kboard == initial_kboard)
3905     current_kboard = terminal->kboard;
3906   terminal->kboard->reference_count++;
3908   dpyinfo->next = x_display_list;
3909   x_display_list = dpyinfo;
3911   /* Put it on ns_display_name_list */
3912   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
3913                                 ns_display_name_list);
3914   dpyinfo->name_list_element = XCAR (ns_display_name_list);
3916   /* Set the name of the terminal. */
3917   terminal->name = (char *) xmalloc (SBYTES (display_name) + 1);
3918   strncpy (terminal->name, SDATA (display_name), SBYTES (display_name));
3919   terminal->name[SBYTES (display_name)] = 0;
3921   UNBLOCK_INPUT;
3923   if (!inhibit_x_resources)
3924     {
3925       ns_default ("GSFontAntiAlias", &ns_antialias_text,
3926                  Qt, Qnil, NO, NO);
3927       tmp = Qnil;
3928       /* this is a standard variable */
3929       ns_default ("AppleAntiAliasingThreshold", &tmp,
3930                  make_float (10.0), make_float (6.0), YES, NO);
3931       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
3932     }
3934   ns_selection_color = [[NSUserDefaults standardUserDefaults]
3935                          stringForKey: @"AppleHighlightColor"];
3936   if (ns_selection_color == nil)
3937     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
3939   {
3940     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
3942     if ( cl == nil )
3943       {
3944         Lisp_Object color_file, color_map, color;
3945         int r,g,b;
3946         unsigned long c;
3947         char *name;
3949         color_file = Fexpand_file_name (build_string ("rgb.txt"),
3950                          Fsymbol_value (intern ("data-directory")));
3951         if (NILP (Ffile_readable_p (color_file)))
3952           fatal ("Could not find %s.\n", SDATA (color_file));
3954         color_map = Fx_load_color_file (color_file);
3955         if (NILP (color_map))
3956           fatal ("Could not read %s.\n", SDATA (color_file));
3958         cl = [[NSColorList alloc] initWithName: @"Emacs"];
3959         for ( ; CONSP (color_map); color_map = XCDR (color_map))
3960           {
3961             color = XCAR (color_map);
3962             name = SDATA (XCAR (color));
3963             c = XINT (XCDR (color));
3964             [cl setColor:
3965                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
3966                                             green: GREEN_FROM_ULONG (c) / 255.0
3967                                              blue: BLUE_FROM_ULONG (c) / 255.0
3968                                             alpha: 1.0]
3969                   forKey: [NSString stringWithUTF8String: name]];
3970           }
3971         [cl writeToFile: nil];
3972       }
3973   }
3975   {
3976     char c[128];
3977 #ifdef NS_IMPL_GNUSTEP
3978     strncpy (c, gnustep_base_version, sizeof (c));
3979 #else
3980     /*PSnextrelease (128, c); */
3981     snprintf (c, sizeof (c), "%g", NSAppKitVersionNumber);
3982 #endif
3983     Vwindow_system_version = build_string (c);
3984   }
3986   delete_keyboard_wait_descriptor (0);
3988   ns_app_name = [[NSProcessInfo processInfo] processName];
3990 /* Set up OS X app menu */
3991 #ifdef NS_IMPL_COCOA
3992   {
3993     NSMenu *appMenu;
3994     NSMenuItem *item;
3995     /* set up the application menu */
3996     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
3997     [svcsMenu setAutoenablesItems: NO];
3998     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
3999     [appMenu setAutoenablesItems: NO];
4000     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4001     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4003     [appMenu insertItemWithTitle: @"About Emacs"
4004                           action: @selector (orderFrontStandardAboutPanel:)
4005                    keyEquivalent: @""
4006                          atIndex: 0];
4007     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4008     [appMenu insertItemWithTitle: @"Preferences..."
4009                           action: @selector (showPreferencesWindow:)
4010                    keyEquivalent: @","
4011                          atIndex: 2];
4012     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4013     item = [appMenu insertItemWithTitle: @"Services"
4014                                  action: @selector (menuDown:)
4015                           keyEquivalent: @""
4016                                 atIndex: 4];
4017     [appMenu setSubmenu: svcsMenu forItem: item];
4018     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4019     [appMenu insertItemWithTitle: @"Hide Emacs"
4020                           action: @selector (hide:)
4021                    keyEquivalent: @"h"
4022                          atIndex: 6];
4023     item =  [appMenu insertItemWithTitle: @"Hide Others"
4024                           action: @selector (hideOtherApplications:)
4025                    keyEquivalent: @"h"
4026                          atIndex: 7];
4027     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4028     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4029     [appMenu insertItemWithTitle: @"Quit Emacs"
4030                           action: @selector (terminate:)
4031                    keyEquivalent: @"q"
4032                          atIndex: 9];
4034     item = [mainMenu insertItemWithTitle: ns_app_name
4035                                   action: @selector (menuDown:)
4036                            keyEquivalent: @""
4037                                  atIndex: 0];
4038     [mainMenu setSubmenu: appMenu forItem: item];
4039     [dockMenu insertItemWithTitle: @"New Frame"
4040                            action: @selector (newFrame:)
4041                     keyEquivalent: @""
4042                           atIndex: 0];
4044     [NSApp setMainMenu: mainMenu];
4045     [NSApp setAppleMenu: appMenu];
4046     [NSApp setServicesMenu: svcsMenu];
4047     /* Needed at least on Cocoa, to get dock menu to show windows */
4048     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4049   }
4050 #endif /* MAC OS X menu setup */
4052   [NSApp run];
4054   return dpyinfo;
4058 void
4059 ns_term_shutdown (int sig)
4061   [[NSUserDefaults standardUserDefaults] synchronize];
4063   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4064   if (STRINGP (Vauto_save_list_file_name))
4065     unlink (SDATA (Vauto_save_list_file_name));
4067   if (sig == 0 || sig == SIGTERM)
4068     {
4069       [NSApp terminate: NSApp];
4070     }
4071   else // force a stack trace to happen
4072     {
4073       abort();
4074     }
4078 /* ==========================================================================
4080     EmacsApp implementation
4082    ========================================================================== */
4085 @implementation EmacsApp
4087 - (void)logNotification: (NSNotification *)notification
4089   const char *name = [[notification name] UTF8String];
4090   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4091       && !strstr (name, "WindowNumber"))
4092     NSLog (@"notification: '%@'", [notification name]);
4096 - (void)sendEvent: (NSEvent *)theEvent
4097 /* --------------------------------------------------------------------------
4098      Called when NSApp is running for each event received.  Used to stop
4099      the loop when we choose, since there's no way to just run one iteration.
4100    -------------------------------------------------------------------------- */
4102   int type = [theEvent type];
4103   NSWindow *window = [theEvent window];
4104 /*  NSTRACE (sendEvent); */
4105 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4107   if (type == NSCursorUpdate && window == nil)
4108     {
4109       fprintf (stderr, "Dropping external cursor update event.\n");
4110       return;
4111     }
4113 #ifdef NS_IMPL_COCOA
4114   /* pass mouse down in resize handle and subsequent drags directly to
4115      EmacsWindow so we can generate continuous redisplays */
4116   if (ns_in_resize)
4117     {
4118       if (type == NSLeftMouseDragged)
4119         {
4120           [window mouseDragged: theEvent];
4121           return;
4122         }
4123       else if (type == NSLeftMouseUp)
4124         {
4125           [window mouseUp: theEvent];
4126           return;
4127         }
4128     }
4129   else if (type == NSLeftMouseDown)
4130     {
4131       NSRect r = ns_resize_handle_rect (window);
4132       if (NSPointInRect ([theEvent locationInWindow], r))
4133         {
4134           ns_in_resize = YES;
4135           [window mouseDown: theEvent];
4136           return;
4137         }
4138     }
4139 #endif
4141   if (type == NSApplicationDefined)
4142     {
4143       /* Events posted by ns_send_appdefined interrupt the run loop here.
4144          But, if a modal window is up, an appdefined can still come through,
4145          (e.g., from a makeKeyWindow event) but stopping self also stops the
4146          modal loop. Just defer it until later. */
4147       if ([NSApp modalWindow] == nil)
4148         {
4149           last_appdefined_event = theEvent;
4150           [self stop: self];
4151         }
4152       else
4153         {
4154           send_appdefined = YES;
4155         }
4156     }
4158   [super sendEvent: theEvent];
4162 - (void)showPreferencesWindow: (id)sender
4164   struct frame *emacsframe = SELECTED_FRAME ();
4165   NSEvent *theEvent = [NSApp currentEvent];
4167   if (!emacs_event)
4168     return;
4169   emacs_event->kind = NS_NONKEY_EVENT;
4170   emacs_event->code = KEY_NS_SHOW_PREFS;
4171   emacs_event->modifiers = 0;
4172   EV_TRAILER (theEvent);
4176 - (void)newFrame: (id)sender
4178   struct frame *emacsframe = SELECTED_FRAME ();
4179   NSEvent *theEvent = [NSApp currentEvent];
4181   if (!emacs_event)
4182     return;
4183   emacs_event->kind = NS_NONKEY_EVENT;
4184   emacs_event->code = KEY_NS_NEW_FRAME;
4185   emacs_event->modifiers = 0;
4186   EV_TRAILER (theEvent);
4190 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4191 - (BOOL) openFile: (NSString *)fileName
4193   struct frame *emacsframe = SELECTED_FRAME ();
4194   NSEvent *theEvent = [NSApp currentEvent];
4196   if (!emacs_event)
4197     return NO;
4199   emacs_event->kind = NS_NONKEY_EVENT;
4200   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4201   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4202   ns_input_line = Qnil; /* can be start or cons start,end */
4203   emacs_event->modifiers =0;
4204   EV_TRAILER (theEvent);
4206   return YES;
4210 /* **************************************************************************
4212       EmacsApp delegate implementation
4214    ************************************************************************** */
4216 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4217 /* --------------------------------------------------------------------------
4218      When application is loaded, terminate event loop in ns_term_init
4219    -------------------------------------------------------------------------- */
4221   NSTRACE (applicationDidFinishLaunching);
4222   [NSApp setServicesProvider: NSApp];
4223   ns_send_appdefined (-2);
4227 /* Termination sequences:
4228     C-x C-c:
4229     Cmd-Q:
4230     MenuBar | File | Exit:
4231     Select Quit from App menubar:
4232         -terminate
4233         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4234         ns_term_shutdown()
4236     Select Quit from Dock menu:
4237     Logout attempt:
4238         -appShouldTerminate
4239           Cancel -> Nothing else
4240           Accept ->
4242           -terminate
4243           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4244           ns_term_shutdown()
4248 - (void) terminate: (id)sender
4250   struct frame *emacsframe = SELECTED_FRAME ();
4252   if (!emacs_event)
4253     return;
4255   emacs_event->kind = NS_NONKEY_EVENT;
4256   emacs_event->code = KEY_NS_POWER_OFF;
4257   emacs_event->arg = Qt; /* mark as non-key event */
4258   EV_TRAILER ((id)nil);
4262 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4264   int ret;
4266   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4267     return NSTerminateNow;
4269     ret = NSRunAlertPanel(ns_app_name,
4270                           [NSString stringWithUTF8String:"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?"],
4271                           @"Save Buffers and Exit", @"Cancel", nil);
4273     if (ret == NSAlertDefaultReturn)
4274         return NSTerminateNow;
4275     else if (ret == NSAlertAlternateReturn)
4276         return NSTerminateCancel;
4277     return NSTerminateNow;  /* just in case */
4281 /*   Notification from the Workspace to open a file */
4282 - (BOOL)application: sender openFile: (NSString *)file
4284   [ns_pending_files addObject: file];
4285   return YES;
4289 /*   Open a file as a temporary file */
4290 - (BOOL)application: sender openTempFile: (NSString *)file
4292   [ns_pending_files addObject: file];
4293   return YES;
4297 /*   Notification from the Workspace to open a file noninteractively (?) */
4298 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4300   [ns_pending_files addObject: file];
4301   return YES;
4305 /*   Notification from the Workspace to open multiple files */
4306 - (void)application: sender openFiles: (NSArray *)fileList
4308   NSEnumerator *files = [fileList objectEnumerator];
4309   NSString *file;
4310   while ((file = [files nextObject]) != nil)
4311     [ns_pending_files addObject: file];
4313   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4318 /* Handle dock menu requests.  */
4319 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4321   return dockMenu;
4325 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4326 - (void)applicationWillBecomeActive: (NSNotification *)notification
4328   //ns_app_active=YES;
4330 - (void)applicationDidBecomeActive: (NSNotification *)notification
4332   NSTRACE (applicationDidBecomeActive);
4334   //ns_app_active=YES;
4336   ns_update_auto_hide_menu_bar ();
4337   // No constrining takes place when the application is not active.
4338   ns_constrain_all_frames ();
4340 - (void)applicationDidResignActive: (NSNotification *)notification
4342   //ns_app_active=NO;
4343   ns_send_appdefined (-1);
4348 /* ==========================================================================
4350     EmacsApp aux handlers for managing event loop
4352    ========================================================================== */
4355 - (void)timeout_handler: (NSTimer *)timedEntry
4356 /* --------------------------------------------------------------------------
4357      The timeout specified to ns_select has passed.
4358    -------------------------------------------------------------------------- */
4360   /*NSTRACE (timeout_handler); */
4361   ns_send_appdefined (-2);
4364 - (void)fd_handler: (NSTimer *) fdEntry
4365 /* --------------------------------------------------------------------------
4366      Check data waiting on file descriptors and terminate if so
4367    -------------------------------------------------------------------------- */
4369   int result;
4370   /* NSTRACE (fd_handler); */
4372   if (select_nfds == 0)
4373     return;
4375   memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4377   select_timeout.tv_sec = select_timeout.tv_usec = 0;
4378   result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
4379                   &select_timeout);
4380   if (result)
4381     {
4382       memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4383       ns_send_appdefined (result);
4384     }
4389 /* ==========================================================================
4391     Service provision
4393    ========================================================================== */
4395 /* called from system: queue for next pass through event loop */
4396 - (void)requestService: (NSPasteboard *)pboard
4397               userData: (NSString *)userData
4398                  error: (NSString **)error
4400   [ns_pending_service_names addObject: userData];
4401   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4402       SDATA (ns_string_from_pasteboard (pboard))]];
4406 /* called from ns_read_socket to clear queue */
4407 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4409   struct frame *emacsframe = SELECTED_FRAME ();
4410   NSEvent *theEvent = [NSApp currentEvent];
4412   if (!emacs_event)
4413     return NO;
4415   emacs_event->kind = NS_NONKEY_EVENT;
4416   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4417   ns_input_spi_name = build_string ([name UTF8String]);
4418   ns_input_spi_arg = build_string ([arg UTF8String]);
4419   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4420   EV_TRAILER (theEvent);
4422   return YES;
4426 @end  /* EmacsApp */
4430 /* ==========================================================================
4432     EmacsView implementation
4434    ========================================================================== */
4437 @implementation EmacsView
4439 /* needed to inform when window closed from LISP */
4440 - (void) setWindowClosing: (BOOL)closing
4442   windowClosing = closing;
4446 - (void)dealloc
4448   NSTRACE (EmacsView_dealloc);
4449   [toolbar release];
4450   [super dealloc];
4454 /* called on font panel selection */
4455 - (void)changeFont: (id)sender
4457   NSEvent *e =[[self window] currentEvent];
4458   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4459   id newFont;
4460   float size;
4462   NSTRACE (changeFont);
4463   if (!emacs_event)
4464     return;
4466   if (newFont = [sender convertFont:
4467                            ((struct nsfont_info *)face->font)->nsfont])
4468     {
4469       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4471       emacs_event->kind = NS_NONKEY_EVENT;
4472       emacs_event->modifiers = 0;
4473       emacs_event->code = KEY_NS_CHANGE_FONT;
4475       size = [newFont pointSize];
4476       ns_input_fontsize = make_number (lrint (size));
4477       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4478       EV_TRAILER (e);
4479     }
4483 - (BOOL)acceptsFirstResponder
4485   NSTRACE (acceptsFirstResponder);
4486   return YES;
4490 - (void)resetCursorRects
4492   NSRect visible = [self visibleRect];
4493   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4494   NSTRACE (resetCursorRects);
4496   if (currentCursor == nil)
4497     currentCursor = [NSCursor arrowCursor];
4499   if (!NSIsEmptyRect (visible))
4500     [self addCursorRect: visible cursor: currentCursor];
4501   [currentCursor setOnMouseEntered: YES];
4506 /*****************************************************************************/
4507 /* Keyboard handling. */
4508 #define NS_KEYLOG 0
4510 - (void)keyDown: (NSEvent *)theEvent
4512   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4513   int code;
4514   unsigned fnKeysym = 0;
4515   int flags;
4516   static NSMutableArray *nsEvArray;
4517   static BOOL firstTime = YES;
4518   int left_is_none;
4520   NSTRACE (keyDown);
4522   /* Rhapsody and OS X give up and down events for the arrow keys */
4523   if (ns_fake_keydown == YES)
4524     ns_fake_keydown = NO;
4525   else if ([theEvent type] != NSKeyDown)
4526     return;
4528   if (!emacs_event)
4529     return;
4531  if (![[self window] isKeyWindow]
4532      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4533      /* we must avoid an infinite loop here. */
4534      && (EmacsView *)[[theEvent window] delegate] != self)
4535    {
4536      /* XXX: There is an occasional condition in which, when Emacs display
4537          updates a different frame from the current one, and temporarily
4538          selects it, then processes some interrupt-driven input
4539          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4540          for some reason that window has its first responder set to the NSView
4541          most recently updated (I guess), which is not the correct one. */
4542      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4543      return;
4544    }
4546   if (nsEvArray == nil)
4547     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4549   [NSCursor setHiddenUntilMouseMoves: YES];
4551   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4552     {
4553       clear_mouse_face (hlinfo);
4554       hlinfo->mouse_face_hidden = 1;
4555     }
4557   if (!processingCompose)
4558     {
4559       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4560         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4561       /* (Carbon way: [theEvent keyCode]) */
4563       /* is it a "function key"? */
4564       fnKeysym = ns_convert_key (code);
4565       if (fnKeysym)
4566         {
4567           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4568              because Emacs treats Delete and KP-Delete same (in simple.el). */
4569           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4570             code = 0xFF08; /* backspace */
4571           else
4572             code = fnKeysym;
4573         }
4575       /* are there modifiers? */
4576       emacs_event->modifiers = 0;
4577       flags = [theEvent modifierFlags];
4579       if (flags & NSHelpKeyMask)
4580           emacs_event->modifiers |= hyper_modifier;
4582       if (flags & NSShiftKeyMask)
4583         emacs_event->modifiers |= shift_modifier;
4585       if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask)
4586         emacs_event->modifiers |= parse_solitary_modifier
4587           (EQ (ns_right_command_modifier, Qleft)
4588            ? ns_command_modifier
4589            : ns_right_command_modifier);
4591       if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask)
4592         {
4593           emacs_event->modifiers |= parse_solitary_modifier
4594             (ns_command_modifier);
4596           /* if super (default), take input manager's word so things like
4597              dvorak / qwerty layout work */
4598           if (EQ (ns_command_modifier, Qsuper)
4599               && !fnKeysym
4600               && [[theEvent characters] length] != 0)
4601             {
4602               /* XXX: the code we get will be unshifted, so if we have
4603                  a shift modifier, must convert ourselves */
4604               if (!(flags & NSShiftKeyMask))
4605                 code = [[theEvent characters] characterAtIndex: 0];
4606 #if 0
4607               /* this is ugly and also requires linking w/Carbon framework
4608                  (for LMGetKbdType) so for now leave this rare (?) case
4609                  undealt with.. in future look into CGEvent methods */
4610               else
4611                 {
4612                   long smv = GetScriptManagerVariable (smKeyScript);
4613                   Handle uchrHandle = GetResource
4614                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4615                   UInt32 dummy = 0;
4616                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4617                                  [[theEvent characters] characterAtIndex: 0],
4618                                  kUCKeyActionDisplay,
4619                                  (flags & ~NSCommandKeyMask) >> 8,
4620                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4621                                  &dummy, 1, &dummy, &code);
4622                   code &= 0xFF;
4623                 }
4624 #endif
4625             }
4626         }
4628       if ((flags & NSRightControlKeyMask) == NSRightControlKeyMask)
4629           emacs_event->modifiers |= parse_solitary_modifier
4630               (EQ (ns_right_control_modifier, Qleft)
4631                ? ns_control_modifier
4632                : ns_right_control_modifier);
4634       if ((flags & NSLeftControlKeyMask) == NSLeftControlKeyMask)
4635         emacs_event->modifiers |= parse_solitary_modifier
4636           (ns_control_modifier);
4638       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4639           emacs_event->modifiers |=
4640             parse_solitary_modifier (ns_function_modifier);
4642       left_is_none = NILP (ns_alternate_modifier)
4643         || EQ (ns_alternate_modifier, Qnone);
4645       if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask)
4646         {
4647           if ((NILP (ns_right_alternate_modifier)
4648                || EQ (ns_right_alternate_modifier, Qnone)
4649                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4650               && !fnKeysym)
4651             {   /* accept pre-interp alt comb */
4652               if ([[theEvent characters] length] > 0)
4653                 code = [[theEvent characters] characterAtIndex: 0];
4654               /*HACK: clear lone shift modifier to stop next if from firing */
4655               if (emacs_event->modifiers == shift_modifier)
4656                 emacs_event->modifiers = 0;
4657             }
4658           else
4659             emacs_event->modifiers |= parse_solitary_modifier
4660               (EQ (ns_right_alternate_modifier, Qleft)
4661                ? ns_alternate_modifier
4662                : ns_right_alternate_modifier);
4663         }
4665       if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask) /* default = meta */
4666         {
4667           if (left_is_none && !fnKeysym)
4668             {   /* accept pre-interp alt comb */
4669               if ([[theEvent characters] length] > 0)
4670                 code = [[theEvent characters] characterAtIndex: 0];
4671               /*HACK: clear lone shift modifier to stop next if from firing */
4672               if (emacs_event->modifiers == shift_modifier)
4673                 emacs_event->modifiers = 0;
4674             }
4675           else
4676               emacs_event->modifiers |=
4677                 parse_solitary_modifier (ns_alternate_modifier);
4678         }
4680   if (NS_KEYLOG)
4681     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4682              code, fnKeysym, flags, emacs_event->modifiers);
4684       /* if it was a function key or had modifiers, pass it directly to emacs */
4685       if (fnKeysym || (emacs_event->modifiers
4686                        && (emacs_event->modifiers != shift_modifier)
4687                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4688 /*[[theEvent characters] length] */
4689         {
4690           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4691           if (code < 0x20)
4692             code |= (1<<28)|(3<<16);
4693           else if (code == 0x7f)
4694             code |= (1<<28)|(3<<16);
4695           else if (!fnKeysym)
4696             emacs_event->kind = code > 0xFF
4697               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4699           emacs_event->code = code;
4700           EV_TRAILER (theEvent);
4701           return;
4702         }
4703     }
4705   /* if we get here we should send the key for input manager processing */
4706   if (firstTime && [[NSInputManager currentInputManager]
4707                      wantsToDelayTextChangeNotifications] == NO)
4708     fprintf (stderr,
4709           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4710   firstTime = NO;
4712   if (NS_KEYLOG && !processingCompose)
4713     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4715   processingCompose = YES;
4716   [nsEvArray addObject: theEvent];
4717   [self interpretKeyEvents: nsEvArray];
4718   [nsEvArray removeObject: theEvent];
4722 #ifdef NS_IMPL_COCOA
4723 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4724    decided not to send key-down for.
4725    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4726    This only applies on Tiger and earlier.
4727    If it matches one of these, send it on to keyDown. */
4728 -(void)keyUp: (NSEvent *)theEvent
4730   int flags = [theEvent modifierFlags];
4731   int code = [theEvent keyCode];
4732   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
4733       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4734     {
4735       if (NS_KEYLOG)
4736         fprintf (stderr, "keyUp: passed test");
4737       ns_fake_keydown = YES;
4738       [self keyDown: theEvent];
4739     }
4741 #endif
4744 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4747 /* <NSTextInput>: called when done composing;
4748    NOTE: also called when we delete over working text, followed immed.
4749          by doCommandBySelector: deleteBackward: */
4750 - (void)insertText: (id)aString
4752   int code;
4753   int len = [(NSString *)aString length];
4754   int i;
4756   if (NS_KEYLOG)
4757     NSLog (@"insertText '%@'\tlen = %d", aString, len);
4758   processingCompose = NO;
4760   if (!emacs_event)
4761     return;
4763   /* first, clear any working text */
4764   if (workingText != nil)
4765     [self deleteWorkingText];
4767   /* now insert the string as keystrokes */
4768   for (i =0; i<len; i++)
4769     {
4770       code = [aString characterAtIndex: i];
4771       /* TODO: still need this? */
4772       if (code == 0x2DC)
4773         code = '~'; /* 0x7E */
4774       emacs_event->modifiers = 0;
4775       emacs_event->kind
4776         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4777       emacs_event->code = code;
4778       EV_TRAILER ((id)nil);
4779     }
4783 /* <NSTextInput>: inserts display of composing characters */
4784 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
4786   NSString *str = [aString respondsToSelector: @selector (string)] ?
4787     [aString string] : aString;
4788   if (NS_KEYLOG)
4789     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
4790            selRange.length, selRange.location);
4792   if (workingText != nil)
4793     [self deleteWorkingText];
4794   if ([str length] == 0)
4795     return;
4797   if (!emacs_event)
4798     return;
4800   processingCompose = YES;
4801   workingText = [str copy];
4802   ns_working_text = build_string ([workingText UTF8String]);
4804   emacs_event->kind = NS_TEXT_EVENT;
4805   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
4806   EV_TRAILER ((id)nil);
4810 /* delete display of composing characters [not in <NSTextInput>] */
4811 - (void)deleteWorkingText
4813   if (workingText == nil)
4814     return;
4815   if (NS_KEYLOG)
4816     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
4817   [workingText release];
4818   workingText = nil;
4819   processingCompose = NO;
4821   if (!emacs_event)
4822     return;
4824   emacs_event->kind = NS_TEXT_EVENT;
4825   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
4826   EV_TRAILER ((id)nil);
4830 - (BOOL)hasMarkedText
4832   return workingText != nil;
4836 - (NSRange)markedRange
4838   NSRange rng = workingText != nil
4839     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
4840   if (NS_KEYLOG)
4841     NSLog (@"markedRange request");
4842   return rng;
4846 - (void)unmarkText
4848   if (NS_KEYLOG)
4849     NSLog (@"unmark (accept) text");
4850   [self deleteWorkingText];
4851   processingCompose = NO;
4855 /* used to position char selection windows, etc. */
4856 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
4858   NSRect rect;
4859   NSPoint pt;
4860   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
4861   if (NS_KEYLOG)
4862     NSLog (@"firstRectForCharRange request");
4864   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
4865   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
4866   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
4867   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
4868                                        +FRAME_LINE_HEIGHT (emacsframe));
4870   pt = [self convertPoint: pt toView: nil];
4871   pt = [[self window] convertBaseToScreen: pt];
4872   rect.origin = pt;
4873   return rect;
4877 - (long)conversationIdentifier
4879   return (long)self;
4883 - (void)doCommandBySelector: (SEL)aSelector
4885   if (NS_KEYLOG)
4886     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
4888   if (aSelector == @selector (deleteBackward:))
4889     {
4890       /* happens when user backspaces over an ongoing composition:
4891          throw a 'delete' into the event queue */
4892       if (!emacs_event)
4893         return;
4894       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4895       emacs_event->code = 0xFF08;
4896       EV_TRAILER ((id)nil);
4897     }
4900 - (NSArray *)validAttributesForMarkedText
4902   static NSArray *arr = nil;
4903   if (arr == nil) arr = [NSArray new];
4904  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
4905   return arr;
4908 - (NSRange)selectedRange
4910   if (NS_KEYLOG)
4911     NSLog (@"selectedRange request");
4912   return NSMakeRange (NSNotFound, 0);
4915 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
4917   if (NS_KEYLOG)
4918     NSLog (@"characterIndexForPoint request");
4919   return 0;
4922 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
4924   static NSAttributedString *str = nil;
4925   if (str == nil) str = [NSAttributedString new];
4926   if (NS_KEYLOG)
4927     NSLog (@"attributedSubstringFromRange request");
4928   return str;
4931 /* End <NSTextInput> impl. */
4932 /*****************************************************************************/
4935 /* This is what happens when the user presses a mouse button.  */
4936 - (void)mouseDown: (NSEvent *)theEvent
4938   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
4939   Lisp_Object window;
4941   NSTRACE (mouseDown);
4943   [self deleteWorkingText];
4945   if (!emacs_event)
4946     return;
4948   last_mouse_frame = emacsframe;
4949   /* appears to be needed to prevent spurious movement events generated on
4950      button clicks */
4951   last_mouse_frame->mouse_moved = 0;
4953   if ([theEvent type] == NSScrollWheel)
4954     {
4955       float delta = [theEvent deltaY];
4956       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
4957       if (delta == 0)
4958         return;
4959       emacs_event->kind = WHEEL_EVENT;
4960       emacs_event->code = 0;
4961       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
4962         ((delta > 0) ? up_modifier : down_modifier);
4963     }
4964   else
4965     {
4966       emacs_event->kind = MOUSE_CLICK_EVENT;
4967       emacs_event->code = EV_BUTTON (theEvent);
4968       emacs_event->modifiers = EV_MODIFIERS (theEvent)
4969                              | EV_UDMODIFIERS (theEvent);
4970     }
4971   XSETINT (emacs_event->x, lrint (p.x));
4972   XSETINT (emacs_event->y, lrint (p.y));
4973   EV_TRAILER (theEvent);
4977 - (void)rightMouseDown: (NSEvent *)theEvent
4979   NSTRACE (rightMouseDown);
4980   [self mouseDown: theEvent];
4984 - (void)otherMouseDown: (NSEvent *)theEvent
4986   NSTRACE (otherMouseDown);
4987   [self mouseDown: theEvent];
4991 - (void)mouseUp: (NSEvent *)theEvent
4993   NSTRACE (mouseUp);
4994   [self mouseDown: theEvent];
4998 - (void)rightMouseUp: (NSEvent *)theEvent
5000   NSTRACE (rightMouseUp);
5001   [self mouseDown: theEvent];
5005 - (void)otherMouseUp: (NSEvent *)theEvent
5007   NSTRACE (otherMouseUp);
5008   [self mouseDown: theEvent];
5012 - (void) scrollWheel: (NSEvent *)theEvent
5014   NSTRACE (scrollWheel);
5015   [self mouseDown: theEvent];
5019 /* Tell emacs the mouse has moved. */
5020 - (void)mouseMoved: (NSEvent *)e
5022   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5023   Lisp_Object frame;
5025 //  NSTRACE (mouseMoved);
5027   last_mouse_movement_time = EV_TIMESTAMP (e);
5028   last_mouse_motion_position
5029     = [self convertPoint: [e locationInWindow] fromView: nil];
5031   /* update any mouse face */
5032   if (hlinfo->mouse_face_hidden)
5033     {
5034       hlinfo->mouse_face_hidden = 0;
5035       clear_mouse_face (hlinfo);
5036     }
5038   /* tooltip handling */
5039   previous_help_echo_string = help_echo_string;
5040   help_echo_string = Qnil;
5042   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5043                             last_mouse_motion_position.y))
5044     help_echo_string = previous_help_echo_string;
5046   XSETFRAME (frame, emacsframe);
5047   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5048     {
5049       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5050          (note_mouse_highlight), which is called through the
5051          note_mouse_movement () call above */
5052       gen_help_event (help_echo_string, frame, help_echo_window,
5053                       help_echo_object, help_echo_pos);
5054     }
5055   else
5056     {
5057       help_echo_string = Qnil;
5058       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5059     }
5061   if (emacsframe->mouse_moved && send_appdefined)
5062     ns_send_appdefined (-1);
5066 - (void)mouseDragged: (NSEvent *)e
5068   NSTRACE (mouseDragged);
5069   [self mouseMoved: e];
5073 - (void)rightMouseDragged: (NSEvent *)e
5075   NSTRACE (rightMouseDragged);
5076   [self mouseMoved: e];
5080 - (void)otherMouseDragged: (NSEvent *)e
5082   NSTRACE (otherMouseDragged);
5083   [self mouseMoved: e];
5087 - (BOOL)windowShouldClose: (id)sender
5089   NSEvent *e =[[self window] currentEvent];
5091   NSTRACE (windowShouldClose);
5092   windowClosing = YES;
5093   if (!emacs_event)
5094     return NO;
5095   emacs_event->kind = DELETE_WINDOW_EVENT;
5096   emacs_event->modifiers = 0;
5097   emacs_event->code = 0;
5098   EV_TRAILER (e);
5099   /* Don't close this window, let this be done from lisp code.  */
5100   return NO;
5104 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5105 /* normalize frame to gridded text size */
5107   NSTRACE (windowWillResize);
5108 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5110   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5111 #ifdef NS_IMPL_GNUSTEP
5112                                         frameSize.width + 3);
5113 #else
5114                                         frameSize.width);
5115 #endif
5116   if (cols < MINWIDTH)
5117     cols = MINWIDTH;
5119   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
5120 #ifdef NS_IMPL_GNUSTEP
5121       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
5122         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5123 #else
5124       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5125         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5126 #endif
5127   if (rows < MINHEIGHT)
5128     rows = MINHEIGHT;
5129 #ifdef NS_IMPL_COCOA
5130   {
5131     /* this sets window title to have size in it; the wm does this under GS */
5132     NSRect r = [[self window] frame];
5133     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5134       {
5135         if (old_title != 0)
5136           {
5137             xfree (old_title);
5138             old_title = 0;
5139           }
5140       }
5141     else
5142       {
5143         char *size_title;
5144         NSWindow *window = [self window];
5145         if (old_title == 0)
5146           {
5147             const char *t = [[[self window] title] UTF8String];
5148             char *pos = strstr (t, "  â€”  ");
5149             if (pos)
5150               *pos = '\0';
5151             old_title = (char *) xmalloc (strlen (t) + 1);
5152             strcpy (old_title, t);
5153           }
5154         size_title = xmalloc (strlen (old_title) + 40);
5155         sprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5156         [window setTitle: [NSString stringWithUTF8String: size_title]];
5157         [window display];
5158         xfree (size_title);
5159       }
5160   }
5161 #endif /* NS_IMPL_COCOA */
5162 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5164   return frameSize;
5168 - (void)windowDidResize: (NSNotification *)notification
5170   NSWindow *theWindow = [notification object];
5172 #ifdef NS_IMPL_GNUSTEP
5173    /* in GNUstep, at least currently, it's possible to get a didResize
5174       without getting a willResize.. therefore we need to act as if we got
5175       the willResize now */
5176   NSSize sz = [theWindow frame].size;
5177   sz = [self windowWillResize: theWindow toSize: sz];
5178 #endif /* NS_IMPL_GNUSTEP */
5180   NSTRACE (windowDidResize);
5181 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5183 #ifdef NS_IMPL_COCOA
5184   if (old_title != 0)
5185     {
5186       xfree (old_title);
5187       old_title = 0;
5188     }
5189 #endif /* NS_IMPL_COCOA */
5191   /* Avoid loop under GNUstep due to call at beginning of this function.
5192      (x_set_window_size causes a resize which causes
5193      a "windowDidResize" which calls x_set_window_size).  */
5194 #ifndef NS_IMPL_GNUSTEP
5195   if (cols > 0 && rows > 0)
5196     x_set_window_size (emacsframe, 0, cols, rows);
5197 #endif
5199   ns_send_appdefined (-1);
5203 - (void)windowDidBecomeKey: (NSNotification *)notification
5204 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5206   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5207   struct frame *old_focus = dpyinfo->x_focus_frame;
5209   NSTRACE (windowDidBecomeKey);
5211   if (emacsframe != old_focus)
5212     dpyinfo->x_focus_frame = emacsframe;
5214   ns_frame_rehighlight (emacsframe);
5216   if (emacs_event)
5217     {
5218       emacs_event->kind = FOCUS_IN_EVENT;
5219       EV_TRAILER ((id)nil);
5220     }
5224 - (void)windowDidResignKey: (NSNotification *)notification
5225 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5227   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5228   NSTRACE (windowDidResignKey);
5230   if (dpyinfo->x_focus_frame == emacsframe)
5231     dpyinfo->x_focus_frame = 0;
5233   ns_frame_rehighlight (emacsframe);
5235   /* FIXME: for some reason needed on second and subsequent clicks away
5236             from sole-frame Emacs to get hollow box to show */
5237   if (!windowClosing && [[self window] isVisible] == YES)
5238     {
5239       x_update_cursor (emacsframe, 1);
5240       x_set_frame_alpha (emacsframe);
5241     }
5243   if (emacs_event)
5244     {
5245       [self deleteWorkingText];
5246       emacs_event->kind = FOCUS_IN_EVENT;
5247       EV_TRAILER ((id)nil);
5248     }
5252 - (void)windowWillMiniaturize: sender
5254   NSTRACE (windowWillMiniaturize);
5258 - (BOOL)isFlipped
5260   return YES;
5264 - (BOOL)isOpaque
5266   return NO;
5270 - initFrameFromEmacs: (struct frame *)f
5272   NSRect r, wr;
5273   Lisp_Object tem;
5274   NSWindow *win;
5275   NSButton *toggleButton;
5276   int vbextra = NS_SCROLL_BAR_WIDTH (f);
5277   NSSize sz;
5278   NSColor *col;
5279   NSString *name;
5281   NSTRACE (initFrameFromEmacs);
5283   windowClosing = NO;
5284   processingCompose = NO;
5285   scrollbarsNeedingUpdate = 0;
5287 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5289   ns_userRect = NSMakeRect (0, 0, 0, 0);
5290   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5291                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5292   [self initWithFrame: r];
5293   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5295   FRAME_NS_VIEW (f) = self;
5296   emacsframe = f;
5297   old_title = 0;
5299   win = [[EmacsWindow alloc]
5300             initWithContentRect: r
5301                       styleMask: (NSResizableWindowMask |
5302                                   NSMiniaturizableWindowMask |
5303                                   NSClosableWindowMask)
5304                         backing: NSBackingStoreBuffered
5305                           defer: YES];
5307   wr = [win frame];
5308   f->border_width = wr.size.width - r.size.width;
5309   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5311   [win setAcceptsMouseMovedEvents: YES];
5312   [win setDelegate: self];
5313   [win useOptimizedDrawing: YES];
5315   sz.width = FRAME_COLUMN_WIDTH (f);
5316   sz.height = FRAME_LINE_HEIGHT (f);
5317   [win setResizeIncrements: sz];
5319   [[win contentView] addSubview: self];
5321   if (ns_drag_types)
5322     [self registerForDraggedTypes: ns_drag_types];
5324   tem = f->name;
5325   name = [NSString stringWithUTF8String:
5326                    NILP (tem) ? (unsigned char *)"Emacs" : SDATA (tem)];
5327   [win setTitle: name];
5329   /* toolbar support */
5330   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5331                          [NSString stringWithFormat: @"Emacs Frame %d",
5332                                    ns_window_num]];
5333   [win setToolbar: toolbar];
5334   [toolbar setVisible: NO];
5335 #ifdef NS_IMPL_COCOA
5336   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5337   [toggleButton setTarget: self];
5338   [toggleButton setAction: @selector (toggleToolbar: )];
5339 #endif
5340   FRAME_TOOLBAR_HEIGHT (f) = 0;
5342   tem = f->icon_name;
5343   if (!NILP (tem))
5344     [win setMiniwindowTitle:
5345            [NSString stringWithUTF8String: SDATA (tem)]];
5347   {
5348     NSScreen *screen = [win screen];
5350     if (screen != 0)
5351       [win setFrameTopLeftPoint: NSMakePoint
5352            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5353             IN_BOUND (-SCREENMAX,
5354                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5355   }
5357   [win makeFirstResponder: self];
5359   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5360                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5361   [win setBackgroundColor: col];
5362   if ([col alphaComponent] != 1.0)
5363     [win setOpaque: NO];
5365   [self allocateGState];
5367   ns_window_num++;
5368   return self;
5372 - (void)windowDidMove: sender
5374   NSWindow *win = [self window];
5375   NSRect r = [win frame];
5376   NSArray *screens = [NSScreen screens];
5377   NSScreen *screen = [screens objectAtIndex: 0];
5379   NSTRACE (windowDidMove);
5381   if (!emacsframe->output_data.ns)
5382     return;
5383   if (screen != nil)
5384     {
5385       emacsframe->left_pos = r.origin.x;
5386       emacsframe->top_pos =
5387         [screen frame].size.height - (r.origin.y + r.size.height);
5388     }
5392 /* Called AFTER method below, but before our windowWillResize call there leads
5393    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5394    location so set_window_size moves the frame. */
5395 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5397   emacsframe->output_data.ns->zooming = 1;
5398   return YES;
5402 /* Override to do something slightly nonstandard, but nice.  First click on
5403    zoom button will zoom vertically.  Second will zoom completely.  Third
5404    returns to original. */
5405 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5406                         defaultFrame:(NSRect)defaultFrame
5408   NSRect result = [sender frame];
5410   NSTRACE (windowWillUseStandardFrame);
5412   if (abs (defaultFrame.size.height - result.size.height)
5413       > FRAME_LINE_HEIGHT (emacsframe))
5414     {
5415       /* first click */
5416       ns_userRect = result;
5417       result.size.height = defaultFrame.size.height;
5418       result.origin.y = defaultFrame.origin.y;
5419     }
5420   else
5421     {
5422       if (abs (defaultFrame.size.width - result.size.width)
5423           > FRAME_COLUMN_WIDTH (emacsframe))
5424         result = defaultFrame;  /* second click */
5425       else
5426         {
5427           /* restore */
5428           result = ns_userRect.size.height ? ns_userRect : result;
5429           ns_userRect = NSMakeRect (0, 0, 0, 0);
5430         }
5431     }
5433   [self windowWillResize: sender toSize: result.size];
5434   return result;
5438 - (void)windowDidDeminiaturize: sender
5440   NSTRACE (windowDidDeminiaturize);
5441   if (!emacsframe->output_data.ns)
5442     return;
5443   emacsframe->async_iconified = 0;
5444   emacsframe->async_visible   = 1;
5445   windows_or_buffers_changed++;
5447   if (emacs_event)
5448     {
5449       emacs_event->kind = ICONIFY_EVENT;
5450       EV_TRAILER ((id)nil);
5451     }
5455 - (void)windowDidExpose: sender
5457   NSTRACE (windowDidExpose);
5458   if (!emacsframe->output_data.ns)
5459     return;
5460   emacsframe->async_visible = 1;
5461   SET_FRAME_GARBAGED (emacsframe);
5463   if (send_appdefined)
5464     ns_send_appdefined (-1);
5468 - (void)windowDidMiniaturize: sender
5470   NSTRACE (windowDidMiniaturize);
5471   if (!emacsframe->output_data.ns)
5472     return;
5474   emacsframe->async_iconified = 1;
5475   emacsframe->async_visible = 0;
5477   if (emacs_event)
5478     {
5479       emacs_event->kind = ICONIFY_EVENT;
5480       EV_TRAILER ((id)nil);
5481     }
5485 - (void)mouseEntered: (NSEvent *)theEvent
5487   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5488   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5489   NSTRACE (mouseEntered);
5491   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5495 - (void)mouseExited: (NSEvent *)theEvent
5497   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5498   NSRect r;
5499   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
5501   NSTRACE (mouseExited);
5503   if (!hlinfo)
5504     return;
5506   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5508   if (emacsframe == hlinfo->mouse_face_mouse_frame)
5509     {
5510       clear_mouse_face (hlinfo);
5511       hlinfo->mouse_face_mouse_frame = 0;
5512     }
5516 - menuDown: sender
5518   NSTRACE (menuDown);
5519   if (context_menu_value == -1)
5520     context_menu_value = [sender tag];
5521   else
5522     find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5523                                   emacsframe->menu_bar_vector,
5524                                   (void *)[sender tag]);
5525   ns_send_appdefined (-1);
5526   return self;
5530 - (EmacsToolbar *)toolbar
5532   return toolbar;
5536 /* this gets called on toolbar button click */
5537 - toolbarClicked: (id)item
5539   NSEvent *theEvent;
5540   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5542   NSTRACE (toolbarClicked);
5544   if (!emacs_event)
5545     return self;
5547   /* send first event (for some reason two needed) */
5548   theEvent = [[self window] currentEvent];
5549   emacs_event->kind = TOOL_BAR_EVENT;
5550   XSETFRAME (emacs_event->arg, emacsframe);
5551   EV_TRAILER (theEvent);
5553   emacs_event->kind = TOOL_BAR_EVENT;
5554 /*   XSETINT (emacs_event->code, 0); */
5555   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5556                           idx + TOOL_BAR_ITEM_KEY);
5557   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5558   EV_TRAILER (theEvent);
5559   return self;
5563 - toggleToolbar: (id)sender
5565   if (!emacs_event)
5566     return self;
5568   emacs_event->kind = NS_NONKEY_EVENT;
5569   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
5570   EV_TRAILER ((id)nil);
5571   return self;
5575 - (void)drawRect: (NSRect)rect
5577   int x = NSMinX (rect), y = NSMinY (rect);
5578   int width = NSWidth (rect), height = NSHeight (rect);
5580   NSTRACE (drawRect);
5582   if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
5583     return;
5585   ns_clear_frame_area (emacsframe, x, y, width, height);
5586   expose_frame (emacsframe, x, y, width, height);
5588   /*
5589     drawRect: may be called (at least in OS X 10.5) for invisible
5590     views as well for some reason.  Thus, do not infer visibility
5591     here.
5593     emacsframe->async_visible = 1;
5594     emacsframe->async_iconified = 0;
5595   */
5599 /* NSDraggingDestination protocol methods.  Actually this is not really a
5600    protocol, but a category of Object.  O well...  */
5602 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
5604   NSTRACE (draggingEntered);
5605   return NSDragOperationGeneric;
5609 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5611   return YES;
5615 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5617   id pb;
5618   int x, y;
5619   NSString *type;
5620   NSEvent *theEvent = [[self window] currentEvent];
5621   NSPoint position;
5623   NSTRACE (performDragOperation);
5625   if (!emacs_event)
5626     return NO;
5628   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5629   x = lrint (position.x);  y = lrint (position.y);
5631   pb = [sender draggingPasteboard];
5632   type = [pb availableTypeFromArray: ns_drag_types];
5633   if (type == 0)
5634     {
5635       return NO;
5636     }
5637   else if ([type isEqualToString: NSFilenamesPboardType])
5638     {
5639       NSArray *files;
5640       NSEnumerator *fenum;
5641       NSString *file;
5643       if (!(files = [pb propertyListForType: type]))
5644         return NO;
5646       fenum = [files objectEnumerator];
5647       while ( (file = [fenum nextObject]) )
5648         {
5649           emacs_event->kind = NS_NONKEY_EVENT;
5650           emacs_event->code = KEY_NS_DRAG_FILE;
5651           XSETINT (emacs_event->x, x);
5652           XSETINT (emacs_event->y, y);
5653           ns_input_file = append2 (ns_input_file,
5654                                    build_string ([file UTF8String]));
5655           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5656           EV_TRAILER (theEvent);
5657         }
5658       return YES;
5659     }
5660   else if ([type isEqualToString: NSURLPboardType])
5661     {
5662       NSString *file;
5663       NSURL *fileURL;
5665       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5666           [fileURL isFileURL] == NO)
5667         return NO;
5669       file = [fileURL path];
5670       emacs_event->kind = NS_NONKEY_EVENT;
5671       emacs_event->code = KEY_NS_DRAG_FILE;
5672       XSETINT (emacs_event->x, x);
5673       XSETINT (emacs_event->y, y);
5674       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5675       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5676       EV_TRAILER (theEvent);
5677       return YES;
5678     }
5679   else if ([type isEqualToString: NSStringPboardType]
5680            || [type isEqualToString: NSTabularTextPboardType])
5681     {
5682       NSString *data;
5684       if (! (data = [pb stringForType: type]))
5685         return NO;
5687       emacs_event->kind = NS_NONKEY_EVENT;
5688       emacs_event->code = KEY_NS_DRAG_TEXT;
5689       XSETINT (emacs_event->x, x);
5690       XSETINT (emacs_event->y, y);
5691       ns_input_text = build_string ([data UTF8String]);
5692       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5693       EV_TRAILER (theEvent);
5694       return YES;
5695     }
5696   else if ([type isEqualToString: NSColorPboardType])
5697     {
5698       NSColor *c = [NSColor colorFromPasteboard: pb];
5699       emacs_event->kind = NS_NONKEY_EVENT;
5700       emacs_event->code = KEY_NS_DRAG_COLOR;
5701       XSETINT (emacs_event->x, x);
5702       XSETINT (emacs_event->y, y);
5703       ns_input_color = ns_color_to_lisp (c);
5704       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5705       EV_TRAILER (theEvent);
5706       return YES;
5707     }
5708   else if ([type isEqualToString: NSFontPboardType])
5709     {
5710       /* impl based on GNUstep NSTextView.m */
5711       NSData *data = [pb dataForType: NSFontPboardType];
5712       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5713       NSFont *font = [dict objectForKey: NSFontAttributeName];
5714       char fontSize[10];
5716       if (font == nil)
5717         return NO;
5719       emacs_event->kind = NS_NONKEY_EVENT;
5720       emacs_event->code = KEY_NS_CHANGE_FONT;
5721       XSETINT (emacs_event->x, x);
5722       XSETINT (emacs_event->y, y);
5723       ns_input_font = build_string ([[font fontName] UTF8String]);
5724       snprintf (fontSize, 10, "%f", [font pointSize]);
5725       ns_input_fontsize = build_string (fontSize);
5726       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5727       EV_TRAILER (theEvent);
5728       return YES;
5729     }
5730   else
5731     {
5732       error ("Invalid data type in dragging pasteboard.");
5733       return NO;
5734     }
5738 - validRequestorForSendType: (NSString *)typeSent
5739                  returnType: (NSString *)typeReturned
5741   NSTRACE (validRequestorForSendType);
5742   if ([ns_send_types indexOfObjectIdenticalTo: typeSent] != NSNotFound &&
5743       [ns_return_types indexOfObjectIdenticalTo: typeSent] != NSNotFound)
5744     return self;
5746   return [super validRequestorForSendType: typeSent
5747                                returnType: typeReturned];
5751 /* The next two methods are part of NSServicesRequests informal protocol,
5752    supposedly called when a services menu item is chosen from this app.
5753    But this should not happen because we override the services menu with our
5754    own entries which call ns-perform-service.
5755    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
5756    So let's at least stub them out until further investigation can be done. */
5758 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
5760   /* we could call ns_string_from_pasteboard(pboard) here but then it should
5761      be written into the buffer in place of the existing selection..
5762      ordinary service calls go through functions defined in ns-win.el */
5763   return NO;
5766 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
5768   /* supposed to write for as many of types as we are able */
5769   return NO;
5773 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
5774    (gives a miniaturized version of the window); currently we use the latter for
5775    frames whose active buffer doesn't correspond to any file
5776    (e.g., '*scratch*') */
5777 - setMiniwindowImage: (BOOL) setMini
5779   id image = [[self window] miniwindowImage];
5780   NSTRACE (setMiniwindowImage);
5782   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
5783      about "AppleDockIconEnabled" notwithstanding, however the set message
5784      below has its effect nonetheless. */
5785   if (image != emacsframe->output_data.ns->miniimage)
5786     {
5787       if (image && [image isKindOfClass: [EmacsImage class]])
5788         [image release];
5789       [[self window] setMiniwindowImage:
5790                        setMini ? emacsframe->output_data.ns->miniimage : nil];
5791     }
5793   return self;
5797 - (void) setRows: (int) r andColumns: (int) c
5799   rows = r;
5800   cols = c;
5803 @end  /* EmacsView */
5807 /* ==========================================================================
5809     EmacsWindow implementation
5811    ========================================================================== */
5813 @implementation EmacsWindow
5815 /* If we have multiple monitors, one above the other, we don't want to
5816    restrict the height to just one monitor.  So we override this.  */
5817 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
5819   /* When making the frame visible for the first time, we want to
5820      constrain.  Other times not.  */
5821   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
5822   NSTRACE (constrainFrameRect);
5824   if (f->output_data.ns->dont_constrain
5825       || ns_menu_bar_should_be_hidden ())
5826     return frameRect;
5828   f->output_data.ns->dont_constrain = 1;
5829   return [super constrainFrameRect:frameRect toScreen:screen];
5833 /* called only on resize clicks by special case in EmacsApp-sendEvent */
5834 - (void)mouseDown: (NSEvent *)theEvent
5836   if (ns_in_resize)
5837     {
5838       NSSize size = [[theEvent window] frame].size;
5839       grabOffset = [theEvent locationInWindow];
5840       grabOffset.x = size.width - grabOffset.x;
5841     }
5842   else
5843     [super mouseDown: theEvent];
5847 /* stop resizing */
5848 - (void)mouseUp: (NSEvent *)theEvent
5850   if (ns_in_resize)
5851     {
5852       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
5853       ns_in_resize = NO;
5854       ns_set_name_as_filename (f);
5855       [self display];
5856       ns_send_appdefined (-1);
5857     }
5858   else
5859     [super mouseUp: theEvent];
5863 /* send resize events */
5864 - (void)mouseDragged: (NSEvent *)theEvent
5866   if (ns_in_resize)
5867     {
5868       NSPoint p = [theEvent locationInWindow];
5869       NSSize size, vettedSize, origSize = [self frame].size;
5871       size.width = p.x + grabOffset.x;
5872       size.height = origSize.height - p.y + grabOffset.y;
5874       if (size.width == origSize.width && size.height == origSize.height)
5875         return;
5877       vettedSize = [[self delegate] windowWillResize: self toSize: size];
5878       [[NSNotificationCenter defaultCenter]
5879             postNotificationName: NSWindowDidResizeNotification
5880                           object: self];
5881     }
5882   else
5883     [super mouseDragged: theEvent];
5886 @end /* EmacsWindow */
5889 /* ==========================================================================
5891     EmacsScroller implementation
5893    ========================================================================== */
5896 @implementation EmacsScroller
5898 /* for repeat button push */
5899 #define SCROLL_BAR_FIRST_DELAY 0.5
5900 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
5902 + (CGFloat) scrollerWidth
5904   /* TODO: if we want to allow variable widths, this is the place to do it,
5905            however neither GNUstep nor Cocoa support it very well */
5906   return [NSScroller scrollerWidth];
5910 - initFrame: (NSRect )r window: (Lisp_Object)nwin
5912   NSTRACE (EmacsScroller_initFrame);
5914   r.size.width = [EmacsScroller scrollerWidth];
5915   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
5916   [self setContinuous: YES];
5917   [self setEnabled: YES];
5919   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
5920      locked against the top and bottom edges, and right edge on OS X, where
5921      scrollers are on right. */
5922 #ifdef NS_IMPL_GNUSTEP
5923   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
5924 #else
5925   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
5926 #endif
5928   win = nwin;
5929   condemned = NO;
5930   pixel_height = NSHeight (r);
5931   if (pixel_height == 0) pixel_height = 1;
5932   min_portion = 20 / pixel_height;
5934   frame = XFRAME (XWINDOW (win)->frame);
5935   if (FRAME_LIVE_P (frame))
5936     {
5937       int i;
5938       EmacsView *view = FRAME_NS_VIEW (frame);
5939       NSView *sview = [[view window] contentView];
5940       NSArray *subs = [sview subviews];
5942       /* disable optimization stopping redraw of other scrollbars */
5943       view->scrollbarsNeedingUpdate = 0;
5944       for (i =[subs count]-1; i >= 0; i--)
5945         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
5946           view->scrollbarsNeedingUpdate++;
5947       [sview addSubview: self];
5948     }
5950 /*  [self setFrame: r]; */
5952   return self;
5956 - (void)setFrame: (NSRect)newRect
5958   NSTRACE (EmacsScroller_setFrame);
5959 /*  BLOCK_INPUT; */
5960   pixel_height = NSHeight (newRect);
5961   if (pixel_height == 0) pixel_height = 1;
5962   min_portion = 20 / pixel_height;
5963   [super setFrame: newRect];
5964   [self display];
5965 /*  UNBLOCK_INPUT; */
5969 - (void)dealloc
5971   NSTRACE (EmacsScroller_dealloc);
5972   if (!NILP (win))
5973     XWINDOW (win)->vertical_scroll_bar = Qnil;
5974   [super dealloc];
5978 - condemn
5980   NSTRACE (condemn);
5981   condemned =YES;
5982   return self;
5986 - reprieve
5988   NSTRACE (reprieve);
5989   condemned =NO;
5990   return self;
5994 - judge
5996   NSTRACE (judge);
5997   if (condemned)
5998     {
5999       EmacsView *view;
6000       BLOCK_INPUT;
6001       /* ensure other scrollbar updates after deletion */
6002       view = (EmacsView *)FRAME_NS_VIEW (frame);
6003       if (view != nil)
6004         view->scrollbarsNeedingUpdate++;
6005       [self removeFromSuperview];
6006       [self release];
6007       UNBLOCK_INPUT;
6008     }
6009   return self;
6013 - (void)resetCursorRects
6015   NSRect visible = [self visibleRect];
6016   NSTRACE (resetCursorRects);
6018   if (!NSIsEmptyRect (visible))
6019     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6020   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6024 - (int) checkSamePosition: (int) position portion: (int) portion
6025                     whole: (int) whole
6027   return em_position ==position && em_portion ==portion && em_whole ==whole
6028     && portion != whole; /* needed for resize empty buf */
6032 - setPosition: (int)position portion: (int)portion whole: (int)whole
6034   NSTRACE (setPosition);
6036   em_position = position;
6037   em_portion = portion;
6038   em_whole = whole;
6040   if (portion >= whole)
6041     [self setFloatValue: 0.0 knobProportion: 1.0];
6042   else
6043     {
6044       float pos, por;
6045       portion = max ((float)whole*min_portion/pixel_height, portion);
6046       pos = (float)position / (whole - portion);
6047       por = (float)portion/whole;
6048       [self setFloatValue: pos knobProportion: por];
6049     }
6050   return self;
6053 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6054      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6055 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6056                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6058   *part = last_hit_part;
6059   *window = win;
6060   XSETINT (*y, pixel_height);
6061   if ([self floatValue] > 0.999)
6062     XSETINT (*x, pixel_height);
6063   else
6064     XSETINT (*x, pixel_height * [self floatValue]);
6068 /* set up emacs_event */
6069 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6071   if (!emacs_event)
6072     return;
6074   emacs_event->part = last_hit_part;
6075   emacs_event->code = 0;
6076   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6077   emacs_event->frame_or_window = win;
6078   emacs_event->timestamp = EV_TIMESTAMP (e);
6079   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6080   emacs_event->arg = Qnil;
6081   XSETINT (emacs_event->x, loc * pixel_height);
6082   XSETINT (emacs_event->y, pixel_height-20);
6084   n_emacs_events_pending++;
6085   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6086   EVENT_INIT (*emacs_event);
6087   ns_send_appdefined (-1);
6091 /* called manually thru timer to implement repeated button action w/hold-down */
6092 - repeatScroll: (NSTimer *)scrollEntry
6094   NSEvent *e = [[self window] currentEvent];
6095   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6096   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6098   /* clear timer if need be */
6099   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6100     {
6101         [scroll_repeat_entry invalidate];
6102         [scroll_repeat_entry release];
6103         scroll_repeat_entry = nil;
6105         if (inKnob)
6106           return self;
6108         scroll_repeat_entry
6109           = [[NSTimer scheduledTimerWithTimeInterval:
6110                         SCROLL_BAR_CONTINUOUS_DELAY
6111                                             target: self
6112                                           selector: @selector (repeatScroll:)
6113                                           userInfo: 0
6114                                            repeats: YES]
6115               retain];
6116     }
6118   [self sendScrollEventAtLoc: 0 fromEvent: e];
6119   return self;
6123 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6124    mouseDragged events without going into a modal loop. */
6125 - (void)mouseDown: (NSEvent *)e
6127   NSRect sr, kr;
6128   /* hitPart is only updated AFTER event is passed on */
6129   NSScrollerPart part = [self testPart: [e locationInWindow]];
6130   double inc = 0.0, loc, kloc, pos;
6131   int edge = 0;
6133   NSTRACE (EmacsScroller_mouseDown);
6135   switch (part)
6136     {
6137     case NSScrollerDecrementPage:
6138         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6139     case NSScrollerIncrementPage:
6140         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6141     case NSScrollerDecrementLine:
6142       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6143     case NSScrollerIncrementLine:
6144       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6145     case NSScrollerKnob:
6146       last_hit_part = scroll_bar_handle; break;
6147     case NSScrollerKnobSlot:  /* GNUstep-only */
6148       last_hit_part = scroll_bar_move_ratio; break;
6149     default:  /* NSScrollerNoPart? */
6150       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6151                (long) part);
6152       return;
6153     }
6155   if (inc != 0.0)
6156     {
6157       pos = 0;      /* ignored */
6159       /* set a timer to repeat, as we can't let superclass do this modally */
6160       scroll_repeat_entry
6161         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6162                                             target: self
6163                                           selector: @selector (repeatScroll:)
6164                                           userInfo: 0
6165                                            repeats: YES]
6166             retain];
6167     }
6168   else
6169     {
6170       /* handle, or on GNUstep possibly slot */
6171       NSEvent *fake_event;
6173       /* compute float loc in slot and mouse offset on knob */
6174       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6175                       toView: nil];
6176       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6177       if (loc <= 0.0)
6178         {
6179           loc = 0.0;
6180           edge = -1;
6181         }
6182       else if (loc >= NSHeight (sr))
6183         {
6184           loc = NSHeight (sr);
6185           edge = 1;
6186         }
6188       if (edge)
6189         kloc = 0.5 * edge;
6190       else
6191         {
6192           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6193                           toView: nil];
6194           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6195         }
6196       last_mouse_offset = kloc;
6198       /* if knob, tell emacs a location offset by knob pos
6199          (to indicate top of handle) */
6200       if (part == NSScrollerKnob)
6201           pos = (loc - last_mouse_offset) / NSHeight (sr);
6202       else
6203         /* else this is a slot click on GNUstep: go straight there */
6204         pos = loc / NSHeight (sr);
6206       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6207       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6208                                       location: [e locationInWindow]
6209                                  modifierFlags: [e modifierFlags]
6210                                      timestamp: [e timestamp]
6211                                   windowNumber: [e windowNumber]
6212                                        context: [e context]
6213                                    eventNumber: [e eventNumber]
6214                                     clickCount: [e clickCount]
6215                                       pressure: [e pressure]];
6216       [super mouseUp: fake_event];
6217     }
6219   if (part != NSScrollerKnob)
6220     [self sendScrollEventAtLoc: pos fromEvent: e];
6224 /* Called as we manually track scroller drags, rather than superclass. */
6225 - (void)mouseDragged: (NSEvent *)e
6227     NSRect sr;
6228     double loc, pos;
6229     int edge = 0;
6231     NSTRACE (EmacsScroller_mouseDragged);
6233       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6234                       toView: nil];
6235       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6237       if (loc <= 0.0)
6238         {
6239           loc = 0.0;
6240           edge = -1;
6241         }
6242       else if (loc >= NSHeight (sr) + last_mouse_offset)
6243         {
6244           loc = NSHeight (sr) + last_mouse_offset;
6245           edge = 1;
6246         }
6248       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6249       [self sendScrollEventAtLoc: pos fromEvent: e];
6253 - (void)mouseUp: (NSEvent *)e
6255   if (scroll_repeat_entry)
6256     {
6257       [scroll_repeat_entry invalidate];
6258       [scroll_repeat_entry release];
6259       scroll_repeat_entry = nil;
6260     }
6261   last_hit_part = 0;
6265 /* treat scrollwheel events in the bar as though they were in the main window */
6266 - (void) scrollWheel: (NSEvent *)theEvent
6268   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6269   [view mouseDown: theEvent];
6272 @end  /* EmacsScroller */
6277 /* ==========================================================================
6279    Font-related functions; these used to be in nsfaces.m
6281    ========================================================================== */
6284 Lisp_Object
6285 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6287   struct font *font = XFONT_OBJECT (font_object);
6289   if (fontset < 0)
6290     fontset = fontset_from_font (font_object);
6291   FRAME_FONTSET (f) = fontset;
6293   if (FRAME_FONT (f) == font)
6294     /* This font is already set in frame F.  There's nothing more to
6295        do.  */
6296     return font_object;
6298   FRAME_FONT (f) = font;
6300   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6301   FRAME_COLUMN_WIDTH (f) = font->average_width;
6302   FRAME_SPACE_WIDTH (f) = font->space_width;
6303   FRAME_LINE_HEIGHT (f) = font->height;
6305   compute_fringe_widths (f, 1);
6307   /* Compute the scroll bar width in character columns.  */
6308   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6309     {
6310       int wid = FRAME_COLUMN_WIDTH (f);
6311       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6312         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6313     }
6314   else
6315     {
6316       int wid = FRAME_COLUMN_WIDTH (f);
6317       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6318     }
6320   /* Now make the frame display the given font.  */
6321   if (FRAME_NS_WINDOW (f) != 0)
6322         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6324   return font_object;
6328 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6329 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6330          in 1.43. */
6332 const char *
6333 ns_xlfd_to_fontname (const char *xlfd)
6334 /* --------------------------------------------------------------------------
6335     Convert an X font name (XLFD) to an NS font name.
6336     Only family is used.
6337     The string returned is temporarily allocated.
6338    -------------------------------------------------------------------------- */
6340   char *name = xmalloc (180);
6341   int i, len;
6342   const char *ret;
6344   if (!strncmp (xlfd, "--", 2))
6345     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6346   else
6347     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6349   /* stopgap for malformed XLFD input */
6350   if (strlen (name) == 0)
6351     strcpy (name, "Monaco");
6353   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6354      also uppercase after '-' or ' ' */
6355   name[0] = toupper (name[0]);
6356   for (len =strlen (name), i =0; i<len; i++)
6357     {
6358       if (name[i] == '$')
6359         {
6360           name[i] = '-';
6361           if (i+1<len)
6362             name[i+1] = toupper (name[i+1]);
6363         }
6364       else if (name[i] == '_')
6365         {
6366           name[i] = ' ';
6367           if (i+1<len)
6368             name[i+1] = toupper (name[i+1]);
6369         }
6370     }
6371 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6372   ret = [[NSString stringWithUTF8String: name] UTF8String];
6373   xfree (name);
6374   return ret;
6378 void
6379 syms_of_nsterm (void)
6381   NSTRACE (syms_of_nsterm);
6383   ns_antialias_threshold = 10.0;
6385   /* from 23+ we need to tell emacs what modifiers there are.. */
6386   DEFSYM (Qmodifier_value, "modifier-value");
6387   DEFSYM (Qalt, "alt");
6388   DEFSYM (Qhyper, "hyper");
6389   DEFSYM (Qmeta, "meta");
6390   DEFSYM (Qsuper, "super");
6391   DEFSYM (Qcontrol, "control");
6392   DEFSYM (Qnone, "none");
6393   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6394   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6395   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6396   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6397   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6399   DEFVAR_LISP ("ns-input-file", ns_input_file,
6400               "The file specified in the last NS event.");
6401   ns_input_file =Qnil;
6403   DEFVAR_LISP ("ns-input-text", ns_input_text,
6404               "The data received in the last NS text drag event.");
6405   ns_input_text =Qnil;
6407   DEFVAR_LISP ("ns-working-text", ns_working_text,
6408               "String for visualizing working composition sequence.");
6409   ns_working_text =Qnil;
6411   DEFVAR_LISP ("ns-input-font", ns_input_font,
6412               "The font specified in the last NS event.");
6413   ns_input_font =Qnil;
6415   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
6416               "The fontsize specified in the last NS event.");
6417   ns_input_fontsize =Qnil;
6419   DEFVAR_LISP ("ns-input-line", ns_input_line,
6420                "The line specified in the last NS event.");
6421   ns_input_line =Qnil;
6423   DEFVAR_LISP ("ns-input-color", ns_input_color,
6424                "The color specified in the last NS event.");
6425   ns_input_color =Qnil;
6427   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
6428                "The service name specified in the last NS event.");
6429   ns_input_spi_name =Qnil;
6431   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
6432                "The service argument specified in the last NS event.");
6433   ns_input_spi_arg =Qnil;
6435   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
6436                "This variable describes the behavior of the alternate or option key.\n\
6437 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6438 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6439 at all, allowing it to be used at a lower level for accented character entry.");
6440   ns_alternate_modifier = Qmeta;
6442   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
6443                "This variable describes the behavior of the right alternate or option key.\n\
6444 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6445 Set to left means be the same key as `ns-alternate-modifier'.\n\
6446 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6447 at all, allowing it to be used at a lower level for accented character entry.");
6448   ns_right_alternate_modifier = Qleft;
6450   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
6451                "This variable describes the behavior of the command key.\n\
6452 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6453   ns_command_modifier = Qsuper;
6455   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
6456                "This variable describes the behavior of the right command key.\n\
6457 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6458 Set to left means be the same key as `ns-command-modifier'.\n\
6459 Set to none means that the command / option key is not interpreted by Emacs\n\
6460 at all, allowing it to be used at a lower level for accented character entry.");
6461   ns_right_command_modifier = Qleft;
6463   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
6464                "This variable describes the behavior of the control key.\n\
6465 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6466   ns_control_modifier = Qcontrol;
6468   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
6469                "This variable describes the behavior of the right control key.\n\
6470 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6471 Set to left means be the same key as `ns-control-modifier'.\n\
6472 Set to none means that the control / option key is not interpreted by Emacs\n\
6473 at all, allowing it to be used at a lower level for accented character entry.");
6474   ns_right_control_modifier = Qleft;
6476   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
6477                "This variable describes the behavior of the function key (on laptops).\n\
6478 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6479 Set to none means that the function key is not interpreted by Emacs at all,\n\
6480 allowing it to be used at a lower level for accented character entry.");
6481   ns_function_modifier = Qnone;
6483   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
6484                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6485   ns_antialias_text = Qt;
6487   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
6488                "Whether to confirm application quit using dialog.");
6489   ns_confirm_quit = Qnil;
6491   staticpro (&ns_display_name_list);
6492   ns_display_name_list = Qnil;
6494   staticpro (&last_mouse_motion_frame);
6495   last_mouse_motion_frame = Qnil;
6497   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
6498                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
6499 Only works on OSX 10.6 or later.  */);
6500   ns_auto_hide_menu_bar = Qnil;
6502   /* TODO: move to common code */
6503   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
6504                doc: /* If not nil, Emacs uses toolkit scroll bars.  */);
6505 #ifdef USE_TOOLKIT_SCROLL_BARS
6506   Vx_toolkit_scroll_bars = Qt;
6507 #else
6508   Vx_toolkit_scroll_bars = Qnil;
6509 #endif
6511   /* these are unsupported but we need the declarations to avoid whining
6512      messages from cus-start.el */
6513   DEFVAR_BOOL ("x-use-underline-position-properties",
6514                x_use_underline_position_properties,
6515      doc: /* NOT SUPPORTED UNDER NS.
6516 *Non-nil means make use of UNDERLINE_POSITION font properties.
6517 A value of nil means ignore them.  If you encounter fonts with bogus
6518 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6519 to 4.1, set this to nil.
6521 NOTE: Not supported on Mac yet.  */);
6522   x_use_underline_position_properties = 0;
6524   DEFVAR_BOOL ("x-underline-at-descent-line",
6525                x_underline_at_descent_line,
6526      doc: /* NOT SUPPORTED UNDER NS.
6527 *Non-nil means to draw the underline at the same place as the descent line.
6528 A value of nil means to draw the underline according to the value of the
6529 variable `x-use-underline-position-properties', which is usually at the
6530 baseline level.  The default value is nil.  */);
6531   x_underline_at_descent_line = 0;
6533   /* Tell emacs about this window system. */
6534   Fprovide (intern ("ns"), Qnil);