* lisp/progmodes/grep.el (grep-filter): Don't trip on partial lines.
[emacs.git] / src / nsterm.m
blobc4756dc83cdc6ca3ebc1e69ce375c63d09837316
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 unsigned long 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                    unsigned long *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   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4062   if (STRINGP (Vauto_save_list_file_name))
4063     unlink (SDATA (Vauto_save_list_file_name));
4065   if (sig == 0 || sig == SIGTERM)
4066     {
4067       [NSApp terminate: NSApp];
4068     }
4069   else // force a stack trace to happen
4070     {
4071       abort();
4072     }
4076 /* ==========================================================================
4078     EmacsApp implementation
4080    ========================================================================== */
4083 @implementation EmacsApp
4085 - (void)logNotification: (NSNotification *)notification
4087   const char *name = [[notification name] UTF8String];
4088   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4089       && !strstr (name, "WindowNumber"))
4090     NSLog (@"notification: '%@'", [notification name]);
4094 - (void)sendEvent: (NSEvent *)theEvent
4095 /* --------------------------------------------------------------------------
4096      Called when NSApp is running for each event received.  Used to stop
4097      the loop when we choose, since there's no way to just run one iteration.
4098    -------------------------------------------------------------------------- */
4100   int type = [theEvent type];
4101   NSWindow *window = [theEvent window];
4102 /*  NSTRACE (sendEvent); */
4103 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4105   if (type == NSCursorUpdate && window == nil)
4106     {
4107       fprintf (stderr, "Dropping external cursor update event.\n");
4108       return;
4109     }
4111 #ifdef NS_IMPL_COCOA
4112   /* pass mouse down in resize handle and subsequent drags directly to
4113      EmacsWindow so we can generate continuous redisplays */
4114   if (ns_in_resize)
4115     {
4116       if (type == NSLeftMouseDragged)
4117         {
4118           [window mouseDragged: theEvent];
4119           return;
4120         }
4121       else if (type == NSLeftMouseUp)
4122         {
4123           [window mouseUp: theEvent];
4124           return;
4125         }
4126     }
4127   else if (type == NSLeftMouseDown)
4128     {
4129       NSRect r = ns_resize_handle_rect (window);
4130       if (NSPointInRect ([theEvent locationInWindow], r))
4131         {
4132           ns_in_resize = YES;
4133           [window mouseDown: theEvent];
4134           return;
4135         }
4136     }
4137 #endif
4139   if (type == NSApplicationDefined)
4140     {
4141       /* Events posted by ns_send_appdefined interrupt the run loop here.
4142          But, if a modal window is up, an appdefined can still come through,
4143          (e.g., from a makeKeyWindow event) but stopping self also stops the
4144          modal loop. Just defer it until later. */
4145       if ([NSApp modalWindow] == nil)
4146         {
4147           last_appdefined_event = theEvent;
4148           [self stop: self];
4149         }
4150       else
4151         {
4152           send_appdefined = YES;
4153         }
4154     }
4156   [super sendEvent: theEvent];
4160 - (void)showPreferencesWindow: (id)sender
4162   struct frame *emacsframe = SELECTED_FRAME ();
4163   NSEvent *theEvent = [NSApp currentEvent];
4165   if (!emacs_event)
4166     return;
4167   emacs_event->kind = NS_NONKEY_EVENT;
4168   emacs_event->code = KEY_NS_SHOW_PREFS;
4169   emacs_event->modifiers = 0;
4170   EV_TRAILER (theEvent);
4174 - (void)newFrame: (id)sender
4176   struct frame *emacsframe = SELECTED_FRAME ();
4177   NSEvent *theEvent = [NSApp currentEvent];
4179   if (!emacs_event)
4180     return;
4181   emacs_event->kind = NS_NONKEY_EVENT;
4182   emacs_event->code = KEY_NS_NEW_FRAME;
4183   emacs_event->modifiers = 0;
4184   EV_TRAILER (theEvent);
4188 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4189 - (BOOL) openFile: (NSString *)fileName
4191   struct frame *emacsframe = SELECTED_FRAME ();
4192   NSEvent *theEvent = [NSApp currentEvent];
4194   if (!emacs_event)
4195     return NO;
4197   emacs_event->kind = NS_NONKEY_EVENT;
4198   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4199   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4200   ns_input_line = Qnil; /* can be start or cons start,end */
4201   emacs_event->modifiers =0;
4202   EV_TRAILER (theEvent);
4204   return YES;
4208 /* **************************************************************************
4210       EmacsApp delegate implementation
4212    ************************************************************************** */
4214 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4215 /* --------------------------------------------------------------------------
4216      When application is loaded, terminate event loop in ns_term_init
4217    -------------------------------------------------------------------------- */
4219   NSTRACE (applicationDidFinishLaunching);
4220   [NSApp setServicesProvider: NSApp];
4221   ns_send_appdefined (-2);
4225 /* Termination sequences:
4226     C-x C-c:
4227     Cmd-Q:
4228     MenuBar | File | Exit:
4229     Select Quit from App menubar:
4230         -terminate
4231         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4232         ns_term_shutdown()
4234     Select Quit from Dock menu:
4235     Logout attempt:
4236         -appShouldTerminate
4237           Cancel -> Nothing else
4238           Accept ->
4240           -terminate
4241           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4242           ns_term_shutdown()
4246 - (void) terminate: (id)sender
4248   struct frame *emacsframe = SELECTED_FRAME ();
4250   if (!emacs_event)
4251     return;
4253   emacs_event->kind = NS_NONKEY_EVENT;
4254   emacs_event->code = KEY_NS_POWER_OFF;
4255   emacs_event->arg = Qt; /* mark as non-key event */
4256   EV_TRAILER ((id)nil);
4260 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4262   int ret;
4264   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4265     return NSTerminateNow;
4267     ret = NSRunAlertPanel(ns_app_name,
4268                           [NSString stringWithUTF8String:"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?"],
4269                           @"Save Buffers and Exit", @"Cancel", nil);
4271     if (ret == NSAlertDefaultReturn)
4272         return NSTerminateNow;
4273     else if (ret == NSAlertAlternateReturn)
4274         return NSTerminateCancel;
4275     return NSTerminateNow;  /* just in case */
4279 /*   Notification from the Workspace to open a file */
4280 - (BOOL)application: sender openFile: (NSString *)file
4282   [ns_pending_files addObject: file];
4283   return YES;
4287 /*   Open a file as a temporary file */
4288 - (BOOL)application: sender openTempFile: (NSString *)file
4290   [ns_pending_files addObject: file];
4291   return YES;
4295 /*   Notification from the Workspace to open a file noninteractively (?) */
4296 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4298   [ns_pending_files addObject: file];
4299   return YES;
4303 /*   Notification from the Workspace to open multiple files */
4304 - (void)application: sender openFiles: (NSArray *)fileList
4306   NSEnumerator *files = [fileList objectEnumerator];
4307   NSString *file;
4308   while ((file = [files nextObject]) != nil)
4309     [ns_pending_files addObject: file];
4311   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4316 /* Handle dock menu requests.  */
4317 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4319   return dockMenu;
4323 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4324 - (void)applicationWillBecomeActive: (NSNotification *)notification
4326   //ns_app_active=YES;
4328 - (void)applicationDidBecomeActive: (NSNotification *)notification
4330   NSTRACE (applicationDidBecomeActive);
4332   //ns_app_active=YES;
4334   ns_update_auto_hide_menu_bar ();
4335   // No constrining takes place when the application is not active.
4336   ns_constrain_all_frames ();
4338 - (void)applicationDidResignActive: (NSNotification *)notification
4340   //ns_app_active=NO;
4341   ns_send_appdefined (-1);
4346 /* ==========================================================================
4348     EmacsApp aux handlers for managing event loop
4350    ========================================================================== */
4353 - (void)timeout_handler: (NSTimer *)timedEntry
4354 /* --------------------------------------------------------------------------
4355      The timeout specified to ns_select has passed.
4356    -------------------------------------------------------------------------- */
4358   /*NSTRACE (timeout_handler); */
4359   ns_send_appdefined (-2);
4362 - (void)fd_handler: (NSTimer *) fdEntry
4363 /* --------------------------------------------------------------------------
4364      Check data waiting on file descriptors and terminate if so
4365    -------------------------------------------------------------------------- */
4367   int result;
4368   /* NSTRACE (fd_handler); */
4370   if (select_nfds == 0)
4371     return;
4373   memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4375   select_timeout.tv_sec = select_timeout.tv_usec = 0;
4376   result = select (select_nfds, &t_readfds, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
4377                   &select_timeout);
4378   if (result)
4379     {
4380       memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4381       ns_send_appdefined (result);
4382     }
4387 /* ==========================================================================
4389     Service provision
4391    ========================================================================== */
4393 /* called from system: queue for next pass through event loop */
4394 - (void)requestService: (NSPasteboard *)pboard
4395               userData: (NSString *)userData
4396                  error: (NSString **)error
4398   [ns_pending_service_names addObject: userData];
4399   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4400       SDATA (ns_string_from_pasteboard (pboard))]];
4404 /* called from ns_read_socket to clear queue */
4405 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4407   struct frame *emacsframe = SELECTED_FRAME ();
4408   NSEvent *theEvent = [NSApp currentEvent];
4410   if (!emacs_event)
4411     return NO;
4413   emacs_event->kind = NS_NONKEY_EVENT;
4414   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4415   ns_input_spi_name = build_string ([name UTF8String]);
4416   ns_input_spi_arg = build_string ([arg UTF8String]);
4417   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4418   EV_TRAILER (theEvent);
4420   return YES;
4424 @end  /* EmacsApp */
4428 /* ==========================================================================
4430     EmacsView implementation
4432    ========================================================================== */
4435 @implementation EmacsView
4437 /* needed to inform when window closed from LISP */
4438 - (void) setWindowClosing: (BOOL)closing
4440   windowClosing = closing;
4444 - (void)dealloc
4446   NSTRACE (EmacsView_dealloc);
4447   [toolbar release];
4448   [super dealloc];
4452 /* called on font panel selection */
4453 - (void)changeFont: (id)sender
4455   NSEvent *e =[[self window] currentEvent];
4456   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4457   id newFont;
4458   float size;
4460   NSTRACE (changeFont);
4461   if (!emacs_event)
4462     return;
4464   if (newFont = [sender convertFont:
4465                            ((struct nsfont_info *)face->font)->nsfont])
4466     {
4467       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4469       emacs_event->kind = NS_NONKEY_EVENT;
4470       emacs_event->modifiers = 0;
4471       emacs_event->code = KEY_NS_CHANGE_FONT;
4473       size = [newFont pointSize];
4474       ns_input_fontsize = make_number (lrint (size));
4475       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4476       EV_TRAILER (e);
4477     }
4481 - (BOOL)acceptsFirstResponder
4483   NSTRACE (acceptsFirstResponder);
4484   return YES;
4488 - (void)resetCursorRects
4490   NSRect visible = [self visibleRect];
4491   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4492   NSTRACE (resetCursorRects);
4494   if (currentCursor == nil)
4495     currentCursor = [NSCursor arrowCursor];
4497   if (!NSIsEmptyRect (visible))
4498     [self addCursorRect: visible cursor: currentCursor];
4499   [currentCursor setOnMouseEntered: YES];
4504 /*****************************************************************************/
4505 /* Keyboard handling. */
4506 #define NS_KEYLOG 0
4508 - (void)keyDown: (NSEvent *)theEvent
4510   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4511   int code;
4512   unsigned fnKeysym = 0;
4513   int flags;
4514   static NSMutableArray *nsEvArray;
4515   static BOOL firstTime = YES;
4516   int left_is_none;
4518   NSTRACE (keyDown);
4520   /* Rhapsody and OS X give up and down events for the arrow keys */
4521   if (ns_fake_keydown == YES)
4522     ns_fake_keydown = NO;
4523   else if ([theEvent type] != NSKeyDown)
4524     return;
4526   if (!emacs_event)
4527     return;
4529  if (![[self window] isKeyWindow]
4530      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4531      /* we must avoid an infinite loop here. */
4532      && (EmacsView *)[[theEvent window] delegate] != self)
4533    {
4534      /* XXX: There is an occasional condition in which, when Emacs display
4535          updates a different frame from the current one, and temporarily
4536          selects it, then processes some interrupt-driven input
4537          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4538          for some reason that window has its first responder set to the NSView
4539          most recently updated (I guess), which is not the correct one. */
4540      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4541      return;
4542    }
4544   if (nsEvArray == nil)
4545     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4547   [NSCursor setHiddenUntilMouseMoves: YES];
4549   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4550     {
4551       clear_mouse_face (hlinfo);
4552       hlinfo->mouse_face_hidden = 1;
4553     }
4555   if (!processingCompose)
4556     {
4557       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4558         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4559       /* (Carbon way: [theEvent keyCode]) */
4561       /* is it a "function key"? */
4562       fnKeysym = ns_convert_key (code);
4563       if (fnKeysym)
4564         {
4565           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4566              because Emacs treats Delete and KP-Delete same (in simple.el). */
4567           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4568             code = 0xFF08; /* backspace */
4569           else
4570             code = fnKeysym;
4571         }
4573       /* are there modifiers? */
4574       emacs_event->modifiers = 0;
4575       flags = [theEvent modifierFlags];
4577       if (flags & NSHelpKeyMask)
4578           emacs_event->modifiers |= hyper_modifier;
4580       if (flags & NSShiftKeyMask)
4581         emacs_event->modifiers |= shift_modifier;
4583       if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask)
4584         emacs_event->modifiers |= parse_solitary_modifier
4585           (EQ (ns_right_command_modifier, Qleft)
4586            ? ns_command_modifier
4587            : ns_right_command_modifier);
4589       if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask)
4590         {
4591           emacs_event->modifiers |= parse_solitary_modifier
4592             (ns_command_modifier);
4594           /* if super (default), take input manager's word so things like
4595              dvorak / qwerty layout work */
4596           if (EQ (ns_command_modifier, Qsuper)
4597               && !fnKeysym
4598               && [[theEvent characters] length] != 0)
4599             {
4600               /* XXX: the code we get will be unshifted, so if we have
4601                  a shift modifier, must convert ourselves */
4602               if (!(flags & NSShiftKeyMask))
4603                 code = [[theEvent characters] characterAtIndex: 0];
4604 #if 0
4605               /* this is ugly and also requires linking w/Carbon framework
4606                  (for LMGetKbdType) so for now leave this rare (?) case
4607                  undealt with.. in future look into CGEvent methods */
4608               else
4609                 {
4610                   long smv = GetScriptManagerVariable (smKeyScript);
4611                   Handle uchrHandle = GetResource
4612                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4613                   UInt32 dummy = 0;
4614                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4615                                  [[theEvent characters] characterAtIndex: 0],
4616                                  kUCKeyActionDisplay,
4617                                  (flags & ~NSCommandKeyMask) >> 8,
4618                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4619                                  &dummy, 1, &dummy, &code);
4620                   code &= 0xFF;
4621                 }
4622 #endif
4623             }
4624         }
4626       if ((flags & NSRightControlKeyMask) == NSRightControlKeyMask)
4627           emacs_event->modifiers |= parse_solitary_modifier
4628               (EQ (ns_right_control_modifier, Qleft)
4629                ? ns_control_modifier
4630                : ns_right_control_modifier);
4632       if ((flags & NSLeftControlKeyMask) == NSLeftControlKeyMask)
4633         emacs_event->modifiers |= parse_solitary_modifier
4634           (ns_control_modifier);
4636       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4637           emacs_event->modifiers |=
4638             parse_solitary_modifier (ns_function_modifier);
4640       left_is_none = NILP (ns_alternate_modifier)
4641         || EQ (ns_alternate_modifier, Qnone);
4643       if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask)
4644         {
4645           if ((NILP (ns_right_alternate_modifier)
4646                || EQ (ns_right_alternate_modifier, Qnone)
4647                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4648               && !fnKeysym)
4649             {   /* accept pre-interp alt comb */
4650               if ([[theEvent characters] length] > 0)
4651                 code = [[theEvent characters] characterAtIndex: 0];
4652               /*HACK: clear lone shift modifier to stop next if from firing */
4653               if (emacs_event->modifiers == shift_modifier)
4654                 emacs_event->modifiers = 0;
4655             }
4656           else
4657             emacs_event->modifiers |= parse_solitary_modifier
4658               (EQ (ns_right_alternate_modifier, Qleft)
4659                ? ns_alternate_modifier
4660                : ns_right_alternate_modifier);
4661         }
4663       if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask) /* default = meta */
4664         {
4665           if (left_is_none && !fnKeysym)
4666             {   /* accept pre-interp alt comb */
4667               if ([[theEvent characters] length] > 0)
4668                 code = [[theEvent characters] characterAtIndex: 0];
4669               /*HACK: clear lone shift modifier to stop next if from firing */
4670               if (emacs_event->modifiers == shift_modifier)
4671                 emacs_event->modifiers = 0;
4672             }
4673           else
4674               emacs_event->modifiers |=
4675                 parse_solitary_modifier (ns_alternate_modifier);
4676         }
4678   if (NS_KEYLOG)
4679     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4680              code, fnKeysym, flags, emacs_event->modifiers);
4682       /* if it was a function key or had modifiers, pass it directly to emacs */
4683       if (fnKeysym || (emacs_event->modifiers
4684                        && (emacs_event->modifiers != shift_modifier)
4685                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4686 /*[[theEvent characters] length] */
4687         {
4688           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4689           if (code < 0x20)
4690             code |= (1<<28)|(3<<16);
4691           else if (code == 0x7f)
4692             code |= (1<<28)|(3<<16);
4693           else if (!fnKeysym)
4694             emacs_event->kind = code > 0xFF
4695               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4697           emacs_event->code = code;
4698           EV_TRAILER (theEvent);
4699           return;
4700         }
4701     }
4703   /* if we get here we should send the key for input manager processing */
4704   if (firstTime && [[NSInputManager currentInputManager]
4705                      wantsToDelayTextChangeNotifications] == NO)
4706     fprintf (stderr,
4707           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4708   firstTime = NO;
4710   if (NS_KEYLOG && !processingCompose)
4711     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4713   processingCompose = YES;
4714   [nsEvArray addObject: theEvent];
4715   [self interpretKeyEvents: nsEvArray];
4716   [nsEvArray removeObject: theEvent];
4720 #ifdef NS_IMPL_COCOA
4721 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4722    decided not to send key-down for.
4723    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4724    This only applies on Tiger and earlier.
4725    If it matches one of these, send it on to keyDown. */
4726 -(void)keyUp: (NSEvent *)theEvent
4728   int flags = [theEvent modifierFlags];
4729   int code = [theEvent keyCode];
4730   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
4731       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4732     {
4733       if (NS_KEYLOG)
4734         fprintf (stderr, "keyUp: passed test");
4735       ns_fake_keydown = YES;
4736       [self keyDown: theEvent];
4737     }
4739 #endif
4742 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4745 /* <NSTextInput>: called when done composing;
4746    NOTE: also called when we delete over working text, followed immed.
4747          by doCommandBySelector: deleteBackward: */
4748 - (void)insertText: (id)aString
4750   int code;
4751   int len = [(NSString *)aString length];
4752   int i;
4754   if (NS_KEYLOG)
4755     NSLog (@"insertText '%@'\tlen = %d", aString, len);
4756   processingCompose = NO;
4758   if (!emacs_event)
4759     return;
4761   /* first, clear any working text */
4762   if (workingText != nil)
4763     [self deleteWorkingText];
4765   /* now insert the string as keystrokes */
4766   for (i =0; i<len; i++)
4767     {
4768       code = [aString characterAtIndex: i];
4769       /* TODO: still need this? */
4770       if (code == 0x2DC)
4771         code = '~'; /* 0x7E */
4772       emacs_event->modifiers = 0;
4773       emacs_event->kind
4774         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4775       emacs_event->code = code;
4776       EV_TRAILER ((id)nil);
4777     }
4781 /* <NSTextInput>: inserts display of composing characters */
4782 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
4784   NSString *str = [aString respondsToSelector: @selector (string)] ?
4785     [aString string] : aString;
4786   if (NS_KEYLOG)
4787     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
4788            selRange.length, selRange.location);
4790   if (workingText != nil)
4791     [self deleteWorkingText];
4792   if ([str length] == 0)
4793     return;
4795   if (!emacs_event)
4796     return;
4798   processingCompose = YES;
4799   workingText = [str copy];
4800   ns_working_text = build_string ([workingText UTF8String]);
4802   emacs_event->kind = NS_TEXT_EVENT;
4803   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
4804   EV_TRAILER ((id)nil);
4808 /* delete display of composing characters [not in <NSTextInput>] */
4809 - (void)deleteWorkingText
4811   if (workingText == nil)
4812     return;
4813   if (NS_KEYLOG)
4814     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
4815   [workingText release];
4816   workingText = nil;
4817   processingCompose = NO;
4819   if (!emacs_event)
4820     return;
4822   emacs_event->kind = NS_TEXT_EVENT;
4823   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
4824   EV_TRAILER ((id)nil);
4828 - (BOOL)hasMarkedText
4830   return workingText != nil;
4834 - (NSRange)markedRange
4836   NSRange rng = workingText != nil
4837     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
4838   if (NS_KEYLOG)
4839     NSLog (@"markedRange request");
4840   return rng;
4844 - (void)unmarkText
4846   if (NS_KEYLOG)
4847     NSLog (@"unmark (accept) text");
4848   [self deleteWorkingText];
4849   processingCompose = NO;
4853 /* used to position char selection windows, etc. */
4854 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
4856   NSRect rect;
4857   NSPoint pt;
4858   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
4859   if (NS_KEYLOG)
4860     NSLog (@"firstRectForCharRange request");
4862   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
4863   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
4864   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
4865   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
4866                                        +FRAME_LINE_HEIGHT (emacsframe));
4868   pt = [self convertPoint: pt toView: nil];
4869   pt = [[self window] convertBaseToScreen: pt];
4870   rect.origin = pt;
4871   return rect;
4875 - (long)conversationIdentifier
4877   return (long)self;
4881 - (void)doCommandBySelector: (SEL)aSelector
4883   if (NS_KEYLOG)
4884     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
4886   if (aSelector == @selector (deleteBackward:))
4887     {
4888       /* happens when user backspaces over an ongoing composition:
4889          throw a 'delete' into the event queue */
4890       if (!emacs_event)
4891         return;
4892       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4893       emacs_event->code = 0xFF08;
4894       EV_TRAILER ((id)nil);
4895     }
4898 - (NSArray *)validAttributesForMarkedText
4900   static NSArray *arr = nil;
4901   if (arr == nil) arr = [NSArray new];
4902  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
4903   return arr;
4906 - (NSRange)selectedRange
4908   if (NS_KEYLOG)
4909     NSLog (@"selectedRange request");
4910   return NSMakeRange (NSNotFound, 0);
4913 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
4915   if (NS_KEYLOG)
4916     NSLog (@"characterIndexForPoint request");
4917   return 0;
4920 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
4922   static NSAttributedString *str = nil;
4923   if (str == nil) str = [NSAttributedString new];
4924   if (NS_KEYLOG)
4925     NSLog (@"attributedSubstringFromRange request");
4926   return str;
4929 /* End <NSTextInput> impl. */
4930 /*****************************************************************************/
4933 /* This is what happens when the user presses a mouse button.  */
4934 - (void)mouseDown: (NSEvent *)theEvent
4936   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
4937   Lisp_Object window;
4939   NSTRACE (mouseDown);
4941   [self deleteWorkingText];
4943   if (!emacs_event)
4944     return;
4946   last_mouse_frame = emacsframe;
4947   /* appears to be needed to prevent spurious movement events generated on
4948      button clicks */
4949   last_mouse_frame->mouse_moved = 0;
4951   if ([theEvent type] == NSScrollWheel)
4952     {
4953       float delta = [theEvent deltaY];
4954       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
4955       if (delta == 0)
4956         return;
4957       emacs_event->kind = WHEEL_EVENT;
4958       emacs_event->code = 0;
4959       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
4960         ((delta > 0) ? up_modifier : down_modifier);
4961     }
4962   else
4963     {
4964       emacs_event->kind = MOUSE_CLICK_EVENT;
4965       emacs_event->code = EV_BUTTON (theEvent);
4966       emacs_event->modifiers = EV_MODIFIERS (theEvent)
4967                              | EV_UDMODIFIERS (theEvent);
4968     }
4969   XSETINT (emacs_event->x, lrint (p.x));
4970   XSETINT (emacs_event->y, lrint (p.y));
4971   EV_TRAILER (theEvent);
4975 - (void)rightMouseDown: (NSEvent *)theEvent
4977   NSTRACE (rightMouseDown);
4978   [self mouseDown: theEvent];
4982 - (void)otherMouseDown: (NSEvent *)theEvent
4984   NSTRACE (otherMouseDown);
4985   [self mouseDown: theEvent];
4989 - (void)mouseUp: (NSEvent *)theEvent
4991   NSTRACE (mouseUp);
4992   [self mouseDown: theEvent];
4996 - (void)rightMouseUp: (NSEvent *)theEvent
4998   NSTRACE (rightMouseUp);
4999   [self mouseDown: theEvent];
5003 - (void)otherMouseUp: (NSEvent *)theEvent
5005   NSTRACE (otherMouseUp);
5006   [self mouseDown: theEvent];
5010 - (void) scrollWheel: (NSEvent *)theEvent
5012   NSTRACE (scrollWheel);
5013   [self mouseDown: theEvent];
5017 /* Tell emacs the mouse has moved. */
5018 - (void)mouseMoved: (NSEvent *)e
5020   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5021   Lisp_Object frame;
5023 //  NSTRACE (mouseMoved);
5025   last_mouse_movement_time = EV_TIMESTAMP (e);
5026   last_mouse_motion_position
5027     = [self convertPoint: [e locationInWindow] fromView: nil];
5029   /* update any mouse face */
5030   if (hlinfo->mouse_face_hidden)
5031     {
5032       hlinfo->mouse_face_hidden = 0;
5033       clear_mouse_face (hlinfo);
5034     }
5036   /* tooltip handling */
5037   previous_help_echo_string = help_echo_string;
5038   help_echo_string = Qnil;
5040   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5041                             last_mouse_motion_position.y))
5042     help_echo_string = previous_help_echo_string;
5044   XSETFRAME (frame, emacsframe);
5045   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5046     {
5047       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5048          (note_mouse_highlight), which is called through the
5049          note_mouse_movement () call above */
5050       gen_help_event (help_echo_string, frame, help_echo_window,
5051                       help_echo_object, help_echo_pos);
5052     }
5053   else
5054     {
5055       help_echo_string = Qnil;
5056       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5057     }
5059   if (emacsframe->mouse_moved && send_appdefined)
5060     ns_send_appdefined (-1);
5064 - (void)mouseDragged: (NSEvent *)e
5066   NSTRACE (mouseDragged);
5067   [self mouseMoved: e];
5071 - (void)rightMouseDragged: (NSEvent *)e
5073   NSTRACE (rightMouseDragged);
5074   [self mouseMoved: e];
5078 - (void)otherMouseDragged: (NSEvent *)e
5080   NSTRACE (otherMouseDragged);
5081   [self mouseMoved: e];
5085 - (BOOL)windowShouldClose: (id)sender
5087   NSEvent *e =[[self window] currentEvent];
5089   NSTRACE (windowShouldClose);
5090   windowClosing = YES;
5091   if (!emacs_event)
5092     return NO;
5093   emacs_event->kind = DELETE_WINDOW_EVENT;
5094   emacs_event->modifiers = 0;
5095   emacs_event->code = 0;
5096   EV_TRAILER (e);
5097   /* Don't close this window, let this be done from lisp code.  */
5098   return NO;
5102 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5103 /* normalize frame to gridded text size */
5105   NSTRACE (windowWillResize);
5106 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5108   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5109 #ifdef NS_IMPL_GNUSTEP
5110                                         frameSize.width + 3);
5111 #else
5112                                         frameSize.width);
5113 #endif
5114   if (cols < MINWIDTH)
5115     cols = MINWIDTH;
5117   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
5118 #ifdef NS_IMPL_GNUSTEP
5119       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
5120         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5121 #else
5122       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5123         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5124 #endif
5125   if (rows < MINHEIGHT)
5126     rows = MINHEIGHT;
5127 #ifdef NS_IMPL_COCOA
5128   {
5129     /* this sets window title to have size in it; the wm does this under GS */
5130     NSRect r = [[self window] frame];
5131     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5132       {
5133         if (old_title != 0)
5134           {
5135             xfree (old_title);
5136             old_title = 0;
5137           }
5138       }
5139     else
5140       {
5141         char *size_title;
5142         NSWindow *window = [self window];
5143         if (old_title == 0)
5144           {
5145             const char *t = [[[self window] title] UTF8String];
5146             char *pos = strstr (t, "  â€”  ");
5147             if (pos)
5148               *pos = '\0';
5149             old_title = (char *) xmalloc (strlen (t) + 1);
5150             strcpy (old_title, t);
5151           }
5152         size_title = xmalloc (strlen (old_title) + 40);
5153         sprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5154         [window setTitle: [NSString stringWithUTF8String: size_title]];
5155         [window display];
5156         xfree (size_title);
5157       }
5158   }
5159 #endif /* NS_IMPL_COCOA */
5160 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5162   return frameSize;
5166 - (void)windowDidResize: (NSNotification *)notification
5168   NSWindow *theWindow = [notification object];
5170 #ifdef NS_IMPL_GNUSTEP
5171    /* in GNUstep, at least currently, it's possible to get a didResize
5172       without getting a willResize.. therefore we need to act as if we got
5173       the willResize now */
5174   NSSize sz = [theWindow frame].size;
5175   sz = [self windowWillResize: theWindow toSize: sz];
5176 #endif /* NS_IMPL_GNUSTEP */
5178   NSTRACE (windowDidResize);
5179 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5181 #ifdef NS_IMPL_COCOA
5182   if (old_title != 0)
5183     {
5184       xfree (old_title);
5185       old_title = 0;
5186     }
5187 #endif /* NS_IMPL_COCOA */
5189   /* Avoid loop under GNUstep due to call at beginning of this function.
5190      (x_set_window_size causes a resize which causes
5191      a "windowDidResize" which calls x_set_window_size).  */
5192 #ifndef NS_IMPL_GNUSTEP
5193   if (cols > 0 && rows > 0)
5194     x_set_window_size (emacsframe, 0, cols, rows);
5195 #endif
5197   ns_send_appdefined (-1);
5201 - (void)windowDidBecomeKey: (NSNotification *)notification
5202 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5204   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5205   struct frame *old_focus = dpyinfo->x_focus_frame;
5207   NSTRACE (windowDidBecomeKey);
5209   if (emacsframe != old_focus)
5210     dpyinfo->x_focus_frame = emacsframe;
5212   ns_frame_rehighlight (emacsframe);
5214   if (emacs_event)
5215     {
5216       emacs_event->kind = FOCUS_IN_EVENT;
5217       EV_TRAILER ((id)nil);
5218     }
5222 - (void)windowDidResignKey: (NSNotification *)notification
5223 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5225   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5226   NSTRACE (windowDidResignKey);
5228   if (dpyinfo->x_focus_frame == emacsframe)
5229     dpyinfo->x_focus_frame = 0;
5231   ns_frame_rehighlight (emacsframe);
5233   /* FIXME: for some reason needed on second and subsequent clicks away
5234             from sole-frame Emacs to get hollow box to show */
5235   if (!windowClosing && [[self window] isVisible] == YES)
5236     {
5237       x_update_cursor (emacsframe, 1);
5238       x_set_frame_alpha (emacsframe);
5239     }
5241   if (emacs_event)
5242     {
5243       [self deleteWorkingText];
5244       emacs_event->kind = FOCUS_IN_EVENT;
5245       EV_TRAILER ((id)nil);
5246     }
5250 - (void)windowWillMiniaturize: sender
5252   NSTRACE (windowWillMiniaturize);
5256 - (BOOL)isFlipped
5258   return YES;
5262 - (BOOL)isOpaque
5264   return NO;
5268 - initFrameFromEmacs: (struct frame *)f
5270   NSRect r, wr;
5271   Lisp_Object tem;
5272   NSWindow *win;
5273   NSButton *toggleButton;
5274   int vbextra = NS_SCROLL_BAR_WIDTH (f);
5275   NSSize sz;
5276   NSColor *col;
5277   NSString *name;
5279   NSTRACE (initFrameFromEmacs);
5281   windowClosing = NO;
5282   processingCompose = NO;
5283   scrollbarsNeedingUpdate = 0;
5285 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5287   ns_userRect = NSMakeRect (0, 0, 0, 0);
5288   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5289                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5290   [self initWithFrame: r];
5291   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5293   FRAME_NS_VIEW (f) = self;
5294   emacsframe = f;
5295   old_title = 0;
5297   win = [[EmacsWindow alloc]
5298             initWithContentRect: r
5299                       styleMask: (NSResizableWindowMask |
5300                                   NSMiniaturizableWindowMask |
5301                                   NSClosableWindowMask)
5302                         backing: NSBackingStoreBuffered
5303                           defer: YES];
5305   wr = [win frame];
5306   f->border_width = wr.size.width - r.size.width;
5307   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5309   [win setAcceptsMouseMovedEvents: YES];
5310   [win setDelegate: self];
5311   [win useOptimizedDrawing: YES];
5313   sz.width = FRAME_COLUMN_WIDTH (f);
5314   sz.height = FRAME_LINE_HEIGHT (f);
5315   [win setResizeIncrements: sz];
5317   [[win contentView] addSubview: self];
5319   if (ns_drag_types)
5320     [self registerForDraggedTypes: ns_drag_types];
5322   tem = f->name;
5323   name = [NSString stringWithUTF8String:
5324                    NILP (tem) ? (unsigned char *)"Emacs" : SDATA (tem)];
5325   [win setTitle: name];
5327   /* toolbar support */
5328   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5329                          [NSString stringWithFormat: @"Emacs Frame %d",
5330                                    ns_window_num]];
5331   [win setToolbar: toolbar];
5332   [toolbar setVisible: NO];
5333 #ifdef NS_IMPL_COCOA
5334   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5335   [toggleButton setTarget: self];
5336   [toggleButton setAction: @selector (toggleToolbar: )];
5337 #endif
5338   FRAME_TOOLBAR_HEIGHT (f) = 0;
5340   tem = f->icon_name;
5341   if (!NILP (tem))
5342     [win setMiniwindowTitle:
5343            [NSString stringWithUTF8String: SDATA (tem)]];
5345   {
5346     NSScreen *screen = [win screen];
5348     if (screen != 0)
5349       [win setFrameTopLeftPoint: NSMakePoint
5350            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5351             IN_BOUND (-SCREENMAX,
5352                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5353   }
5355   [win makeFirstResponder: self];
5357   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5358                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5359   [win setBackgroundColor: col];
5360   if ([col alphaComponent] != 1.0)
5361     [win setOpaque: NO];
5363   [self allocateGState];
5365   ns_window_num++;
5366   return self;
5370 - (void)windowDidMove: sender
5372   NSWindow *win = [self window];
5373   NSRect r = [win frame];
5374   NSArray *screens = [NSScreen screens];
5375   NSScreen *screen = [screens objectAtIndex: 0];
5377   NSTRACE (windowDidMove);
5379   if (!emacsframe->output_data.ns)
5380     return;
5381   if (screen != nil)
5382     {
5383       emacsframe->left_pos = r.origin.x;
5384       emacsframe->top_pos =
5385         [screen frame].size.height - (r.origin.y + r.size.height);
5386     }
5390 /* Called AFTER method below, but before our windowWillResize call there leads
5391    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5392    location so set_window_size moves the frame. */
5393 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5395   emacsframe->output_data.ns->zooming = 1;
5396   return YES;
5400 /* Override to do something slightly nonstandard, but nice.  First click on
5401    zoom button will zoom vertically.  Second will zoom completely.  Third
5402    returns to original. */
5403 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5404                         defaultFrame:(NSRect)defaultFrame
5406   NSRect result = [sender frame];
5408   NSTRACE (windowWillUseStandardFrame);
5410   if (abs (defaultFrame.size.height - result.size.height)
5411       > FRAME_LINE_HEIGHT (emacsframe))
5412     {
5413       /* first click */
5414       ns_userRect = result;
5415       result.size.height = defaultFrame.size.height;
5416       result.origin.y = defaultFrame.origin.y;
5417     }
5418   else
5419     {
5420       if (abs (defaultFrame.size.width - result.size.width)
5421           > FRAME_COLUMN_WIDTH (emacsframe))
5422         result = defaultFrame;  /* second click */
5423       else
5424         {
5425           /* restore */
5426           result = ns_userRect.size.height ? ns_userRect : result;
5427           ns_userRect = NSMakeRect (0, 0, 0, 0);
5428         }
5429     }
5431   [self windowWillResize: sender toSize: result.size];
5432   return result;
5436 - (void)windowDidDeminiaturize: sender
5438   NSTRACE (windowDidDeminiaturize);
5439   if (!emacsframe->output_data.ns)
5440     return;
5441   emacsframe->async_iconified = 0;
5442   emacsframe->async_visible   = 1;
5443   windows_or_buffers_changed++;
5445   if (emacs_event)
5446     {
5447       emacs_event->kind = ICONIFY_EVENT;
5448       EV_TRAILER ((id)nil);
5449     }
5453 - (void)windowDidExpose: sender
5455   NSTRACE (windowDidExpose);
5456   if (!emacsframe->output_data.ns)
5457     return;
5458   emacsframe->async_visible = 1;
5459   SET_FRAME_GARBAGED (emacsframe);
5461   if (send_appdefined)
5462     ns_send_appdefined (-1);
5466 - (void)windowDidMiniaturize: sender
5468   NSTRACE (windowDidMiniaturize);
5469   if (!emacsframe->output_data.ns)
5470     return;
5472   emacsframe->async_iconified = 1;
5473   emacsframe->async_visible = 0;
5475   if (emacs_event)
5476     {
5477       emacs_event->kind = ICONIFY_EVENT;
5478       EV_TRAILER ((id)nil);
5479     }
5483 - (void)mouseEntered: (NSEvent *)theEvent
5485   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5486   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5487   NSTRACE (mouseEntered);
5489   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5493 - (void)mouseExited: (NSEvent *)theEvent
5495   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5496   NSRect r;
5497   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
5499   NSTRACE (mouseExited);
5501   if (!hlinfo)
5502     return;
5504   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5506   if (emacsframe == hlinfo->mouse_face_mouse_frame)
5507     {
5508       clear_mouse_face (hlinfo);
5509       hlinfo->mouse_face_mouse_frame = 0;
5510     }
5514 - menuDown: sender
5516   NSTRACE (menuDown);
5517   if (context_menu_value == -1)
5518     context_menu_value = [sender tag];
5519   else
5520     find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5521                                   emacsframe->menu_bar_vector,
5522                                   (void *)[sender tag]);
5523   ns_send_appdefined (-1);
5524   return self;
5528 - (EmacsToolbar *)toolbar
5530   return toolbar;
5534 /* this gets called on toolbar button click */
5535 - toolbarClicked: (id)item
5537   NSEvent *theEvent;
5538   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5540   NSTRACE (toolbarClicked);
5542   if (!emacs_event)
5543     return self;
5545   /* send first event (for some reason two needed) */
5546   theEvent = [[self window] currentEvent];
5547   emacs_event->kind = TOOL_BAR_EVENT;
5548   XSETFRAME (emacs_event->arg, emacsframe);
5549   EV_TRAILER (theEvent);
5551   emacs_event->kind = TOOL_BAR_EVENT;
5552 /*   XSETINT (emacs_event->code, 0); */
5553   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5554                           idx + TOOL_BAR_ITEM_KEY);
5555   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5556   EV_TRAILER (theEvent);
5557   return self;
5561 - toggleToolbar: (id)sender
5563   if (!emacs_event)
5564     return self;
5566   emacs_event->kind = NS_NONKEY_EVENT;
5567   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
5568   EV_TRAILER ((id)nil);
5569   return self;
5573 - (void)drawRect: (NSRect)rect
5575   int x = NSMinX (rect), y = NSMinY (rect);
5576   int width = NSWidth (rect), height = NSHeight (rect);
5578   NSTRACE (drawRect);
5580   if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
5581     return;
5583   ns_clear_frame_area (emacsframe, x, y, width, height);
5584   expose_frame (emacsframe, x, y, width, height);
5586   /*
5587     drawRect: may be called (at least in OS X 10.5) for invisible
5588     views as well for some reason.  Thus, do not infer visibility
5589     here.
5591     emacsframe->async_visible = 1;
5592     emacsframe->async_iconified = 0;
5593   */
5597 /* NSDraggingDestination protocol methods.  Actually this is not really a
5598    protocol, but a category of Object.  O well...  */
5600 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
5602   NSTRACE (draggingEntered);
5603   return NSDragOperationGeneric;
5607 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5609   return YES;
5613 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5615   id pb;
5616   int x, y;
5617   NSString *type;
5618   NSEvent *theEvent = [[self window] currentEvent];
5619   NSPoint position;
5621   NSTRACE (performDragOperation);
5623   if (!emacs_event)
5624     return NO;
5626   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5627   x = lrint (position.x);  y = lrint (position.y);
5629   pb = [sender draggingPasteboard];
5630   type = [pb availableTypeFromArray: ns_drag_types];
5631   if (type == 0)
5632     {
5633       return NO;
5634     }
5635   else if ([type isEqualToString: NSFilenamesPboardType])
5636     {
5637       NSArray *files;
5638       NSEnumerator *fenum;
5639       NSString *file;
5641       if (!(files = [pb propertyListForType: type]))
5642         return NO;
5644       fenum = [files objectEnumerator];
5645       while ( (file = [fenum nextObject]) )
5646         {
5647           emacs_event->kind = NS_NONKEY_EVENT;
5648           emacs_event->code = KEY_NS_DRAG_FILE;
5649           XSETINT (emacs_event->x, x);
5650           XSETINT (emacs_event->y, y);
5651           ns_input_file = append2 (ns_input_file,
5652                                    build_string ([file UTF8String]));
5653           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5654           EV_TRAILER (theEvent);
5655         }
5656       return YES;
5657     }
5658   else if ([type isEqualToString: NSURLPboardType])
5659     {
5660       NSString *file;
5661       NSURL *fileURL;
5663       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5664           [fileURL isFileURL] == NO)
5665         return NO;
5667       file = [fileURL path];
5668       emacs_event->kind = NS_NONKEY_EVENT;
5669       emacs_event->code = KEY_NS_DRAG_FILE;
5670       XSETINT (emacs_event->x, x);
5671       XSETINT (emacs_event->y, y);
5672       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5673       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5674       EV_TRAILER (theEvent);
5675       return YES;
5676     }
5677   else if ([type isEqualToString: NSStringPboardType]
5678            || [type isEqualToString: NSTabularTextPboardType])
5679     {
5680       NSString *data;
5682       if (! (data = [pb stringForType: type]))
5683         return NO;
5685       emacs_event->kind = NS_NONKEY_EVENT;
5686       emacs_event->code = KEY_NS_DRAG_TEXT;
5687       XSETINT (emacs_event->x, x);
5688       XSETINT (emacs_event->y, y);
5689       ns_input_text = build_string ([data UTF8String]);
5690       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5691       EV_TRAILER (theEvent);
5692       return YES;
5693     }
5694   else if ([type isEqualToString: NSColorPboardType])
5695     {
5696       NSColor *c = [NSColor colorFromPasteboard: pb];
5697       emacs_event->kind = NS_NONKEY_EVENT;
5698       emacs_event->code = KEY_NS_DRAG_COLOR;
5699       XSETINT (emacs_event->x, x);
5700       XSETINT (emacs_event->y, y);
5701       ns_input_color = ns_color_to_lisp (c);
5702       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5703       EV_TRAILER (theEvent);
5704       return YES;
5705     }
5706   else if ([type isEqualToString: NSFontPboardType])
5707     {
5708       /* impl based on GNUstep NSTextView.m */
5709       NSData *data = [pb dataForType: NSFontPboardType];
5710       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5711       NSFont *font = [dict objectForKey: NSFontAttributeName];
5712       char fontSize[10];
5714       if (font == nil)
5715         return NO;
5717       emacs_event->kind = NS_NONKEY_EVENT;
5718       emacs_event->code = KEY_NS_CHANGE_FONT;
5719       XSETINT (emacs_event->x, x);
5720       XSETINT (emacs_event->y, y);
5721       ns_input_font = build_string ([[font fontName] UTF8String]);
5722       snprintf (fontSize, 10, "%f", [font pointSize]);
5723       ns_input_fontsize = build_string (fontSize);
5724       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5725       EV_TRAILER (theEvent);
5726       return YES;
5727     }
5728   else
5729     {
5730       error ("Invalid data type in dragging pasteboard.");
5731       return NO;
5732     }
5736 - validRequestorForSendType: (NSString *)typeSent
5737                  returnType: (NSString *)typeReturned
5739   NSTRACE (validRequestorForSendType);
5740   if ([ns_send_types indexOfObjectIdenticalTo: typeSent] != NSNotFound &&
5741       [ns_return_types indexOfObjectIdenticalTo: typeSent] != NSNotFound)
5742     return self;
5744   return [super validRequestorForSendType: typeSent
5745                                returnType: typeReturned];
5749 /* The next two methods are part of NSServicesRequests informal protocol,
5750    supposedly called when a services menu item is chosen from this app.
5751    But this should not happen because we override the services menu with our
5752    own entries which call ns-perform-service.
5753    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
5754    So let's at least stub them out until further investigation can be done. */
5756 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
5758   /* we could call ns_string_from_pasteboard(pboard) here but then it should
5759      be written into the buffer in place of the existing selection..
5760      ordinary service calls go through functions defined in ns-win.el */
5761   return NO;
5764 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
5766   /* supposed to write for as many of types as we are able */
5767   return NO;
5771 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
5772    (gives a miniaturized version of the window); currently we use the latter for
5773    frames whose active buffer doesn't correspond to any file
5774    (e.g., '*scratch*') */
5775 - setMiniwindowImage: (BOOL) setMini
5777   id image = [[self window] miniwindowImage];
5778   NSTRACE (setMiniwindowImage);
5780   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
5781      about "AppleDockIconEnabled" notwithstanding, however the set message
5782      below has its effect nonetheless. */
5783   if (image != emacsframe->output_data.ns->miniimage)
5784     {
5785       if (image && [image isKindOfClass: [EmacsImage class]])
5786         [image release];
5787       [[self window] setMiniwindowImage:
5788                        setMini ? emacsframe->output_data.ns->miniimage : nil];
5789     }
5791   return self;
5795 - (void) setRows: (int) r andColumns: (int) c
5797   rows = r;
5798   cols = c;
5801 @end  /* EmacsView */
5805 /* ==========================================================================
5807     EmacsWindow implementation
5809    ========================================================================== */
5811 @implementation EmacsWindow
5813 /* If we have multiple monitors, one above the other, we don't want to
5814    restrict the height to just one monitor.  So we override this.  */
5815 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
5817   /* When making the frame visible for the first time, we want to
5818      constrain.  Other times not.  */
5819   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
5820   NSTRACE (constrainFrameRect);
5822   if (f->output_data.ns->dont_constrain
5823       || ns_menu_bar_should_be_hidden ())
5824     return frameRect;
5826   f->output_data.ns->dont_constrain = 1;
5827   return [super constrainFrameRect:frameRect toScreen:screen];
5831 /* called only on resize clicks by special case in EmacsApp-sendEvent */
5832 - (void)mouseDown: (NSEvent *)theEvent
5834   if (ns_in_resize)
5835     {
5836       NSSize size = [[theEvent window] frame].size;
5837       grabOffset = [theEvent locationInWindow];
5838       grabOffset.x = size.width - grabOffset.x;
5839     }
5840   else
5841     [super mouseDown: theEvent];
5845 /* stop resizing */
5846 - (void)mouseUp: (NSEvent *)theEvent
5848   if (ns_in_resize)
5849     {
5850       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
5851       ns_in_resize = NO;
5852       ns_set_name_as_filename (f);
5853       [self display];
5854       ns_send_appdefined (-1);
5855     }
5856   else
5857     [super mouseUp: theEvent];
5861 /* send resize events */
5862 - (void)mouseDragged: (NSEvent *)theEvent
5864   if (ns_in_resize)
5865     {
5866       NSPoint p = [theEvent locationInWindow];
5867       NSSize size, vettedSize, origSize = [self frame].size;
5869       size.width = p.x + grabOffset.x;
5870       size.height = origSize.height - p.y + grabOffset.y;
5872       if (size.width == origSize.width && size.height == origSize.height)
5873         return;
5875       vettedSize = [[self delegate] windowWillResize: self toSize: size];
5876       [[NSNotificationCenter defaultCenter]
5877             postNotificationName: NSWindowDidResizeNotification
5878                           object: self];
5879     }
5880   else
5881     [super mouseDragged: theEvent];
5884 @end /* EmacsWindow */
5887 /* ==========================================================================
5889     EmacsScroller implementation
5891    ========================================================================== */
5894 @implementation EmacsScroller
5896 /* for repeat button push */
5897 #define SCROLL_BAR_FIRST_DELAY 0.5
5898 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
5900 + (CGFloat) scrollerWidth
5902   /* TODO: if we want to allow variable widths, this is the place to do it,
5903            however neither GNUstep nor Cocoa support it very well */
5904   return [NSScroller scrollerWidth];
5908 - initFrame: (NSRect )r window: (Lisp_Object)nwin
5910   NSTRACE (EmacsScroller_initFrame);
5912   r.size.width = [EmacsScroller scrollerWidth];
5913   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
5914   [self setContinuous: YES];
5915   [self setEnabled: YES];
5917   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
5918      locked against the top and bottom edges, and right edge on OS X, where
5919      scrollers are on right. */
5920 #ifdef NS_IMPL_GNUSTEP
5921   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
5922 #else
5923   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
5924 #endif
5926   win = nwin;
5927   condemned = NO;
5928   pixel_height = NSHeight (r);
5929   if (pixel_height == 0) pixel_height = 1;
5930   min_portion = 20 / pixel_height;
5932   frame = XFRAME (XWINDOW (win)->frame);
5933   if (FRAME_LIVE_P (frame))
5934     {
5935       int i;
5936       EmacsView *view = FRAME_NS_VIEW (frame);
5937       NSView *sview = [[view window] contentView];
5938       NSArray *subs = [sview subviews];
5940       /* disable optimization stopping redraw of other scrollbars */
5941       view->scrollbarsNeedingUpdate = 0;
5942       for (i =[subs count]-1; i >= 0; i--)
5943         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
5944           view->scrollbarsNeedingUpdate++;
5945       [sview addSubview: self];
5946     }
5948 /*  [self setFrame: r]; */
5950   return self;
5954 - (void)setFrame: (NSRect)newRect
5956   NSTRACE (EmacsScroller_setFrame);
5957 /*  BLOCK_INPUT; */
5958   pixel_height = NSHeight (newRect);
5959   if (pixel_height == 0) pixel_height = 1;
5960   min_portion = 20 / pixel_height;
5961   [super setFrame: newRect];
5962   [self display];
5963 /*  UNBLOCK_INPUT; */
5967 - (void)dealloc
5969   NSTRACE (EmacsScroller_dealloc);
5970   if (!NILP (win))
5971     XWINDOW (win)->vertical_scroll_bar = Qnil;
5972   [super dealloc];
5976 - condemn
5978   NSTRACE (condemn);
5979   condemned =YES;
5980   return self;
5984 - reprieve
5986   NSTRACE (reprieve);
5987   condemned =NO;
5988   return self;
5992 - judge
5994   NSTRACE (judge);
5995   if (condemned)
5996     {
5997       EmacsView *view;
5998       BLOCK_INPUT;
5999       /* ensure other scrollbar updates after deletion */
6000       view = (EmacsView *)FRAME_NS_VIEW (frame);
6001       if (view != nil)
6002         view->scrollbarsNeedingUpdate++;
6003       [self removeFromSuperview];
6004       [self release];
6005       UNBLOCK_INPUT;
6006     }
6007   return self;
6011 - (void)resetCursorRects
6013   NSRect visible = [self visibleRect];
6014   NSTRACE (resetCursorRects);
6016   if (!NSIsEmptyRect (visible))
6017     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6018   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6022 - (int) checkSamePosition: (int) position portion: (int) portion
6023                     whole: (int) whole
6025   return em_position ==position && em_portion ==portion && em_whole ==whole
6026     && portion != whole; /* needed for resize empty buf */
6030 - setPosition: (int)position portion: (int)portion whole: (int)whole
6032   NSTRACE (setPosition);
6034   em_position = position;
6035   em_portion = portion;
6036   em_whole = whole;
6038   if (portion >= whole)
6039     [self setFloatValue: 0.0 knobProportion: 1.0];
6040   else
6041     {
6042       float pos, por;
6043       portion = max ((float)whole*min_portion/pixel_height, portion);
6044       pos = (float)position / (whole - portion);
6045       por = (float)portion/whole;
6046       [self setFloatValue: pos knobProportion: por];
6047     }
6048   return self;
6051 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6052      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6053 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6054                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6056   *part = last_hit_part;
6057   *window = win;
6058   XSETINT (*y, pixel_height);
6059   if ([self floatValue] > 0.999)
6060     XSETINT (*x, pixel_height);
6061   else
6062     XSETINT (*x, pixel_height * [self floatValue]);
6066 /* set up emacs_event */
6067 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6069   if (!emacs_event)
6070     return;
6072   emacs_event->part = last_hit_part;
6073   emacs_event->code = 0;
6074   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6075   emacs_event->frame_or_window = win;
6076   emacs_event->timestamp = EV_TIMESTAMP (e);
6077   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6078   emacs_event->arg = Qnil;
6079   XSETINT (emacs_event->x, loc * pixel_height);
6080   XSETINT (emacs_event->y, pixel_height-20);
6082   n_emacs_events_pending++;
6083   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6084   EVENT_INIT (*emacs_event);
6085   ns_send_appdefined (-1);
6089 /* called manually thru timer to implement repeated button action w/hold-down */
6090 - repeatScroll: (NSTimer *)scrollEntry
6092   NSEvent *e = [[self window] currentEvent];
6093   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6094   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6096   /* clear timer if need be */
6097   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6098     {
6099         [scroll_repeat_entry invalidate];
6100         [scroll_repeat_entry release];
6101         scroll_repeat_entry = nil;
6103         if (inKnob)
6104           return self;
6106         scroll_repeat_entry
6107           = [[NSTimer scheduledTimerWithTimeInterval:
6108                         SCROLL_BAR_CONTINUOUS_DELAY
6109                                             target: self
6110                                           selector: @selector (repeatScroll:)
6111                                           userInfo: 0
6112                                            repeats: YES]
6113               retain];
6114     }
6116   [self sendScrollEventAtLoc: 0 fromEvent: e];
6117   return self;
6121 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6122    mouseDragged events without going into a modal loop. */
6123 - (void)mouseDown: (NSEvent *)e
6125   NSRect sr, kr;
6126   /* hitPart is only updated AFTER event is passed on */
6127   NSScrollerPart part = [self testPart: [e locationInWindow]];
6128   double inc = 0.0, loc, kloc, pos;
6129   int edge = 0;
6131   NSTRACE (EmacsScroller_mouseDown);
6133   switch (part)
6134     {
6135     case NSScrollerDecrementPage:
6136         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6137     case NSScrollerIncrementPage:
6138         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6139     case NSScrollerDecrementLine:
6140       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6141     case NSScrollerIncrementLine:
6142       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6143     case NSScrollerKnob:
6144       last_hit_part = scroll_bar_handle; break;
6145     case NSScrollerKnobSlot:  /* GNUstep-only */
6146       last_hit_part = scroll_bar_move_ratio; break;
6147     default:  /* NSScrollerNoPart? */
6148       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6149                (long) part);
6150       return;
6151     }
6153   if (inc != 0.0)
6154     {
6155       pos = 0;      /* ignored */
6157       /* set a timer to repeat, as we can't let superclass do this modally */
6158       scroll_repeat_entry
6159         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6160                                             target: self
6161                                           selector: @selector (repeatScroll:)
6162                                           userInfo: 0
6163                                            repeats: YES]
6164             retain];
6165     }
6166   else
6167     {
6168       /* handle, or on GNUstep possibly slot */
6169       NSEvent *fake_event;
6171       /* compute float loc in slot and mouse offset on knob */
6172       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6173                       toView: nil];
6174       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6175       if (loc <= 0.0)
6176         {
6177           loc = 0.0;
6178           edge = -1;
6179         }
6180       else if (loc >= NSHeight (sr))
6181         {
6182           loc = NSHeight (sr);
6183           edge = 1;
6184         }
6186       if (edge)
6187         kloc = 0.5 * edge;
6188       else
6189         {
6190           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6191                           toView: nil];
6192           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6193         }
6194       last_mouse_offset = kloc;
6196       /* if knob, tell emacs a location offset by knob pos
6197          (to indicate top of handle) */
6198       if (part == NSScrollerKnob)
6199           pos = (loc - last_mouse_offset) / NSHeight (sr);
6200       else
6201         /* else this is a slot click on GNUstep: go straight there */
6202         pos = loc / NSHeight (sr);
6204       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6205       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6206                                       location: [e locationInWindow]
6207                                  modifierFlags: [e modifierFlags]
6208                                      timestamp: [e timestamp]
6209                                   windowNumber: [e windowNumber]
6210                                        context: [e context]
6211                                    eventNumber: [e eventNumber]
6212                                     clickCount: [e clickCount]
6213                                       pressure: [e pressure]];
6214       [super mouseUp: fake_event];
6215     }
6217   if (part != NSScrollerKnob)
6218     [self sendScrollEventAtLoc: pos fromEvent: e];
6222 /* Called as we manually track scroller drags, rather than superclass. */
6223 - (void)mouseDragged: (NSEvent *)e
6225     NSRect sr;
6226     double loc, pos;
6227     int edge = 0;
6229     NSTRACE (EmacsScroller_mouseDragged);
6231       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6232                       toView: nil];
6233       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6235       if (loc <= 0.0)
6236         {
6237           loc = 0.0;
6238           edge = -1;
6239         }
6240       else if (loc >= NSHeight (sr) + last_mouse_offset)
6241         {
6242           loc = NSHeight (sr) + last_mouse_offset;
6243           edge = 1;
6244         }
6246       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6247       [self sendScrollEventAtLoc: pos fromEvent: e];
6251 - (void)mouseUp: (NSEvent *)e
6253   if (scroll_repeat_entry)
6254     {
6255       [scroll_repeat_entry invalidate];
6256       [scroll_repeat_entry release];
6257       scroll_repeat_entry = nil;
6258     }
6259   last_hit_part = 0;
6263 /* treat scrollwheel events in the bar as though they were in the main window */
6264 - (void) scrollWheel: (NSEvent *)theEvent
6266   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6267   [view mouseDown: theEvent];
6270 @end  /* EmacsScroller */
6275 /* ==========================================================================
6277    Font-related functions; these used to be in nsfaces.m
6279    ========================================================================== */
6282 Lisp_Object
6283 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6285   struct font *font = XFONT_OBJECT (font_object);
6287   if (fontset < 0)
6288     fontset = fontset_from_font (font_object);
6289   FRAME_FONTSET (f) = fontset;
6291   if (FRAME_FONT (f) == font)
6292     /* This font is already set in frame F.  There's nothing more to
6293        do.  */
6294     return font_object;
6296   FRAME_FONT (f) = font;
6298   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6299   FRAME_COLUMN_WIDTH (f) = font->average_width;
6300   FRAME_SPACE_WIDTH (f) = font->space_width;
6301   FRAME_LINE_HEIGHT (f) = font->height;
6303   compute_fringe_widths (f, 1);
6305   /* Compute the scroll bar width in character columns.  */
6306   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6307     {
6308       int wid = FRAME_COLUMN_WIDTH (f);
6309       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6310         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6311     }
6312   else
6313     {
6314       int wid = FRAME_COLUMN_WIDTH (f);
6315       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6316     }
6318   /* Now make the frame display the given font.  */
6319   if (FRAME_NS_WINDOW (f) != 0)
6320         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6322   return font_object;
6326 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6327 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6328          in 1.43. */
6330 const char *
6331 ns_xlfd_to_fontname (const char *xlfd)
6332 /* --------------------------------------------------------------------------
6333     Convert an X font name (XLFD) to an NS font name.
6334     Only family is used.
6335     The string returned is temporarily allocated.
6336    -------------------------------------------------------------------------- */
6338   char *name = xmalloc (180);
6339   int i, len;
6340   const char *ret;
6342   if (!strncmp (xlfd, "--", 2))
6343     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6344   else
6345     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6347   /* stopgap for malformed XLFD input */
6348   if (strlen (name) == 0)
6349     strcpy (name, "Monaco");
6351   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6352      also uppercase after '-' or ' ' */
6353   name[0] = toupper (name[0]);
6354   for (len =strlen (name), i =0; i<len; i++)
6355     {
6356       if (name[i] == '$')
6357         {
6358           name[i] = '-';
6359           if (i+1<len)
6360             name[i+1] = toupper (name[i+1]);
6361         }
6362       else if (name[i] == '_')
6363         {
6364           name[i] = ' ';
6365           if (i+1<len)
6366             name[i+1] = toupper (name[i+1]);
6367         }
6368     }
6369 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6370   ret = [[NSString stringWithUTF8String: name] UTF8String];
6371   xfree (name);
6372   return ret;
6376 void
6377 syms_of_nsterm (void)
6379   NSTRACE (syms_of_nsterm);
6381   ns_antialias_threshold = 10.0;
6383   /* from 23+ we need to tell emacs what modifiers there are.. */
6384   DEFSYM (Qmodifier_value, "modifier-value");
6385   DEFSYM (Qalt, "alt");
6386   DEFSYM (Qhyper, "hyper");
6387   DEFSYM (Qmeta, "meta");
6388   DEFSYM (Qsuper, "super");
6389   DEFSYM (Qcontrol, "control");
6390   DEFSYM (Qnone, "none");
6391   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6392   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6393   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6394   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6395   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6397   DEFVAR_LISP ("ns-input-file", ns_input_file,
6398               "The file specified in the last NS event.");
6399   ns_input_file =Qnil;
6401   DEFVAR_LISP ("ns-input-text", ns_input_text,
6402               "The data received in the last NS text drag event.");
6403   ns_input_text =Qnil;
6405   DEFVAR_LISP ("ns-working-text", ns_working_text,
6406               "String for visualizing working composition sequence.");
6407   ns_working_text =Qnil;
6409   DEFVAR_LISP ("ns-input-font", ns_input_font,
6410               "The font specified in the last NS event.");
6411   ns_input_font =Qnil;
6413   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
6414               "The fontsize specified in the last NS event.");
6415   ns_input_fontsize =Qnil;
6417   DEFVAR_LISP ("ns-input-line", ns_input_line,
6418                "The line specified in the last NS event.");
6419   ns_input_line =Qnil;
6421   DEFVAR_LISP ("ns-input-color", ns_input_color,
6422                "The color specified in the last NS event.");
6423   ns_input_color =Qnil;
6425   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
6426                "The service name specified in the last NS event.");
6427   ns_input_spi_name =Qnil;
6429   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
6430                "The service argument specified in the last NS event.");
6431   ns_input_spi_arg =Qnil;
6433   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
6434                "This variable describes the behavior of the alternate or option key.\n\
6435 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6436 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6437 at all, allowing it to be used at a lower level for accented character entry.");
6438   ns_alternate_modifier = Qmeta;
6440   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
6441                "This variable describes the behavior of the right alternate or option key.\n\
6442 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6443 Set to left means be the same key as `ns-alternate-modifier'.\n\
6444 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6445 at all, allowing it to be used at a lower level for accented character entry.");
6446   ns_right_alternate_modifier = Qleft;
6448   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
6449                "This variable describes the behavior of the command key.\n\
6450 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6451   ns_command_modifier = Qsuper;
6453   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
6454                "This variable describes the behavior of the right command key.\n\
6455 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6456 Set to left means be the same key as `ns-command-modifier'.\n\
6457 Set to none means that the command / option key is not interpreted by Emacs\n\
6458 at all, allowing it to be used at a lower level for accented character entry.");
6459   ns_right_command_modifier = Qleft;
6461   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
6462                "This variable describes the behavior of the control key.\n\
6463 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6464   ns_control_modifier = Qcontrol;
6466   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
6467                "This variable describes the behavior of the right control key.\n\
6468 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6469 Set to left means be the same key as `ns-control-modifier'.\n\
6470 Set to none means that the control / option key is not interpreted by Emacs\n\
6471 at all, allowing it to be used at a lower level for accented character entry.");
6472   ns_right_control_modifier = Qleft;
6474   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
6475                "This variable describes the behavior of the function key (on laptops).\n\
6476 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6477 Set to none means that the function key is not interpreted by Emacs at all,\n\
6478 allowing it to be used at a lower level for accented character entry.");
6479   ns_function_modifier = Qnone;
6481   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
6482                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6483   ns_antialias_text = Qt;
6485   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
6486                "Whether to confirm application quit using dialog.");
6487   ns_confirm_quit = Qnil;
6489   staticpro (&ns_display_name_list);
6490   ns_display_name_list = Qnil;
6492   staticpro (&last_mouse_motion_frame);
6493   last_mouse_motion_frame = Qnil;
6495   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
6496                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
6497 Only works on OSX 10.6 or later.  */);
6498   ns_auto_hide_menu_bar = Qnil;
6500   /* TODO: move to common code */
6501   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
6502                doc: /* If not nil, Emacs uses toolkit scroll bars.  */);
6503 #ifdef USE_TOOLKIT_SCROLL_BARS
6504   Vx_toolkit_scroll_bars = Qt;
6505 #else
6506   Vx_toolkit_scroll_bars = Qnil;
6507 #endif
6509   /* these are unsupported but we need the declarations to avoid whining
6510      messages from cus-start.el */
6511   DEFVAR_BOOL ("x-use-underline-position-properties",
6512                x_use_underline_position_properties,
6513      doc: /* NOT SUPPORTED UNDER NS.
6514 *Non-nil means make use of UNDERLINE_POSITION font properties.
6515 A value of nil means ignore them.  If you encounter fonts with bogus
6516 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6517 to 4.1, set this to nil.
6519 NOTE: Not supported on Mac yet.  */);
6520   x_use_underline_position_properties = 0;
6522   DEFVAR_BOOL ("x-underline-at-descent-line",
6523                x_underline_at_descent_line,
6524      doc: /* NOT SUPPORTED UNDER NS.
6525 *Non-nil means to draw the underline at the same place as the descent line.
6526 A value of nil means to draw the underline according to the value of the
6527 variable `x-use-underline-position-properties', which is usually at the
6528 baseline level.  The default value is nil.  */);
6529   x_underline_at_descent_line = 0;
6531   /* Tell emacs about this window system. */
6532   Fprovide (intern ("ns"), Qnil);