* lisp/progmodes/ruby-mode.el: Improve percent literals.
[emacs.git] / src / nsterm.m
blob5e3c3ac777f8d1b15af3b85d9020391e75c750c6
1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2012
4   Free Software Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30    interpretation of even the system includes. */
31 #include <config.h>
33 #include <math.h>
34 #include <sys/types.h>
35 #include <time.h>
36 #include <signal.h>
37 #include <unistd.h>
38 #include <setjmp.h>
39 #include <c-strcase.h>
40 #include <ftoastr.h>
42 #include "lisp.h"
43 #include "blockinput.h"
44 #include "sysselect.h"
45 #include "nsterm.h"
46 #include "systime.h"
47 #include "character.h"
48 #include "fontset.h"
49 #include "composite.h"
50 #include "ccl.h"
52 #include "termhooks.h"
53 #include "termopts.h"
54 #include "termchar.h"
56 #include "window.h"
57 #include "keyboard.h"
58 #include "buffer.h"
59 #include "font.h"
61 /* call tracing */
62 #if 0
63 int term_trace_num = 0;
64 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
65                                 __FILE__, __LINE__, ++term_trace_num)
66 #else
67 #define NSTRACE(x)
68 #endif
70 extern NSString *NSMenuDidBeginTrackingNotification;
72 /* ==========================================================================
74     Local declarations
76    ========================================================================== */
78 /* Convert a symbol indexed with an NSxxx value to a value as defined
79    in keyboard.c (lispy_function_key). I hope this is a correct way
80    of doing things... */
81 static unsigned convert_ns_to_X_keysym[] =
83   NSHomeFunctionKey,            0x50,
84   NSLeftArrowFunctionKey,       0x51,
85   NSUpArrowFunctionKey,         0x52,
86   NSRightArrowFunctionKey,      0x53,
87   NSDownArrowFunctionKey,       0x54,
88   NSPageUpFunctionKey,          0x55,
89   NSPageDownFunctionKey,        0x56,
90   NSEndFunctionKey,             0x57,
91   NSBeginFunctionKey,           0x58,
92   NSSelectFunctionKey,          0x60,
93   NSPrintFunctionKey,           0x61,
94   NSExecuteFunctionKey,         0x62,
95   NSInsertFunctionKey,          0x63,
96   NSUndoFunctionKey,            0x65,
97   NSRedoFunctionKey,            0x66,
98   NSMenuFunctionKey,            0x67,
99   NSFindFunctionKey,            0x68,
100   NSHelpFunctionKey,            0x6A,
101   NSBreakFunctionKey,           0x6B,
103   NSF1FunctionKey,              0xBE,
104   NSF2FunctionKey,              0xBF,
105   NSF3FunctionKey,              0xC0,
106   NSF4FunctionKey,              0xC1,
107   NSF5FunctionKey,              0xC2,
108   NSF6FunctionKey,              0xC3,
109   NSF7FunctionKey,              0xC4,
110   NSF8FunctionKey,              0xC5,
111   NSF9FunctionKey,              0xC6,
112   NSF10FunctionKey,             0xC7,
113   NSF11FunctionKey,             0xC8,
114   NSF12FunctionKey,             0xC9,
115   NSF13FunctionKey,             0xCA,
116   NSF14FunctionKey,             0xCB,
117   NSF15FunctionKey,             0xCC,
118   NSF16FunctionKey,             0xCD,
119   NSF17FunctionKey,             0xCE,
120   NSF18FunctionKey,             0xCF,
121   NSF19FunctionKey,             0xD0,
122   NSF20FunctionKey,             0xD1,
123   NSF21FunctionKey,             0xD2,
124   NSF22FunctionKey,             0xD3,
125   NSF23FunctionKey,             0xD4,
126   NSF24FunctionKey,             0xD5,
128   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
129   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
130   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
132   NSTabCharacter,               0x09,
133   0x19,                         0x09,  /* left tab->regular since pass shift */
134   NSCarriageReturnCharacter,    0x0D,
135   NSNewlineCharacter,           0x0D,
136   NSEnterCharacter,             0x8D,
138   0x1B,                         0x1B   /* escape */
141 static Lisp_Object Qmodifier_value;
142 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
143 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
145 static Lisp_Object QUTF8_STRING;
147 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
148    the maximum font size to NOT antialias.  On GNUstep there is currently
149    no way to control this behavior. */
150 float ns_antialias_threshold;
152 /* Used to pick up AppleHighlightColor on OS X */
153 NSString *ns_selection_color;
155 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
156 NSString *ns_app_name = @"Emacs";  /* default changed later */
158 /* Display variables */
159 struct ns_display_info *x_display_list; /* Chain of existing displays */
160 Lisp_Object ns_display_name_list;
161 long context_menu_value = 0;
163 /* display update */
164 NSPoint last_mouse_motion_position;
165 static NSRect last_mouse_glyph;
166 static Time last_mouse_movement_time = 0;
167 static Lisp_Object last_mouse_motion_frame;
168 static EmacsScroller *last_mouse_scroll_bar = nil;
169 static struct frame *ns_updating_frame;
170 static NSView *focus_view = NULL;
171 static int ns_window_num = 0;
172 #ifdef NS_IMPL_GNUSTEP
173 static NSRect uRect;
174 #endif
175 static BOOL gsaved = NO;
176 BOOL ns_in_resize = NO;
177 static BOOL ns_fake_keydown = NO;
178 int ns_tmp_flags; /* FIXME */
179 struct nsfont_info *ns_tmp_font; /* FIXME */
180 static BOOL ns_menu_bar_is_hidden = NO;
181 /*static int debug_lock = 0; */
183 /* event loop */
184 static BOOL send_appdefined = YES;
185 static NSEvent *last_appdefined_event = 0;
186 static NSTimer *timed_entry = 0;
187 static NSTimer *fd_entry = nil;
188 static NSTimer *scroll_repeat_entry = nil;
189 static fd_set select_readfds, t_readfds;
190 static int select_nfds;
191 static NSAutoreleasePool *outerpool;
192 static struct input_event *emacs_event = NULL;
193 static struct input_event *q_event_ptr = NULL;
194 static int n_emacs_events_pending = 0;
195 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
196   *ns_pending_service_args;
197 static BOOL inNsSelect = 0;
198 static BOOL ns_do_open_file = NO;
200 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
201 #define NS_FUNCTION_KEY_MASK 0x800000
202 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
203 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
204 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
205 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
206 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
207 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
208 #define EV_MODIFIERS(e)                               \
209     ((([e modifierFlags] & NSHelpKeyMask) ?           \
210            hyper_modifier : 0)                        \
211      | (!EQ (ns_right_alternate_modifier, Qleft) && \
212         (([e modifierFlags] & NSRightAlternateKeyMask) \
213          == NSRightAlternateKeyMask) ? \
214            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
215      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
216            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
217      | (([e modifierFlags] & NSShiftKeyMask) ?     \
218            shift_modifier : 0)                        \
219      | (!EQ (ns_right_control_modifier, Qleft) && \
220         (([e modifierFlags] & NSRightControlKeyMask) \
221          == NSRightControlKeyMask) ? \
222            parse_solitary_modifier (ns_right_control_modifier) : 0) \
223      | (([e modifierFlags] & NSControlKeyMask) ?      \
224            parse_solitary_modifier (ns_control_modifier) : 0)     \
225      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
226            parse_solitary_modifier (ns_function_modifier) : 0)    \
227      | (!EQ (ns_right_command_modifier, Qleft) && \
228         (([e modifierFlags] & NSRightCommandKeyMask) \
229          == NSRightCommandKeyMask) ? \
230            parse_solitary_modifier (ns_right_command_modifier) : 0) \
231      | (([e modifierFlags] & NSCommandKeyMask) ?      \
232            parse_solitary_modifier (ns_command_modifier):0))
234 #define EV_UDMODIFIERS(e)                                      \
235     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
236      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
237      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
238      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
239      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
240      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
241      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
242      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
243      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
245 #define EV_BUTTON(e)                                                         \
246     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
247       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
248      [e buttonNumber] - 1)
250 /* Convert the time field to a timestamp in milliseconds. */
251 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
253 /* This is a piece of code which is common to all the event handling
254    methods.  Maybe it should even be a function.  */
255 #define EV_TRAILER(e)                                         \
256   {                                                           \
257   XSETFRAME (emacs_event->frame_or_window, emacsframe);       \
258   if (e) emacs_event->timestamp = EV_TIMESTAMP (e);           \
259   n_emacs_events_pending++;                                   \
260   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);     \
261   EVENT_INIT (*emacs_event);                                  \
262   ns_send_appdefined (-1);                                    \
263   }
265 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
267 /* TODO: get rid of need for these forward declarations */
268 static void ns_condemn_scroll_bars (struct frame *f);
269 static void ns_judge_scroll_bars (struct frame *f);
270 void x_set_frame_alpha (struct frame *f);
273 /* ==========================================================================
275     Utilities
277    ========================================================================== */
280 static Lisp_Object
281 append2 (Lisp_Object list, Lisp_Object item)
282 /* --------------------------------------------------------------------------
283    Utility to append to a list
284    -------------------------------------------------------------------------- */
286   Lisp_Object array[2];
287   array[0] = list;
288   array[1] = Fcons (item, Qnil);
289   return Fnconc (2, &array[0]);
293 const char *
294 ns_etc_directory (void)
295 /* If running as a self-contained app bundle, return as a string the
296    filename of the etc directory, if present; else nil.  */
298   NSBundle *bundle = [NSBundle mainBundle];
299   NSString *resourceDir = [bundle resourcePath];
300   NSString *resourcePath;
301   NSFileManager *fileManager = [NSFileManager defaultManager];
302   BOOL isDir;
304   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
305   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
306     {
307       if (isDir) return [resourcePath UTF8String];
308     }
309   return NULL;
313 const char *
314 ns_exec_path (void)
315 /* If running as a self-contained app bundle, return as a path string
316    the filenames of the libexec and bin directories, ie libexec:bin.
317    Otherwise, return nil.
318    Normally, Emacs does not add its own bin/ directory to the PATH.
319    However, a self-contained NS build has a different layout, with
320    bin/ and libexec/ subdirectories in the directory that contains
321    Emacs.app itself.
322    We put libexec first, because init_callproc_1 uses the first
323    element to initialize exec-directory.  An alternative would be
324    for init_callproc to check for invocation-directory/libexec.
327   NSBundle *bundle = [NSBundle mainBundle];
328   NSString *resourceDir = [bundle resourcePath];
329   NSString *binDir = [bundle bundlePath];
330   NSString *resourcePath, *resourcePaths;
331   NSRange range;
332   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
333   NSFileManager *fileManager = [NSFileManager defaultManager];
334   NSArray *paths;
335   NSEnumerator *pathEnum;
336   BOOL isDir;
338   range = [resourceDir rangeOfString: @"Contents"];
339   if (range.location != NSNotFound)
340     {
341       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
342 #ifdef NS_IMPL_COCOA
343       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
344 #endif
345     }
347   paths = [binDir stringsByAppendingPaths:
348                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
349   pathEnum = [paths objectEnumerator];
350   resourcePaths = @"";
352   while ((resourcePath = [pathEnum nextObject]))
353     {
354       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
355         if (isDir)
356           {
357             if ([resourcePaths length] > 0)
358               resourcePaths
359                 = [resourcePaths stringByAppendingString: pathSeparator];
360             resourcePaths
361               = [resourcePaths stringByAppendingString: resourcePath];
362           }
363     }
364   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
366   return NULL;
370 const char *
371 ns_load_path (void)
372 /* If running as a self-contained app bundle, return as a path string
373    the filenames of the site-lisp, lisp and leim directories.
374    Ie, site-lisp:lisp:leim.  Otherwise, return nil.  */
376   NSBundle *bundle = [NSBundle mainBundle];
377   NSString *resourceDir = [bundle resourcePath];
378   NSString *resourcePath, *resourcePaths;
379   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
380   NSFileManager *fileManager = [NSFileManager defaultManager];
381   BOOL isDir;
382   NSArray *paths = [resourceDir stringsByAppendingPaths:
383                               [NSArray arrayWithObjects:
384                                          @"site-lisp", @"lisp", @"leim", nil]];
385   NSEnumerator *pathEnum = [paths objectEnumerator];
386   resourcePaths = @"";
388   /* Hack to skip site-lisp.  */
389   if (no_site_lisp) resourcePath = [pathEnum nextObject];
391   while ((resourcePath = [pathEnum nextObject]))
392     {
393       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
394         if (isDir)
395           {
396             if ([resourcePaths length] > 0)
397               resourcePaths
398                 = [resourcePaths stringByAppendingString: pathSeparator];
399             resourcePaths
400               = [resourcePaths stringByAppendingString: resourcePath];
401           }
402     }
403   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
405   return NULL;
408 static void
409 ns_timeout (int usecs)
410 /* --------------------------------------------------------------------------
411      Blocking timer utility used by ns_ring_bell
412    -------------------------------------------------------------------------- */
414   EMACS_TIME wakeup = add_emacs_time (current_emacs_time (),
415                                       make_emacs_time (0, usecs * 1000));
417   /* Keep waiting until past the time wakeup.  */
418   while (1)
419     {
420       EMACS_TIME timeout, now = current_emacs_time ();
421       if (EMACS_TIME_LE (wakeup, now))
422         break;
423       timeout = sub_emacs_time (wakeup, now);
425       /* Try to wait that long--but we might wake up sooner.  */
426       pselect (0, NULL, NULL, NULL, &timeout, NULL);
427     }
431 void
432 ns_release_object (void *obj)
433 /* --------------------------------------------------------------------------
434     Release an object (callable from C)
435    -------------------------------------------------------------------------- */
437     [(id)obj release];
441 void
442 ns_retain_object (void *obj)
443 /* --------------------------------------------------------------------------
444     Retain an object (callable from C)
445    -------------------------------------------------------------------------- */
447     [(id)obj retain];
451 void *
452 ns_alloc_autorelease_pool (void)
453 /* --------------------------------------------------------------------------
454      Allocate a pool for temporary objects (callable from C)
455    -------------------------------------------------------------------------- */
457   return [[NSAutoreleasePool alloc] init];
461 void
462 ns_release_autorelease_pool (void *pool)
463 /* --------------------------------------------------------------------------
464      Free a pool and temporary objects it refers to (callable from C)
465    -------------------------------------------------------------------------- */
467   ns_release_object (pool);
472 /* ==========================================================================
474     Focus (clipping) and screen update
476    ========================================================================== */
478 static NSRect
479 ns_resize_handle_rect (NSWindow *window)
481   NSRect r = [window frame];
482   r.origin.x = r.size.width - RESIZE_HANDLE_SIZE;
483   r.origin.y = 0;
484   r.size.width = r.size.height = RESIZE_HANDLE_SIZE;
485   return r;
490 // Window constraining
491 // -------------------
493 // To ensure that the windows are not placed under the menu bar, they
494 // are typically moved by the call-back constrainFrameRect. However,
495 // by overriding it, it's possible to inhibit this, leaving the window
496 // in it's original position.
498 // It's possible to hide the menu bar. However, technically, it's only
499 // possible to hide it when the application is active. To ensure that
500 // this work properly, the menu bar and window constraining are
501 // deferred until the application becomes active.
503 // Even though it's not possible to manually move a window above the
504 // top of the screen, it is allowed if it's done programmatically,
505 // when the menu is hidden. This allows the editable area to cover the
506 // full screen height.
508 // Test cases
509 // ----------
511 // Use the following extra files:
513 //    init.el:
514 //       ;; Hide menu and place frame slightly above the top of the screen.
515 //       (setq ns-auto-hide-menu-bar t)
516 //       (set-frame-position (selected-frame) 0 -20)
518 // Test 1:
520 //    emacs -Q -l init.el
522 //    Result: No menu bar, and the title bar should be above the screen.
524 // Test 2:
526 //    emacs -Q
528 //    Result: Menu bar visible, frame placed immediately below the menu.
531 static void
532 ns_constrain_all_frames (void)
534   Lisp_Object tail, frame;
536   FOR_EACH_FRAME (tail, frame)
537     {
538       struct frame *f = XFRAME (frame);
539       if (FRAME_NS_P (f))
540         {
541           NSView *view = FRAME_NS_VIEW (f);
542           /* This no-op will trigger the default window placing
543            * constraint system. */
544           f->output_data.ns->dont_constrain = 0;
545           [[view window] setFrameOrigin:[[view window] frame].origin];
546         }
547     }
551 /* True, if the menu bar should be hidden.  */
553 static BOOL
554 ns_menu_bar_should_be_hidden (void)
556   return !NILP (ns_auto_hide_menu_bar)
557     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
561 /* Show or hide the menu bar, based on user setting.  */
563 static void
564 ns_update_auto_hide_menu_bar (void)
566 #ifndef MAC_OS_X_VERSION_10_6
567 #define MAC_OS_X_VERSION_10_6 1060
568 #endif
569 #ifdef NS_IMPL_COCOA
570 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
571   BLOCK_INPUT;
573   NSTRACE (ns_update_auto_hide_menu_bar);
575   if (NSApp != nil
576       && [NSApp isActive]
577       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
578     {
579       // Note, "setPresentationOptions" triggers an error unless the
580       // application is active.
581       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
583       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
584         {
585           NSApplicationPresentationOptions options
586             = NSApplicationPresentationAutoHideDock;
588           if (menu_bar_should_be_hidden)
589             options |= NSApplicationPresentationAutoHideMenuBar;
591           [NSApp setPresentationOptions: options];
593           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
595           if (!ns_menu_bar_is_hidden)
596             {
597               ns_constrain_all_frames ();
598             }
599         }
600     }
602   UNBLOCK_INPUT;
603 #endif
604 #endif
608 static void
609 ns_update_begin (struct frame *f)
610 /* --------------------------------------------------------------------------
611    Prepare for a grouped sequence of drawing calls
612    external (RIF) call; whole frame, called before update_window_begin
613    -------------------------------------------------------------------------- */
615   NSView *view = FRAME_NS_VIEW (f);
616   NSTRACE (ns_update_begin);
618   ns_update_auto_hide_menu_bar ();
620   ns_updating_frame = f;
621   [view lockFocus];
623 #ifdef NS_IMPL_GNUSTEP
624   uRect = NSMakeRect (0, 0, 0, 0);
625 #endif
629 static void
630 ns_update_window_begin (struct window *w)
631 /* --------------------------------------------------------------------------
632    Prepare for a grouped sequence of drawing calls
633    external (RIF) call; for one window, called after update_begin
634    -------------------------------------------------------------------------- */
636   struct frame *f = XFRAME (WINDOW_FRAME (w));
637  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
638   NSTRACE (ns_update_window_begin);
640   updated_window = w;
641   set_output_cursor (&w->cursor);
643   BLOCK_INPUT;
645   if (f == hlinfo->mouse_face_mouse_frame)
646     {
647       /* Don't do highlighting for mouse motion during the update.  */
648       hlinfo->mouse_face_defer = 1;
650         /* If the frame needs to be redrawn,
651            simply forget about any prior mouse highlighting.  */
652       if (FRAME_GARBAGED_P (f))
653         hlinfo->mouse_face_window = Qnil;
655       /* (further code for mouse faces ifdef'd out in other terms elided) */
656     }
658   UNBLOCK_INPUT;
662 static void
663 ns_update_window_end (struct window *w, int cursor_on_p,
664                       int mouse_face_overwritten_p)
665 /* --------------------------------------------------------------------------
666    Finished a grouped sequence of drawing calls
667    external (RIF) call; for one window called before update_end
668    -------------------------------------------------------------------------- */
670   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
672   /* note: this fn is nearly identical in all terms */
673   if (!w->pseudo_window_p)
674     {
675       BLOCK_INPUT;
677       if (cursor_on_p)
678         display_and_set_cursor (w, 1,
679                                 output_cursor.hpos, output_cursor.vpos,
680                                 output_cursor.x, output_cursor.y);
682       if (draw_window_fringes (w, 1))
683         x_draw_vertical_border (w);
685       UNBLOCK_INPUT;
686     }
688   /* If a row with mouse-face was overwritten, arrange for
689      frame_up_to_date to redisplay the mouse highlight.  */
690   if (mouse_face_overwritten_p)
691     {
692       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
693       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
694       hlinfo->mouse_face_window = Qnil;
695     }
697   updated_window = NULL;
698   NSTRACE (update_window_end);
702 static void
703 ns_update_end (struct frame *f)
704 /* --------------------------------------------------------------------------
705    Finished a grouped sequence of drawing calls
706    external (RIF) call; for whole frame, called after update_window_end
707    -------------------------------------------------------------------------- */
709   NSView *view = FRAME_NS_VIEW (f);
711 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
712     MOUSE_HL_INFO (f)->mouse_face_defer = 0;
714   BLOCK_INPUT;
716 #ifdef NS_IMPL_GNUSTEP
717   /* trigger flush only in the rectangle we tracked as being drawn */
718   [view unlockFocusNeedsFlush: NO];
719 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
720   [view lockFocusInRect: uRect];
721 #endif
723   [view unlockFocus];
724   [[view window] flushWindow];
726   UNBLOCK_INPUT;
727   ns_updating_frame = NULL;
728   NSTRACE (ns_update_end);
732 static void
733 ns_flush (struct frame *f)
734 /* --------------------------------------------------------------------------
735    external (RIF) call
736    NS impl is no-op since currently we flush in ns_update_end and elsewhere
737    -------------------------------------------------------------------------- */
739     NSTRACE (ns_flush);
743 static void
744 ns_focus (struct frame *f, NSRect *r, int n)
745 /* --------------------------------------------------------------------------
746    Internal: Focus on given frame.  During small local updates this is used to
747      draw, however during large updates, ns_update_begin and ns_update_end are
748      called to wrap the whole thing, in which case these calls are stubbed out.
749      Except, on GNUstep, we accumulate the rectangle being drawn into, because
750      the back end won't do this automatically, and will just end up flushing
751      the entire window.
752    -------------------------------------------------------------------------- */
754 //  NSTRACE (ns_focus);
755 #ifdef NS_IMPL_GNUSTEP
756   NSRect u;
757     if (n == 2)
758       u = NSUnionRect (r[0], r[1]);
759     else if (r)
760       u = *r;
761 #endif
762 /* static int c =0;
763    fprintf (stderr, "focus: %d", c++);
764    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
765    fprintf (stderr, "\n"); */
767   if (f != ns_updating_frame)
768     {
769       NSView *view = FRAME_NS_VIEW (f);
770       if (view != focus_view)
771         {
772           if (focus_view != NULL)
773             {
774               [focus_view unlockFocus];
775               [[focus_view window] flushWindow];
776 /*debug_lock--; */
777             }
779           if (view)
780 #ifdef NS_IMPL_GNUSTEP
781             r ? [view lockFocusInRect: u] : [view lockFocus];
782 #else
783             [view lockFocus];
784 #endif
785           focus_view = view;
786 /*if (view) debug_lock++; */
787         }
788 #ifdef NS_IMPL_GNUSTEP
789       else
790         {
791           /* more than one rect being drawn into */
792           if (view && r)
793             {
794               [view unlockFocus]; /* add prev rect to redraw list */
795               [view lockFocusInRect: u]; /* focus for draw in new rect */
796             }
797         }
798 #endif
799     }
800 #ifdef NS_IMPL_GNUSTEP
801   else
802     {
803       /* in batch mode, but in GNUstep must still track rectangles explicitly */
804       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
805     }
806 #endif
808   /* clipping */
809   if (r)
810     {
811       [[NSGraphicsContext currentContext] saveGraphicsState];
812       if (n == 2)
813         NSRectClipList (r, 2);
814       else
815         NSRectClip (*r);
816       gsaved = YES;
817     }
821 static void
822 ns_unfocus (struct frame *f)
823 /* --------------------------------------------------------------------------
824      Internal: Remove focus on given frame
825    -------------------------------------------------------------------------- */
827 //  NSTRACE (ns_unfocus);
829   if (gsaved)
830     {
831       [[NSGraphicsContext currentContext] restoreGraphicsState];
832       gsaved = NO;
833     }
835   if (f != ns_updating_frame)
836     {
837       if (focus_view != NULL)
838         {
839           [focus_view unlockFocus];
840           [[focus_view window] flushWindow];
841           focus_view = NULL;
842 /*debug_lock--; */
843         }
844     }
848 static void
849 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
850 /* --------------------------------------------------------------------------
851      Internal (but parallels other terms): Focus drawing on given row
852    -------------------------------------------------------------------------- */
854   struct frame *f = XFRAME (WINDOW_FRAME (w));
855   NSRect clip_rect;
856   int window_x, window_y, window_width;
858   window_box (w, area, &window_x, &window_y, &window_width, 0);
860   clip_rect.origin.x = window_x - FRAME_INTERNAL_BORDER_WIDTH (f);
861   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
862   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
863   clip_rect.size.width = window_width + 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
864   clip_rect.size.height = row->visible_height;
866   /* allow a full-height row at the top when requested
867      (used to draw fringe all the way through internal border area) */
868   if (gc && clip_rect.origin.y < 5)
869     {
870       clip_rect.origin.y -= FRAME_INTERNAL_BORDER_WIDTH (f);
871       clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
872     }
874   /* likewise at bottom */
875   if (gc &&
876       FRAME_PIXEL_HEIGHT (f) - (clip_rect.origin.y + clip_rect.size.height) < 5)
877     clip_rect.size.height += FRAME_INTERNAL_BORDER_WIDTH (f);
879   ns_focus (f, &clip_rect, 1);
883 static void
884 ns_ring_bell (struct frame *f)
885 /* --------------------------------------------------------------------------
886      "Beep" routine
887    -------------------------------------------------------------------------- */
889   NSTRACE (ns_ring_bell);
890   if (visible_bell)
891     {
892       NSAutoreleasePool *pool;
893       struct frame *frame = SELECTED_FRAME ();
894       NSView *view;
896       BLOCK_INPUT;
897       pool = [[NSAutoreleasePool alloc] init];
899       view = FRAME_NS_VIEW (frame);
900       if (view != nil)
901         {
902           NSRect r, surr;
903           NSPoint dim = NSMakePoint (128, 128);
905           r = [view bounds];
906           r.origin.x += (r.size.width - dim.x) / 2;
907           r.origin.y += (r.size.height - dim.y) / 2;
908           r.size.width = dim.x;
909           r.size.height = dim.y;
910           surr = NSInsetRect (r, -2, -2);
911           ns_focus (frame, &surr, 1);
912           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
913           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
914                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
915           NSRectFill (r);
916           [[view window] flushWindow];
917           ns_timeout (150000);
918           [[view window] restoreCachedImage];
919           [[view window] flushWindow];
920           ns_unfocus (frame);
921         }
922       [pool release];
923       UNBLOCK_INPUT;
924     }
925   else
926     {
927       NSBeep ();
928     }
932 static void
933 ns_reset_terminal_modes (struct terminal *terminal)
934 /*  Externally called as hook */
936   NSTRACE (ns_reset_terminal_modes);
940 static void
941 ns_set_terminal_modes (struct terminal *terminal)
942 /*  Externally called as hook */
944   NSTRACE (ns_set_terminal_modes);
949 /* ==========================================================================
951     Frame / window manager related functions
953    ========================================================================== */
956 static void
957 ns_raise_frame (struct frame *f)
958 /* --------------------------------------------------------------------------
959      Bring window to foreground and make it active
960    -------------------------------------------------------------------------- */
962   NSView *view = FRAME_NS_VIEW (f);
963   check_ns ();
964   BLOCK_INPUT;
965   FRAME_SAMPLE_VISIBILITY (f);
966   if (FRAME_VISIBLE_P (f))
967     {
968       [[view window] makeKeyAndOrderFront: NSApp];
969     }
970   UNBLOCK_INPUT;
974 static void
975 ns_lower_frame (struct frame *f)
976 /* --------------------------------------------------------------------------
977      Send window to back
978    -------------------------------------------------------------------------- */
980   NSView *view = FRAME_NS_VIEW (f);
981   check_ns ();
982   BLOCK_INPUT;
983   [[view window] orderBack: NSApp];
984   UNBLOCK_INPUT;
988 static void
989 ns_frame_raise_lower (struct frame *f, int raise)
990 /* --------------------------------------------------------------------------
991      External (hook)
992    -------------------------------------------------------------------------- */
994   NSTRACE (ns_frame_raise_lower);
996   if (raise)
997     ns_raise_frame (f);
998   else
999     ns_lower_frame (f);
1003 static void
1004 ns_frame_rehighlight (struct frame *frame)
1005 /* --------------------------------------------------------------------------
1006      External (hook): called on things like window switching within frame
1007    -------------------------------------------------------------------------- */
1009   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1010   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1012   NSTRACE (ns_frame_rehighlight);
1013   if (dpyinfo->x_focus_frame)
1014     {
1015       dpyinfo->x_highlight_frame
1016         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1017            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1018            : dpyinfo->x_focus_frame);
1019       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1020         {
1021           FSET (dpyinfo->x_focus_frame, focus_frame, Qnil);
1022           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1023         }
1024     }
1025   else
1026       dpyinfo->x_highlight_frame = 0;
1028   if (dpyinfo->x_highlight_frame &&
1029          dpyinfo->x_highlight_frame != old_highlight)
1030     {
1031       if (old_highlight)
1032         {
1033           x_update_cursor (old_highlight, 1);
1034           x_set_frame_alpha (old_highlight);
1035         }
1036       if (dpyinfo->x_highlight_frame)
1037         {
1038           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1039           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1040         }
1041     }
1045 void
1046 x_make_frame_visible (struct frame *f)
1047 /* --------------------------------------------------------------------------
1048      External: Show the window (X11 semantics)
1049    -------------------------------------------------------------------------- */
1051   NSTRACE (x_make_frame_visible);
1052   /* XXX: at some points in past this was not needed, as the only place that
1053      called this (frame.c:Fraise_frame ()) also called raise_lower;
1054      if this ends up the case again, comment this out again. */
1055   if (!FRAME_VISIBLE_P (f))
1056     {
1057       f->async_visible = 1;
1058       ns_raise_frame (f);
1059     }
1063 void
1064 x_make_frame_invisible (struct frame *f)
1065 /* --------------------------------------------------------------------------
1066      External: Hide the window (X11 semantics)
1067    -------------------------------------------------------------------------- */
1069   NSView * view = FRAME_NS_VIEW (f);
1070   NSTRACE (x_make_frame_invisible);
1071   check_ns ();
1072   [[view window] orderOut: NSApp];
1073   f->async_visible = 0;
1074   f->async_iconified = 0;
1078 void
1079 x_iconify_frame (struct frame *f)
1080 /* --------------------------------------------------------------------------
1081      External: Iconify window
1082    -------------------------------------------------------------------------- */
1084   NSView * view = FRAME_NS_VIEW (f);
1085   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1086   NSTRACE (x_iconify_frame);
1087   check_ns ();
1089   if (dpyinfo->x_highlight_frame == f)
1090     dpyinfo->x_highlight_frame = 0;
1092   if ([[view window] windowNumber] <= 0)
1093     {
1094       /* the window is still deferred.  Make it very small, bring it
1095          on screen and order it out. */
1096       NSRect s = { { 100, 100}, {0, 0} };
1097       NSRect t;
1098       t = [[view window] frame];
1099       [[view window] setFrame: s display: NO];
1100       [[view window] orderBack: NSApp];
1101       [[view window] orderOut: NSApp];
1102       [[view window] setFrame: t display: NO];
1103     }
1104   [[view window] miniaturize: NSApp];
1107 /* Free X resources of frame F.  */
1109 void
1110 x_free_frame_resources (struct frame *f)
1112   NSView *view = FRAME_NS_VIEW (f);
1113   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1114   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1115   NSTRACE (x_free_frame_resources);
1116   check_ns ();
1118   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1120   BLOCK_INPUT;
1122   free_frame_menubar (f);
1124   if (FRAME_FACE_CACHE (f))
1125     free_frame_faces (f);
1127   if (f == dpyinfo->x_focus_frame)
1128     dpyinfo->x_focus_frame = 0;
1129   if (f == dpyinfo->x_highlight_frame)
1130     dpyinfo->x_highlight_frame = 0;
1131   if (f == hlinfo->mouse_face_mouse_frame)
1132     {
1133       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1134       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1135       hlinfo->mouse_face_window = Qnil;
1136       hlinfo->mouse_face_deferred_gc = 0;
1137       hlinfo->mouse_face_mouse_frame = 0;
1138     }
1140   if (f->output_data.ns->miniimage != nil)
1141     [f->output_data.ns->miniimage release];
1143   [[view window] close];
1144   [view release];
1146   xfree (f->output_data.ns);
1148   UNBLOCK_INPUT;
1151 void
1152 x_destroy_window (struct frame *f)
1153 /* --------------------------------------------------------------------------
1154      External: Delete the window
1155    -------------------------------------------------------------------------- */
1157   NSTRACE (x_destroy_window);
1158   check_ns ();
1159   x_free_frame_resources (f);
1160   ns_window_num--;
1164 void
1165 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1166 /* --------------------------------------------------------------------------
1167      External: Position the window
1168    -------------------------------------------------------------------------- */
1170   NSView *view = FRAME_NS_VIEW (f);
1171   NSArray *screens = [NSScreen screens];
1172   NSScreen *fscreen = [screens objectAtIndex: 0];
1173   NSScreen *screen = [[view window] screen];
1175   NSTRACE (x_set_offset);
1177   BLOCK_INPUT;
1179   f->left_pos = xoff;
1180   f->top_pos = yoff;
1182   if (view != nil && screen && fscreen)
1183     {
1184       f->left_pos = f->size_hint_flags & XNegative
1185         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1186         : f->left_pos;
1187       /* We use visibleFrame here to take menu bar into account.
1188          Ideally we should also adjust left/top with visibleFrame.origin.  */
1190       f->top_pos = f->size_hint_flags & YNegative
1191         ? ([screen visibleFrame].size.height + f->top_pos
1192            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1193            - FRAME_TOOLBAR_HEIGHT (f))
1194         : f->top_pos;
1195 #ifdef NS_IMPL_GNUSTEP
1196       if (f->left_pos < 100)
1197         f->left_pos = 100;  /* don't overlap menu */
1198 #endif
1199       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1200          menu bar.  */
1201       f->output_data.ns->dont_constrain = 0;
1202       [[view window] setFrameTopLeftPoint:
1203                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1204                                     SCREENMAXBOUND ([fscreen frame].size.height
1205                                                     - NS_TOP_POS (f)))];
1206       f->size_hint_flags &= ~(XNegative|YNegative);
1207     }
1209   UNBLOCK_INPUT;
1213 void
1214 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1215 /* --------------------------------------------------------------------------
1216      Adjust window pixel size based on given character grid size
1217      Impl is a bit more complex than other terms, need to do some
1218      internal clipping.
1219    -------------------------------------------------------------------------- */
1221   EmacsView *view = FRAME_NS_VIEW (f);
1222   NSWindow *window = [view window];
1223   NSRect wr = [window frame];
1224   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1225   int pixelwidth, pixelheight;
1226   static int oldRows, oldCols, oldFontWidth, oldFontHeight;
1227   static int oldTB;
1228   static struct frame *oldF;
1230   NSTRACE (x_set_window_size);
1232   if (view == nil ||
1233       (f == oldF
1234        && rows == oldRows && cols == oldCols
1235        && oldFontWidth == FRAME_COLUMN_WIDTH (f)
1236        && oldFontHeight == FRAME_LINE_HEIGHT (f)
1237        && oldTB == tb))
1238     return;
1240 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1242   BLOCK_INPUT;
1244   check_frame_size (f, &rows, &cols);
1245   oldF = f;
1246   oldRows = rows;
1247   oldCols = cols;
1248   oldFontWidth = FRAME_COLUMN_WIDTH (f);
1249   oldFontHeight = FRAME_LINE_HEIGHT (f);
1250   oldTB = tb;
1252   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1253   compute_fringe_widths (f, 0);
1255   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1256   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1258   /* If we have a toolbar, take its height into account. */
1259   if (tb)
1260     /* NOTE: previously this would generate wrong result if toolbar not
1261              yet displayed and fixing toolbar_height=32 helped, but
1262              now (200903) seems no longer needed */
1263     FRAME_TOOLBAR_HEIGHT (f) =
1264       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1265         - FRAME_NS_TITLEBAR_HEIGHT (f);
1266   else
1267     FRAME_TOOLBAR_HEIGHT (f) = 0;
1269   wr.size.width = pixelwidth + f->border_width;
1270   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f)
1271                   + FRAME_TOOLBAR_HEIGHT (f);
1273   /* Do not try to constrain to this screen.  We may have multiple
1274      screens, and want Emacs to span those.  Constraining to screen
1275      prevents that, and that is not nice to the user.  */
1276  if (f->output_data.ns->zooming)
1277    f->output_data.ns->zooming = 0;
1278  else
1279    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1281   [view setRows: rows andColumns: cols];
1282   [window setFrame: wr display: YES];
1284 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1286   /* This is a trick to compensate for Emacs' managing the scrollbar area
1287      as a fixed number of standard character columns.  Instead of leaving
1288      blank space for the extra, we chopped it off above.  Now for
1289      left-hand scrollbars, we shift all rendering to the left by the
1290      difference between the real width and Emacs' imagined one.  For
1291      right-hand bars, don't worry about it since the extra is never used.
1292      (Obviously doesn't work for vertically split windows tho..) */
1293   {
1294     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1295       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1296                      - NS_SCROLL_BAR_WIDTH (f), 0)
1297       : NSMakePoint (0, 0);
1298     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1299     [view setBoundsOrigin: origin];
1300   }
1302   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1303   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1304   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1305 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1307   mark_window_cursors_off (XWINDOW (f->root_window));
1308   cancel_mouse_face (f);
1310   UNBLOCK_INPUT;
1315 /* ==========================================================================
1317     Color management
1319    ========================================================================== */
1322 NSColor *
1323 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1325   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1326   if (idx < 1 || idx >= color_table->avail)
1327     return nil;
1328   return color_table->colors[idx];
1332 unsigned long
1333 ns_index_color (NSColor *color, struct frame *f)
1335   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1336   ptrdiff_t idx;
1337   ptrdiff_t i;
1339   if (!color_table->colors)
1340     {
1341       color_table->size = NS_COLOR_CAPACITY;
1342       color_table->avail = 1; /* skip idx=0 as marker */
1343       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1344       color_table->colors[0] = nil;
1345       color_table->empty_indices = [[NSMutableSet alloc] init];
1346     }
1348   /* do we already have this color ? */
1349   for (i = 1; i < color_table->avail; i++)
1350     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1351       return i;
1353   if ([color_table->empty_indices count] > 0)
1354     {
1355       NSNumber *index = [color_table->empty_indices anyObject];
1356       [color_table->empty_indices removeObject: index];
1357       idx = [index unsignedLongValue];
1358     }
1359   else
1360     {
1361       if (color_table->avail == color_table->size)
1362         color_table->colors =
1363           xpalloc (color_table->colors, &color_table->size, 1,
1364                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1365       idx = color_table->avail++;
1366     }
1368   color_table->colors[idx] = color;
1369   [color retain];
1370 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1371   return idx;
1375 void
1376 ns_free_indexed_color (unsigned long idx, struct frame *f)
1378   struct ns_color_table *color_table;
1379   NSColor *color;
1380   NSNumber *index;
1382   if (!f)
1383     return;
1385   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1387   if (idx <= 0 || idx >= color_table->size) {
1388     message1 ("ns_free_indexed_color: Color index out of range.\n");
1389     return;
1390   }
1392   index = [NSNumber numberWithUnsignedInt: idx];
1393   if ([color_table->empty_indices containsObject: index]) {
1394     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1395     return;
1396   }
1398   color = color_table->colors[idx];
1399   [color release];
1400   color_table->colors[idx] = nil;
1401   [color_table->empty_indices addObject: index];
1402 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1406 static int
1407 ns_get_color (const char *name, NSColor **col)
1408 /* --------------------------------------------------------------------------
1409      Parse a color name
1410    -------------------------------------------------------------------------- */
1411 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1412    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1413    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1415   NSColor *new = nil;
1416   static char hex[20];
1417   int scaling;
1418   float r = -1.0, g, b;
1419   NSString *nsname = [NSString stringWithUTF8String: name];
1421 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1422   BLOCK_INPUT;
1424   if ([nsname isEqualToString: @"ns_selection_color"])
1425     {
1426       nsname = ns_selection_color;
1427       name = [ns_selection_color UTF8String];
1428     }
1430   /* First, check for some sort of numeric specification. */
1431   hex[0] = '\0';
1433   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1434     {
1435       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1436       [scanner scanFloat: &r];
1437       [scanner scanFloat: &g];
1438       [scanner scanFloat: &b];
1439     }
1440   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1441     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1442   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1443     {
1444       int len = (strlen(name) - 1);
1445       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1446       int i;
1447       scaling = strlen(name+start) / 3;
1448       for (i = 0; i < 3; i++)
1449         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1450                  name + start + i * scaling);
1451       hex[3 * (scaling + 1) - 1] = '\0';
1452     }
1454   if (hex[0])
1455     {
1456       int rr, gg, bb;
1457       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1458       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1459         {
1460           r = rr / fscale;
1461           g = gg / fscale;
1462           b = bb / fscale;
1463         }
1464     }
1466   if (r >= 0.0)
1467     {
1468       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1469       UNBLOCK_INPUT;
1470       return 0;
1471     }
1473   /* Otherwise, color is expected to be from a list */
1474   {
1475     NSEnumerator *lenum, *cenum;
1476     NSString *name;
1477     NSColorList *clist;
1479 #ifdef NS_IMPL_GNUSTEP
1480     /* XXX: who is wrong, the requestor or the implementation? */
1481     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1482         == NSOrderedSame)
1483       nsname = @"highlightColor";
1484 #endif
1486     lenum = [[NSColorList availableColorLists] objectEnumerator];
1487     while ( (clist = [lenum nextObject]) && new == nil)
1488       {
1489         cenum = [[clist allKeys] objectEnumerator];
1490         while ( (name = [cenum nextObject]) && new == nil )
1491           {
1492             if ([name compare: nsname
1493                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1494               new = [clist colorWithKey: name];
1495           }
1496       }
1497   }
1499   if (new)
1500     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1501   UNBLOCK_INPUT;
1502   return new ? 0 : 1;
1507 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1508 /* --------------------------------------------------------------------------
1509      Convert a Lisp string object to a NS color
1510    -------------------------------------------------------------------------- */
1512   NSTRACE (ns_lisp_to_color);
1513   if (STRINGP (color))
1514     return ns_get_color (SSDATA (color), col);
1515   else if (SYMBOLP (color))
1516     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1517   return 1;
1521 Lisp_Object
1522 ns_color_to_lisp (NSColor *col)
1523 /* --------------------------------------------------------------------------
1524      Convert a color to a lisp string with the RGB equivalent
1525    -------------------------------------------------------------------------- */
1527   CGFloat red, green, blue, alpha, gray;
1528   char buf[1024];
1529   const char *str;
1530   NSTRACE (ns_color_to_lisp);
1532   BLOCK_INPUT;
1533   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1535       if ((str =[[col colorNameComponent] UTF8String]))
1536         {
1537           UNBLOCK_INPUT;
1538           return build_string ((char *)str);
1539         }
1541     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1542         getRed: &red green: &green blue: &blue alpha: &alpha];
1543   if (red ==green && red ==blue)
1544     {
1545       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1546             getWhite: &gray alpha: &alpha];
1547       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1548                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1549       UNBLOCK_INPUT;
1550       return build_string (buf);
1551     }
1553   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1554             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1556   UNBLOCK_INPUT;
1557   return build_string (buf);
1561 void
1562 ns_query_color(void *col, XColor *color_def, int setPixel)
1563 /* --------------------------------------------------------------------------
1564          Get ARGB values out of NSColor col and put them into color_def.
1565          If setPixel, set the pixel to a concatenated version.
1566          and set color_def pixel to the resulting index.
1567    -------------------------------------------------------------------------- */
1569   CGFloat r, g, b, a;
1571   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1572   color_def->red   = r * 65535;
1573   color_def->green = g * 65535;
1574   color_def->blue  = b * 65535;
1576   if (setPixel == YES)
1577     color_def->pixel
1578       = ARGB_TO_ULONG((int)(a*255),
1579                       (int)(r*255), (int)(g*255), (int)(b*255));
1584 ns_defined_color (struct frame *f,
1585                   const char *name,
1586                   XColor *color_def,
1587                   int alloc,
1588                   char makeIndex)
1589 /* --------------------------------------------------------------------------
1590          Return 1 if named color found, and set color_def rgb accordingly.
1591          If makeIndex and alloc are nonzero put the color in the color_table,
1592          and set color_def pixel to the resulting index.
1593          If makeIndex is zero, set color_def pixel to ARGB.
1594          Return 0 if not found
1595    -------------------------------------------------------------------------- */
1597   NSColor *col;
1598   NSTRACE (ns_defined_color);
1600   BLOCK_INPUT;
1601   if (ns_get_color (name, &col) != 0) /* Color not found  */
1602     {
1603       UNBLOCK_INPUT;
1604       return 0;
1605     }
1606   if (makeIndex && alloc)
1607     color_def->pixel = ns_index_color (col, f);
1608   ns_query_color (col, color_def, !makeIndex);
1609   UNBLOCK_INPUT;
1610   return 1;
1614 unsigned long
1615 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1616 /* --------------------------------------------------------------------------
1617     return an autoreleased RGB color
1618    -------------------------------------------------------------------------- */
1620 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1621   if (r < 0.0) r = 0.0;
1622   else if (r > 1.0) r = 1.0;
1623   if (g < 0.0) g = 0.0;
1624   else if (g > 1.0) g = 1.0;
1625   if (b < 0.0) b = 0.0;
1626   else if (b > 1.0) b = 1.0;
1627   if (a < 0.0) a = 0.0;
1628   else if (a > 1.0) a = 1.0;
1629   return (unsigned long) ns_index_color(
1630     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1634 void
1635 x_set_frame_alpha (struct frame *f)
1636 /* --------------------------------------------------------------------------
1637      change the entire-frame transparency
1638    -------------------------------------------------------------------------- */
1640   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1641   EmacsView *view = FRAME_NS_VIEW (f);
1642   double alpha = 1.0;
1643   double alpha_min = 1.0;
1645   if (dpyinfo->x_highlight_frame == f)
1646     alpha = f->alpha[0];
1647   else
1648     alpha = f->alpha[1];
1650   if (FLOATP (Vframe_alpha_lower_limit))
1651     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1652   else if (INTEGERP (Vframe_alpha_lower_limit))
1653     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1655   if (alpha < 0.0)
1656     return;
1657   else if (1.0 < alpha)
1658     alpha = 1.0;
1659   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1660     alpha = alpha_min;
1662 #ifdef NS_IMPL_COCOA
1663   [[view window] setAlphaValue: alpha];
1664 #endif
1668 /* ==========================================================================
1670     Mouse handling
1672    ========================================================================== */
1675 void
1676 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1677 /* --------------------------------------------------------------------------
1678      Programmatically reposition mouse pointer in pixel coordinates
1679    -------------------------------------------------------------------------- */
1681   NSTRACE (x_set_mouse_pixel_position);
1682   ns_raise_frame (f);
1683 #if 0
1684   /* FIXME: this does not work, and what about GNUstep? */
1685 #ifdef NS_IMPL_COCOA
1686   [FRAME_NS_VIEW (f) lockFocus];
1687   PSsetmouse ((float)pix_x, (float)pix_y);
1688   [FRAME_NS_VIEW (f) unlockFocus];
1689 #endif
1690 #endif
1694 void
1695 x_set_mouse_position (struct frame *f, int h, int v)
1696 /* --------------------------------------------------------------------------
1697      Programmatically reposition mouse pointer in character coordinates
1698    -------------------------------------------------------------------------- */
1700   int pix_x, pix_y;
1702   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1703   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1705   if (pix_x < 0) pix_x = 0;
1706   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1708   if (pix_y < 0) pix_y = 0;
1709   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1711   x_set_mouse_pixel_position (f, pix_x, pix_y);
1715 static int
1716 note_mouse_movement (struct frame *frame, float x, float y)
1717 /*   ------------------------------------------------------------------------
1718      Called by EmacsView on mouseMovement events.  Passes on
1719      to emacs mainstream code if we moved off of a rect of interest
1720      known as last_mouse_glyph.
1721      ------------------------------------------------------------------------ */
1723 //  NSTRACE (note_mouse_movement);
1725   XSETFRAME (last_mouse_motion_frame, frame);
1727   /* Note, this doesn't get called for enter/leave, since we don't have a
1728      position.  Those are taken care of in the corresponding NSView methods. */
1730   /* has movement gone beyond last rect we were tracking? */
1731   if (x < last_mouse_glyph.origin.x ||
1732       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1733       y < last_mouse_glyph.origin.y ||
1734       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1735     {
1736       ns_update_begin(frame);
1737       frame->mouse_moved = 1;
1738       note_mouse_highlight (frame, x, y);
1739       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1740       ns_update_end(frame);
1741       return 1;
1742     }
1744   return 0;
1748 static void
1749 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1750                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1751                    Time *time)
1752 /* --------------------------------------------------------------------------
1753     External (hook): inform emacs about mouse position and hit parts.
1754     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1755     x & y should be position in the scrollbar (the whole bar, not the handle)
1756     and length of scrollbar respectively
1757    -------------------------------------------------------------------------- */
1759   id view;
1760   NSPoint position;
1761   Lisp_Object frame, tail;
1762   struct frame *f;
1763   struct ns_display_info *dpyinfo;
1765   NSTRACE (ns_mouse_position);
1767   if (*fp == NULL)
1768     {
1769       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1770       return;
1771     }
1773   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1775   BLOCK_INPUT;
1777   if (last_mouse_scroll_bar != nil && insist == 0)
1778     {
1779       /* TODO: we do not use this path at the moment because drag events will
1780            go directly to the EmacsScroller.  Leaving code in for now. */
1781       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1782                                               x: x y: y];
1783       if (time) *time = last_mouse_movement_time;
1784       last_mouse_scroll_bar = nil;
1785     }
1786   else
1787     {
1788       /* Clear the mouse-moved flag for every frame on this display.  */
1789       FOR_EACH_FRAME (tail, frame)
1790         if (FRAME_NS_P (XFRAME (frame))
1791             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1792           XFRAME (frame)->mouse_moved = 0;
1794       last_mouse_scroll_bar = nil;
1795       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1796         f = last_mouse_frame;
1797       else
1798         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1799                                     : SELECTED_FRAME ();
1801       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1802         {
1803           view = FRAME_NS_VIEW (*fp);
1805           position = [[view window] mouseLocationOutsideOfEventStream];
1806           position = [view convertPoint: position fromView: nil];
1807           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1808 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1810           if (bar_window) *bar_window = Qnil;
1811           if (part) *part = 0; /*scroll_bar_handle; */
1813           if (x) XSETINT (*x, lrint (position.x));
1814           if (y) XSETINT (*y, lrint (position.y));
1815           if (time) *time = last_mouse_movement_time;
1816           *fp = f;
1817         }
1818     }
1820   UNBLOCK_INPUT;
1824 static void
1825 ns_frame_up_to_date (struct frame *f)
1826 /* --------------------------------------------------------------------------
1827     External (hook): Fix up mouse highlighting right after a full update.
1828     Some highlighting was deferred if GC was happening during
1829     note_mouse_highlight (), while other highlighting was deferred for update.
1830    -------------------------------------------------------------------------- */
1832   NSTRACE (ns_frame_up_to_date);
1834   if (FRAME_NS_P (f))
1835     {
1836       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1837       if ((hlinfo->mouse_face_deferred_gc || f ==hlinfo->mouse_face_mouse_frame)
1838       /*&& hlinfo->mouse_face_mouse_frame*/)
1839         {
1840           BLOCK_INPUT;
1841           ns_update_begin(f);
1842           if (hlinfo->mouse_face_mouse_frame)
1843             note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1844                                   hlinfo->mouse_face_mouse_x,
1845                                   hlinfo->mouse_face_mouse_y);
1846           hlinfo->mouse_face_deferred_gc = 0;
1847           ns_update_end(f);
1848           UNBLOCK_INPUT;
1849         }
1850     }
1854 static void
1855 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1856 /* --------------------------------------------------------------------------
1857     External (RIF): set frame mouse pointer type.
1858    -------------------------------------------------------------------------- */
1860   NSTRACE (ns_define_frame_cursor);
1861   if (FRAME_POINTER_TYPE (f) != cursor)
1862     {
1863       EmacsView *view = FRAME_NS_VIEW (f);
1864       FRAME_POINTER_TYPE (f) = cursor;
1865       [[view window] invalidateCursorRectsForView: view];
1866       /* Redisplay assumes this function also draws the changed frame
1867          cursor, but this function doesn't, so do it explicitly.  */
1868       x_update_cursor (f, 1);
1869     }
1874 /* ==========================================================================
1876     Keyboard handling
1878    ========================================================================== */
1881 static unsigned
1882 ns_convert_key (unsigned code)
1883 /* --------------------------------------------------------------------------
1884     Internal call used by NSView-keyDown.
1885    -------------------------------------------------------------------------- */
1887   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1888                                 / sizeof (convert_ns_to_X_keysym[0]));
1889   unsigned keysym;
1890   /* An array would be faster, but less easy to read. */
1891   for (keysym = 0; keysym < last_keysym; keysym += 2)
1892     if (code == convert_ns_to_X_keysym[keysym])
1893       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1894   return 0;
1895 /* if decide to use keyCode and Carbon table, use this line:
1896      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1900 char *
1901 x_get_keysym_name (int keysym)
1902 /* --------------------------------------------------------------------------
1903     Called by keyboard.c.  Not sure if the return val is important, except
1904     that it be unique.
1905    -------------------------------------------------------------------------- */
1907   static char value[16];
1908   NSTRACE (x_get_keysym_name);
1909   sprintf (value, "%d", keysym);
1910   return value;
1915 /* ==========================================================================
1917     Block drawing operations
1919    ========================================================================== */
1922 static void
1923 ns_redraw_scroll_bars (struct frame *f)
1925   int i;
1926   id view;
1927   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1928   NSTRACE (ns_judge_scroll_bars);
1929   for (i =[subviews count]-1; i >= 0; i--)
1930     {
1931       view = [subviews objectAtIndex: i];
1932       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1933       [view display];
1934     }
1938 void
1939 ns_clear_frame (struct frame *f)
1940 /* --------------------------------------------------------------------------
1941       External (hook): Erase the entire frame
1942    -------------------------------------------------------------------------- */
1944   NSView *view = FRAME_NS_VIEW (f);
1945   NSRect r;
1947   NSTRACE (ns_clear_frame);
1948   if (ns_in_resize)
1949     return;
1951  /* comes on initial frame because we have
1952     after-make-frame-functions = select-frame */
1953  if (!FRAME_DEFAULT_FACE (f))
1954    return;
1956   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1958   output_cursor.hpos = output_cursor.vpos = 0;
1959   output_cursor.x = -1;
1961   r = [view bounds];
1963   BLOCK_INPUT;
1964   ns_focus (f, &r, 1);
1965   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
1966   NSRectFill (r);
1967   ns_unfocus (f);
1969 #ifdef NS_IMPL_COCOA
1970   [[view window] display];  /* redraw resize handle */
1971 #endif
1973   /* as of 2006/11 or so this is now needed */
1974   ns_redraw_scroll_bars (f);
1975   UNBLOCK_INPUT;
1979 static void
1980 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
1981 /* --------------------------------------------------------------------------
1982     External (RIF):  Clear section of frame
1983    -------------------------------------------------------------------------- */
1985   NSRect r = NSMakeRect (x, y, width, height);
1986   NSView *view = FRAME_NS_VIEW (f);
1987   struct face *face = FRAME_DEFAULT_FACE (f);
1989   if (!view || !face)
1990     return;
1992   NSTRACE (ns_clear_frame_area);
1994   r = NSIntersectionRect (r, [view frame]);
1995   ns_focus (f, &r, 1);
1996   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
1998 #ifdef NS_IMPL_COCOA
1999   {
2000     /* clip out the resize handle */
2001     NSWindow *window = [FRAME_NS_VIEW (f) window];
2002     NSRect ir
2003       = [view convertRect: ns_resize_handle_rect (window) fromView: nil];
2005     ir = NSIntersectionRect (r, ir);
2006     if (NSIsEmptyRect (ir))
2007       {
2008 #endif
2010   NSRectFill (r);
2012 #ifdef NS_IMPL_COCOA
2013       }
2014     else
2015       {
2016         NSRect r1 = r, r2 = r; /* upper and lower non-intersecting */
2017         r1.size.height -= ir.size.height;
2018         r2.origin.y += r1.size.height;
2019         r2.size.width -= ir.size.width;
2020         r2.size.height = ir.size.height;
2021         NSRectFill (r1);
2022         NSRectFill (r2);
2023       }
2024   }
2025 #endif
2027   ns_unfocus (f);
2028   return;
2032 static void
2033 ns_scroll_run (struct window *w, struct run *run)
2034 /* --------------------------------------------------------------------------
2035     External (RIF):  Insert or delete n lines at line vpos
2036    -------------------------------------------------------------------------- */
2038   struct frame *f = XFRAME (w->frame);
2039   int x, y, width, height, from_y, to_y, bottom_y;
2041   NSTRACE (ns_scroll_run);
2043   /* begin copy from other terms */
2044   /* Get frame-relative bounding box of the text display area of W,
2045      without mode lines.  Include in this box the left and right
2046      fringe of W.  */
2047   window_box (w, -1, &x, &y, &width, &height);
2049   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2050   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2051   bottom_y = y + height;
2053   if (to_y < from_y)
2054     {
2055       /* Scrolling up.  Make sure we don't copy part of the mode
2056          line at the bottom.  */
2057       if (from_y + run->height > bottom_y)
2058         height = bottom_y - from_y;
2059       else
2060         height = run->height;
2061     }
2062   else
2063     {
2064       /* Scrolling down.  Make sure we don't copy over the mode line.
2065          at the bottom.  */
2066       if (to_y + run->height > bottom_y)
2067         height = bottom_y - to_y;
2068       else
2069         height = run->height;
2070     }
2071   /* end copy from other terms */
2073   if (height == 0)
2074       return;
2076   BLOCK_INPUT;
2078   updated_window = w;
2079   x_clear_cursor (w);
2081   {
2082     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2083     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2084     NSPoint dstOrigin = NSMakePoint (x, to_y);
2086     ns_focus (f, &dstRect, 1);
2087     NSCopyBits (0, srcRect , dstOrigin);
2088     ns_unfocus (f);
2089   }
2091   UNBLOCK_INPUT;
2095 static void
2096 ns_after_update_window_line (struct glyph_row *desired_row)
2097 /* --------------------------------------------------------------------------
2098     External (RIF): preparatory to fringe update after text was updated
2099    -------------------------------------------------------------------------- */
2101   struct window *w = updated_window;
2102   struct frame *f;
2103   int width, height;
2105   NSTRACE (ns_after_update_window_line);
2107   /* begin copy from other terms */
2108   eassert (w);
2110   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2111     desired_row->redraw_fringe_bitmaps_p = 1;
2113   /* When a window has disappeared, make sure that no rest of
2114      full-width rows stays visible in the internal border.
2115      Under NS this is drawn inside the fringes. */
2116   if (windows_or_buffers_changed
2117       && (f = XFRAME (w->frame),
2118           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2119           width != 0)
2120       && (height = desired_row->visible_height,
2121           height > 0))
2122     {
2123       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2125       /* Internal border is drawn below the tool bar.  */
2126       if (WINDOWP (f->tool_bar_window)
2127           && w == XWINDOW (f->tool_bar_window))
2128         y -= width;
2129       /* end copy from other terms */
2131       BLOCK_INPUT;
2132       if (!desired_row->full_width_p)
2133         {
2134           int x1 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2135             + WINDOW_LEFT_FRINGE_WIDTH (w);
2136           int x2 = WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
2137             + FRAME_PIXEL_WIDTH (f) - NS_SCROLL_BAR_WIDTH (f)
2138             - WINDOW_RIGHT_FRINGE_WIDTH (w)
2139             - FRAME_INTERNAL_BORDER_WIDTH (f);
2140           ns_clear_frame_area (f, x1, y, width, height);
2141           ns_clear_frame_area (f, x2, y, width, height);
2142         }
2143       UNBLOCK_INPUT;
2144     }
2148 static void
2149 ns_shift_glyphs_for_insert (struct frame *f,
2150                            int x, int y, int width, int height,
2151                            int shift_by)
2152 /* --------------------------------------------------------------------------
2153     External (RIF): copy an area horizontally, don't worry about clearing src
2154    -------------------------------------------------------------------------- */
2156   NSRect srcRect = NSMakeRect (x, y, width, height);
2157   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2158   NSPoint dstOrigin = dstRect.origin;
2160   NSTRACE (ns_shift_glyphs_for_insert);
2162   ns_focus (f, &dstRect, 1);
2163   NSCopyBits (0, srcRect, dstOrigin);
2164   ns_unfocus (f);
2169 /* ==========================================================================
2171     Character encoding and metrics
2173    ========================================================================== */
2176 static inline void
2177 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2178 /* --------------------------------------------------------------------------
2179      External (RIF); compute left/right overhang of whole string and set in s
2180    -------------------------------------------------------------------------- */
2182   struct font *font = s->font;
2184   if (s->char2b)
2185     {
2186       struct font_metrics metrics;
2187       unsigned int codes[2];
2188       codes[0] = *(s->char2b);
2189       codes[1] = *(s->char2b + s->nchars - 1);
2191       font->driver->text_extents (font, codes, 2, &metrics);
2192       s->left_overhang = -metrics.lbearing;
2193       s->right_overhang
2194         = metrics.rbearing > metrics.width
2195         ? metrics.rbearing - metrics.width : 0;
2196     }
2197   else
2198     {
2199       s->left_overhang = 0;
2200       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2201         FONT_HEIGHT (font) * 0.2 : 0;
2202     }
2207 /* ==========================================================================
2209     Fringe and cursor drawing
2211    ========================================================================== */
2214 extern int max_used_fringe_bitmap;
2215 static void
2216 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2217                       struct draw_fringe_bitmap_params *p)
2218 /* --------------------------------------------------------------------------
2219     External (RIF); fringe-related
2220    -------------------------------------------------------------------------- */
2222   struct frame *f = XFRAME (WINDOW_FRAME (w));
2223   struct face *face = p->face;
2224   int rowY;
2225   static EmacsImage **bimgs = NULL;
2226   static int nBimgs = 0;
2227   /* NS-specific: move internal border inside fringe */
2228   int x = p->bx < 0 ? p->x : p->bx;
2229   int wd = p->bx < 0 ? p->wd : p->nx;
2230   BOOL fringeOnVeryLeft
2231     = x - WINDOW_LEFT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w)
2232       - FRAME_INTERNAL_BORDER_WIDTH (f) < 10;
2233   BOOL fringeOnVeryRight
2234     = FRAME_PIXEL_WIDTH (f) - x - wd - FRAME_INTERNAL_BORDER_WIDTH (f)
2235       - WINDOW_RIGHT_SCROLL_BAR_COLS (w) * WINDOW_FRAME_COLUMN_WIDTH (w) < 10;
2236   int xAdjust = FRAME_INTERNAL_BORDER_WIDTH (f) *
2237     (fringeOnVeryLeft ? -1 : (fringeOnVeryRight ? 1 : 0));
2239   /* grow bimgs if needed */
2240   if (nBimgs < max_used_fringe_bitmap)
2241     {
2242       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2243       memset (bimgs + nBimgs, 0,
2244               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2245       nBimgs = max_used_fringe_bitmap;
2246     }
2248   /* Must clip because of partially visible lines.  */
2249   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2250   ns_clip_to_row (w, row, -1, YES);
2252   if (p->bx >= 0 && !p->overlay_p)
2253     {
2254       int yAdjust = rowY - FRAME_INTERNAL_BORDER_WIDTH (f) < 5 ?
2255         -FRAME_INTERNAL_BORDER_WIDTH (f) : 0;
2256       int yIncr = FRAME_PIXEL_HEIGHT (f) - (p->by+yAdjust + p->ny) < 5 ?
2257         FRAME_INTERNAL_BORDER_WIDTH (f) : 0
2258         + (yAdjust ? FRAME_INTERNAL_BORDER_WIDTH (f) : 0);
2259       NSRect r = NSMakeRect (p->bx+xAdjust, p->by+yAdjust, p->nx, p->ny+yIncr);
2260       NSRectClip (r);
2261       [ns_lookup_indexed_color(face->background, f) set];
2262       NSRectFill (r);
2263     }
2265   if (p->which)
2266     {
2267       NSRect r = NSMakeRect (p->x+xAdjust, p->y, p->wd, p->h);
2268       EmacsImage *img = bimgs[p->which - 1];
2270       if (!img)
2271         {
2272           unsigned short *bits = p->bits + p->dh;
2273           int len = p->h;
2274           int i;
2275           unsigned char *cbits = xmalloc (len);
2277           for (i =0; i<len; i++)
2278             cbits[i] = ~(bits[i] & 0xff);
2279           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2280                                            flip: NO];
2281           bimgs[p->which - 1] = img;
2282           xfree (cbits);
2283         }
2285       NSRectClip (r);
2286       /* Since we composite the bitmap instead of just blitting it, we need
2287          to erase the whole background. */
2288       [ns_lookup_indexed_color(face->background, f) set];
2289       NSRectFill (r);
2290       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2291       [img drawInRect: r
2292               fromRect: NSZeroRect
2293              operation: NSCompositeSourceOver
2294               fraction: 1.0
2295            respectFlipped: YES
2296                 hints: nil];
2297     }
2298   ns_unfocus (f);
2302 static void
2303 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2304                        int x, int y, int cursor_type, int cursor_width,
2305                        int on_p, int active_p)
2306 /* --------------------------------------------------------------------------
2307      External call (RIF): draw cursor.
2308      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2309    -------------------------------------------------------------------------- */
2311   NSRect r, s;
2312   int fx, fy, h, cursor_height;
2313   struct frame *f = WINDOW_XFRAME (w);
2314   struct glyph *phys_cursor_glyph;
2315   int overspill;
2316   struct glyph *cursor_glyph;
2317   struct face *face;
2318   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2320   /* If cursor is out of bounds, don't draw garbage.  This can happen
2321      in mini-buffer windows when switching between echo area glyphs
2322      and mini-buffer.  */
2324   NSTRACE (dumpcursor);
2326   if (!on_p)
2327     return;
2329   w->phys_cursor_type = cursor_type;
2330   w->phys_cursor_on_p = on_p;
2332   if (cursor_type == NO_CURSOR)
2333     {
2334       w->phys_cursor_width = 0;
2335       return;
2336     }
2338   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2339     {
2340       if (glyph_row->exact_window_width_line_p
2341           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2342         {
2343           glyph_row->cursor_in_fringe_p = 1;
2344           draw_fringe_bitmap (w, glyph_row, 0);
2345         }
2346       return;
2347     }
2349   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2350      (other terminals do it the other way round).  We must set
2351      w->phys_cursor_width to the cursor width.  For bar cursors, that
2352      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2353   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2355   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2356      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2357   if (cursor_type == BAR_CURSOR)
2358     {
2359       if (cursor_width < 1)
2360         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2361       w->phys_cursor_width = cursor_width;
2362     }
2363   /* If we have an HBAR, "cursor_width" MAY specify height. */
2364   else if (cursor_type == HBAR_CURSOR)
2365     {
2366       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2367       fy += h - cursor_height;
2368       h = cursor_height;
2369     }
2371   r.origin.x = fx, r.origin.y = fy;
2372   r.size.height = h;
2373   r.size.width = w->phys_cursor_width;
2375   /* FIXME: if we overwrite the internal border area, it does not get erased;
2376      fix by truncating cursor, but better would be to erase properly */
2377   overspill = r.origin.x + r.size.width -
2378     WINDOW_TEXT_TO_FRAME_PIXEL_X (w, WINDOW_BOX_RIGHT_EDGE_X (w)
2379       - WINDOW_TOTAL_FRINGE_WIDTH (w) - FRAME_INTERNAL_BORDER_WIDTH (f));
2380   if (overspill > 0)
2381     r.size.width -= overspill;
2383   /* TODO: only needed in rare cases with last-resort font in HELLO..
2384      should we do this more efficiently? */
2385   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2388   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2389   if (face && NS_FACE_BACKGROUND (face)
2390       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2391     {
2392       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2393       hollow_color = FRAME_CURSOR_COLOR (f);
2394     }
2395   else
2396     [FRAME_CURSOR_COLOR (f) set];
2398 #ifdef NS_IMPL_COCOA
2399   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2400            atomic.  Cleaner ways of doing this should be investigated.
2401            One way would be to set a global variable DRAWING_CURSOR
2402            when making the call to draw_phys..(), don't focus in that
2403            case, then move the ns_unfocus() here after that call. */
2404   NSDisableScreenUpdates ();
2405 #endif
2407   switch (cursor_type)
2408     {
2409     case NO_CURSOR:
2410       break;
2411     case FILLED_BOX_CURSOR:
2412       NSRectFill (r);
2413       break;
2414     case HOLLOW_BOX_CURSOR:
2415       NSRectFill (r);
2416       [hollow_color set];
2417       NSRectFill (NSInsetRect (r, 1, 1));
2418       [FRAME_CURSOR_COLOR (f) set];
2419       break;
2420     case HBAR_CURSOR:
2421       NSRectFill (r);
2422       break;
2423     case BAR_CURSOR:
2424       s = r;
2425       /* If the character under cursor is R2L, draw the bar cursor
2426          on the right of its glyph, rather than on the left.  */
2427       cursor_glyph = get_phys_cursor_glyph (w);
2428       if ((cursor_glyph->resolved_level & 1) != 0)
2429         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2431       NSRectFill (s);
2432       break;
2433     }
2434   ns_unfocus (f);
2436   /* draw the character under the cursor */
2437   if (cursor_type != NO_CURSOR)
2438     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2440 #ifdef NS_IMPL_COCOA
2441   NSEnableScreenUpdates ();
2442 #endif
2447 static void
2448 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2449 /* --------------------------------------------------------------------------
2450      External (RIF): Draw a vertical line.
2451    -------------------------------------------------------------------------- */
2453   struct frame *f = XFRAME (WINDOW_FRAME (w));
2454   struct face *face;
2455   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2457   NSTRACE (ns_draw_vertical_window_border);
2459   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2460   if (face)
2461       [ns_lookup_indexed_color(face->foreground, f) set];
2463   ns_focus (f, &r, 1);
2464   NSRectFill(r);
2465   ns_unfocus (f);
2469 void
2470 show_hourglass (struct atimer *timer)
2472   if (hourglass_shown_p)
2473     return;
2475   BLOCK_INPUT;
2477   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2479   hourglass_shown_p = 1;
2480   UNBLOCK_INPUT;
2484 void
2485 hide_hourglass (void)
2487   if (!hourglass_shown_p)
2488     return;
2490   BLOCK_INPUT;
2492   /* TODO: remove NSProgressIndicator from all frames */
2494   hourglass_shown_p = 0;
2495   UNBLOCK_INPUT;
2500 /* ==========================================================================
2502     Glyph drawing operations
2504    ========================================================================== */
2507 static inline NSRect
2508 ns_fix_rect_ibw (NSRect r, int fibw, int frame_pixel_width)
2509 /* --------------------------------------------------------------------------
2510     Under NS we draw internal borders inside fringes, and want full-width
2511     rendering to go all the way to edge.  This function makes that correction.
2512    -------------------------------------------------------------------------- */
2514   if (r.origin.y <= fibw+1)
2515     {
2516       r.size.height += r.origin.y;
2517       r.origin.y = 0;
2518     }
2519   if (r.origin.x <= fibw+1)
2520     {
2521       r.size.width += r.origin.x;
2522       r.origin.x = 0;
2523     }
2524   if (frame_pixel_width - (r.origin.x+r.size.width) <= fibw+1)
2525     r.size.width += fibw;
2527   return r;
2531 static int
2532 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2533 /* --------------------------------------------------------------------------
2534     Wrapper utility to account for internal border width on full-width lines,
2535     and allow top full-width rows to hit the frame top.  nr should be pointer
2536     to two successive NSRects.  Number of rects actually used is returned.
2537    -------------------------------------------------------------------------- */
2539   int n = get_glyph_string_clip_rects (s, nr, 2);
2540   if (s->row->full_width_p)
2541     {
2542       *nr = ns_fix_rect_ibw (*nr, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2543                             FRAME_PIXEL_WIDTH (s->f));
2544       if (n == 2)
2545         *nr = ns_fix_rect_ibw (*(nr+1), FRAME_INTERNAL_BORDER_WIDTH (s->f),
2546                               FRAME_PIXEL_WIDTH (s->f));
2547     }
2548   return n;
2551 /* --------------------------------------------------------------------
2552    Draw a wavy line under glyph string s. The wave fills wave_height
2553    pixels from y.
2555                     x          wave_length = 3
2556                                  --
2557                 y    *   *   *   *   *
2558                      |* * * * * * * * *
2559     wave_height = 3  | *   *   *   *
2560   --------------------------------------------------------------------- */
2562 static void
2563 ns_draw_underwave (struct glyph_string *s, CGFloat width, CGFloat x)
2565   int wave_height = 3, wave_length = 3;
2566   int y, dx, dy, odd, xmax;
2567   NSPoint a, b;
2568   NSRect waveClip;
2570   dx = wave_length;
2571   dy = wave_height - 1;
2572   y =  s->ybase + 1;
2573   xmax = x + width;
2575   /* Find and set clipping rectangle */
2576   waveClip = NSMakeRect (x, y, width, wave_height);
2577   [[NSGraphicsContext currentContext] saveGraphicsState];
2578   NSRectClip (waveClip);
2580   /* Draw the waves */
2581   a.x = x - ((int)(x) % dx);
2582   b.x = a.x + dx;
2583   odd = (int)(a.x/dx) % 2;
2584   a.y = b.y = y;
2586   if (odd)
2587     a.y += dy;
2588   else
2589     b.y += dy;
2591   while (a.x <= xmax)
2592     {
2593       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2594       a.x = b.x, a.y = b.y;
2595       b.x += dx, b.y = y + odd*dy;
2596       odd = !odd;
2597     }
2599   /* Restore previous clipping rectangle(s) */
2600   [[NSGraphicsContext currentContext] restoreGraphicsState];
2605 void
2606 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2607                          NSColor *defaultCol, CGFloat width, CGFloat x)
2608 /* --------------------------------------------------------------------------
2609    Draw underline, overline, and strike-through on glyph string s.
2610    -------------------------------------------------------------------------- */
2612   if (s->for_overlaps)
2613     return;
2615   /* Do underline. */
2616   if (face->underline_p)
2617     {
2618       if (s->face->underline_type == FACE_UNDER_WAVE)
2619         {
2620           if (face->underline_defaulted_p)
2621             [defaultCol set];
2622           else
2623             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2625           ns_draw_underwave (s, width, x);
2626         }
2627       else if (s->face->underline_type == FACE_UNDER_LINE)
2628         {
2630           NSRect r;
2631           unsigned long thickness, position;
2633           /* If the prev was underlined, match its appearance. */
2634           if (s->prev && s->prev->face->underline_p
2635               && s->prev->underline_thickness > 0)
2636             {
2637               thickness = s->prev->underline_thickness;
2638               position = s->prev->underline_position;
2639             }
2640           else
2641             {
2642               struct font *font;
2643               unsigned long descent;
2645               font=s->font;
2646               descent = s->y + s->height - s->ybase;
2648               /* Use underline thickness of font, defaulting to 1. */
2649               thickness = (font && font->underline_thickness > 0)
2650                 ? font->underline_thickness : 1;
2652               /* Determine the offset of underlining from the baseline. */
2653               if (x_underline_at_descent_line)
2654                 position = descent - thickness;
2655               else if (x_use_underline_position_properties
2656                        && font && font->underline_position >= 0)
2657                 position = font->underline_position;
2658               else if (font)
2659                 position = lround (font->descent / 2);
2660               else
2661                 position = underline_minimum_offset;
2663               position = max (position, underline_minimum_offset);
2665               /* Ensure underlining is not cropped. */
2666               if (descent <= position)
2667                 {
2668                   position = descent - 1;
2669                   thickness = 1;
2670                 }
2671               else if (descent < position + thickness)
2672                 thickness = 1;
2673             }
2675           s->underline_thickness = thickness;
2676           s->underline_position = position;
2678           r = NSMakeRect (x, s->ybase + position, width, thickness);
2680           if (face->underline_defaulted_p)
2681             [defaultCol set];
2682           else
2683             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2684           NSRectFill (r);
2685         }
2686     }
2687   /* Do overline. We follow other terms in using a thickness of 1
2688      and ignoring overline_margin. */
2689   if (face->overline_p)
2690     {
2691       NSRect r;
2692       r = NSMakeRect (x, s->y, width, 1);
2694       if (face->overline_color_defaulted_p)
2695         [defaultCol set];
2696       else
2697         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2698       NSRectFill (r);
2699     }
2701   /* Do strike-through.  We follow other terms for thickness and
2702      vertical position.*/
2703   if (face->strike_through_p)
2704     {
2705       NSRect r;
2706       unsigned long dy;
2708       dy = lrint ((s->height - 1) / 2);
2709       r = NSMakeRect (x, s->y + dy, width, 1);
2711       if (face->strike_through_color_defaulted_p)
2712         [defaultCol set];
2713       else
2714         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2715       NSRectFill (r);
2716     }
2719 static void
2720 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2721 /* --------------------------------------------------------------------------
2722     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2723     Note we can't just use an NSDrawRect command, because of the possibility
2724     of some sides not being drawn, and because the rect will be filled.
2725    -------------------------------------------------------------------------- */
2727   NSRect s = r;
2728   [col set];
2730   /* top, bottom */
2731   s.size.height = thickness;
2732   NSRectFill (s);
2733   s.origin.y += r.size.height - thickness;
2734   NSRectFill (s);
2736   s.size.height = r.size.height;
2737   s.origin.y = r.origin.y;
2739   /* left, right (optional) */
2740   s.size.width = thickness;
2741   if (left_p)
2742     NSRectFill (s);
2743   if (right_p)
2744     {
2745       s.origin.x += r.size.width - thickness;
2746       NSRectFill (s);
2747     }
2751 static void
2752 ns_draw_relief (NSRect r, int thickness, char raised_p,
2753                char top_p, char bottom_p, char left_p, char right_p,
2754                struct glyph_string *s)
2755 /* --------------------------------------------------------------------------
2756     Draw a relief rect inside r, optionally leaving some sides open.
2757     Note we can't just use an NSDrawBezel command, because of the possibility
2758     of some sides not being drawn, and because the rect will be filled.
2759    -------------------------------------------------------------------------- */
2761   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2762   NSColor *newBaseCol = nil;
2763   NSRect sr = r;
2765   NSTRACE (ns_draw_relief);
2767   /* set up colors */
2769   if (s->face->use_box_color_for_shadows_p)
2770     {
2771       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2772     }
2773 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2774            && s->img->pixmap
2775            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2776        {
2777          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2778        } */
2779   else
2780     {
2781       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2782     }
2784   if (newBaseCol == nil)
2785     newBaseCol = [NSColor grayColor];
2787   if (newBaseCol != baseCol)  /* TODO: better check */
2788     {
2789       [baseCol release];
2790       baseCol = [newBaseCol retain];
2791       [lightCol release];
2792       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2793       [darkCol release];
2794       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2795     }
2797   [(raised_p ? lightCol : darkCol) set];
2799   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2801   /* top */
2802   sr.size.height = thickness;
2803   if (top_p) NSRectFill (sr);
2805   /* left */
2806   sr.size.height = r.size.height;
2807   sr.size.width = thickness;
2808   if (left_p) NSRectFill (sr);
2810   [(raised_p ? darkCol : lightCol) set];
2812   /* bottom */
2813   sr.size.width = r.size.width;
2814   sr.size.height = thickness;
2815   sr.origin.y += r.size.height - thickness;
2816   if (bottom_p) NSRectFill (sr);
2818   /* right */
2819   sr.size.height = r.size.height;
2820   sr.origin.y = r.origin.y;
2821   sr.size.width = thickness;
2822   sr.origin.x += r.size.width - thickness;
2823   if (right_p) NSRectFill (sr);
2827 static void
2828 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2829 /* --------------------------------------------------------------------------
2830       Function modeled after x_draw_glyph_string_box ().
2831       Sets up parameters for drawing.
2832    -------------------------------------------------------------------------- */
2834   int right_x, last_x;
2835   char left_p, right_p;
2836   struct glyph *last_glyph;
2837   NSRect r;
2838   int thickness;
2839   struct face *face;
2841   if (s->hl == DRAW_MOUSE_FACE)
2842     {
2843       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2844       if (!face)
2845         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2846     }
2847   else
2848     face = s->face;
2850   thickness = face->box_line_width;
2852   NSTRACE (ns_dumpglyphs_box_or_relief);
2854   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2855             ? WINDOW_RIGHT_EDGE_X (s->w)
2856             : window_box_right (s->w, s->area));
2857   last_glyph = (s->cmp || s->img
2858                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2860   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2861               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2863   left_p = (s->first_glyph->left_box_line_p
2864             || (s->hl == DRAW_MOUSE_FACE
2865                 && (s->prev == NULL || s->prev->hl != s->hl)));
2866   right_p = (last_glyph->right_box_line_p
2867              || (s->hl == DRAW_MOUSE_FACE
2868                  && (s->next == NULL || s->next->hl != s->hl)));
2870   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2872   /* expand full-width row over internal borders */
2873   if (s->row->full_width_p)
2874     r = ns_fix_rect_ibw (r, FRAME_INTERNAL_BORDER_WIDTH (s->f),
2875                         FRAME_PIXEL_WIDTH (s->f));
2877   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2878   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2879     {
2880       ns_draw_box (r, abs (thickness),
2881                    ns_lookup_indexed_color (face->box_color, s->f),
2882                   left_p, right_p);
2883     }
2884   else
2885     {
2886       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2887                      1, 1, left_p, right_p, s);
2888     }
2892 static void
2893 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2894 /* --------------------------------------------------------------------------
2895       Modeled after x_draw_glyph_string_background, which draws BG in
2896       certain cases.  Others are left to the text rendering routine.
2897    -------------------------------------------------------------------------- */
2899   NSTRACE (ns_maybe_dumpglyphs_background);
2901   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2902     {
2903       int box_line_width = max (s->face->box_line_width, 0);
2904       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2905           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2906         {
2907           struct face *face;
2908           if (s->hl == DRAW_MOUSE_FACE)
2909             {
2910               face = FACE_FROM_ID (s->f,
2911                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2912               if (!face)
2913                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2914             }
2915           else
2916             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2917           if (!face->stipple)
2918             [(NS_FACE_BACKGROUND (face) != 0
2919               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2920               : FRAME_BACKGROUND_COLOR (s->f)) set];
2921           else
2922             {
2923               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2924               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2925             }
2927           if (s->hl != DRAW_CURSOR)
2928             {
2929               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2930                                     s->background_width,
2931                                     s->height-2*box_line_width);
2933               /* expand full-width row over internal borders */
2934               if (s->row->full_width_p)
2935                 {
2936                   int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
2937                   if (r.origin.y <= fibw+1 + box_line_width)
2938                     {
2939                       r.size.height += r.origin.y;
2940                       r.origin.y = 0;
2941                     }
2942                   if (r.origin.x <= fibw+1)
2943                     {
2944                       r.size.width += 2*r.origin.x;
2945                       r.origin.x = 0;
2946                     }
2947                   if (FRAME_PIXEL_WIDTH (s->f) - (r.origin.x + r.size.width)
2948                       <= fibw+1)
2949                     r.size.width += fibw;
2950                 }
2952               NSRectFill (r);
2953             }
2955           s->background_filled_p = 1;
2956         }
2957     }
2961 static void
2962 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2963 /* --------------------------------------------------------------------------
2964       Renders an image and associated borders.
2965    -------------------------------------------------------------------------- */
2967   EmacsImage *img = s->img->pixmap;
2968   int box_line_vwidth = max (s->face->box_line_width, 0);
2969   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2970   int bg_x, bg_y, bg_height;
2971   int th;
2972   char raised_p;
2973   NSRect br;
2974   struct face *face;
2975   NSColor *tdCol;
2977   NSTRACE (ns_dumpglyphs_image);
2979   if (s->face->box != FACE_NO_BOX
2980       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2981     x += abs (s->face->box_line_width);
2983   bg_x = x;
2984   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2985   bg_height = s->height;
2986   /* other terms have this, but was causing problems w/tabbar mode */
2987   /* - 2 * box_line_vwidth; */
2989   if (s->slice.x == 0) x += s->img->hmargin;
2990   if (s->slice.y == 0) y += s->img->vmargin;
2992   /* Draw BG: if we need larger area than image itself cleared, do that,
2993      otherwise, since we composite the image under NS (instead of mucking
2994      with its background color), we must clear just the image area. */
2995   if (s->hl == DRAW_MOUSE_FACE)
2996     {
2997       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2998       if (!face)
2999        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3000     }
3001   else
3002     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3004   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3006   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3007       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3008     {
3009       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3010       s->background_filled_p = 1;
3011     }
3012   else
3013     {
3014       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3015     }
3017   /* expand full-width row over internal borders */
3018   if (s->row->full_width_p)
3019     {
3020       int fibw = FRAME_INTERNAL_BORDER_WIDTH (s->f);
3021       if (br.origin.y <= fibw+1 + box_line_vwidth)
3022         {
3023           br.size.height += br.origin.y;
3024           br.origin.y = 0;
3025         }
3026       if (br.origin.x <= fibw+1 + box_line_vwidth)
3027         {
3028           br.size.width += br.origin.x;
3029           br.origin.x = 0;
3030         }
3031       if (FRAME_PIXEL_WIDTH (s->f) - (br.origin.x + br.size.width) <= fibw+1)
3032         br.size.width += fibw;
3033     }
3035   NSRectFill (br);
3037   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3038   if (img != nil)
3039       [img drawInRect: br
3040               fromRect: NSZeroRect
3041              operation: NSCompositeSourceOver
3042               fraction: 1.0
3043            respectFlipped: YES
3044                 hints: nil];
3046   if (s->hl == DRAW_CURSOR)
3047     {
3048     [FRAME_CURSOR_COLOR (s->f) set];
3049     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3050       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3051     else
3052       /* Currently on NS img->mask is always 0. Since
3053          get_window_cursor_type specifies a hollow box cursor when on
3054          a non-masked image we never reach this clause. But we put it
3055          in in anticipation of better support for image masks on
3056          NS. */
3057       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3058     }
3059   else
3060     {
3061       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3062     }
3064   /* Draw underline, overline, strike-through. */
3065   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3067   /* Draw relief, if requested */
3068   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3069     {
3070       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3071         {
3072           th = tool_bar_button_relief >= 0 ?
3073             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3074           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3075         }
3076       else
3077         {
3078           th = abs (s->img->relief);
3079           raised_p = (s->img->relief > 0);
3080         }
3082       r.origin.x = x - th;
3083       r.origin.y = y - th;
3084       r.size.width = s->slice.width + 2*th-1;
3085       r.size.height = s->slice.height + 2*th-1;
3086       ns_draw_relief (r, th, raised_p,
3087                       s->slice.y == 0,
3088                       s->slice.y + s->slice.height == s->img->height,
3089                       s->slice.x == 0,
3090                       s->slice.x + s->slice.width == s->img->width, s);
3091     }
3093   /* If there is no mask, the background won't be seen,
3094      so draw a rectangle on the image for the cursor.
3095      Do this for all images, getting transparency right is not reliable.  */
3096   if (s->hl == DRAW_CURSOR)
3097     {
3098       int thickness = abs (s->img->relief);
3099       if (thickness == 0) thickness = 1;
3100       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3101     }
3105 static void
3106 ns_dumpglyphs_stretch (struct glyph_string *s)
3108   NSRect r[2];
3109   int n, i;
3110   struct face *face;
3111   NSColor *fgCol, *bgCol;
3113   if (!s->background_filled_p)
3114     {
3115       n = ns_get_glyph_string_clip_rect (s, r);
3116       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3118       ns_focus (s->f, r, n);
3120       if (s->hl == DRAW_MOUSE_FACE)
3121        {
3122          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3123          if (!face)
3124            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3125        }
3126       else
3127        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3129       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3130       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3132       for (i=0; i<n; i++)
3133         {
3134           if (!s->row->full_width_p)
3135             {
3136               int overrun, leftoverrun;
3138               /* truncate to avoid overwriting fringe and/or scrollbar */
3139               overrun = max (0, (s->x + s->background_width)
3140                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3141                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3142               r[i].size.width -= overrun;
3144               /* truncate to avoid overwriting to left of the window box */
3145               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3146                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3148               if (leftoverrun > 0)
3149                 {
3150                   r[i].origin.x += leftoverrun;
3151                   r[i].size.width -= leftoverrun;
3152                 }
3154               /* XXX: Try to work between problem where a stretch glyph on
3155                  a partially-visible bottom row will clear part of the
3156                  modeline, and another where list-buffers headers and similar
3157                  rows erroneously have visible_height set to 0.  Not sure
3158                  where this is coming from as other terms seem not to show. */
3159               r[i].size.height = min (s->height, s->row->visible_height);
3160             }
3162           /* expand full-width rows over internal borders */
3163           else
3164             {
3165               r[i] = ns_fix_rect_ibw (r[i], FRAME_INTERNAL_BORDER_WIDTH (s->f),
3166                                       FRAME_PIXEL_WIDTH (s->f));
3167             }
3169           [bgCol set];
3171           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3172              overwriting cursor (usually when cursor on a tab) */
3173           if (s->hl == DRAW_CURSOR)
3174             {
3175               CGFloat x, width;
3177               x = r[i].origin.x;
3178               width = s->w->phys_cursor_width;
3179               r[i].size.width -= width;
3180               r[i].origin.x += width;
3182               NSRectFill (r[i]);
3184               /* Draw overlining, etc. on the cursor. */
3185               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3186                 ns_draw_text_decoration (s, face, bgCol, width, x);
3187               else
3188                 ns_draw_text_decoration (s, face, fgCol, width, x);
3189             }
3190           else
3191             {
3192               NSRectFill (r[i]);
3193             }
3195           /* Draw overlining, etc. on the stretch glyph (or the part
3196              of the stretch glyph after the cursor). */
3197           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3198                                    r[i].origin.x);
3199         }
3200       ns_unfocus (s->f);
3201       s->background_filled_p = 1;
3202     }
3206 static void
3207 ns_draw_glyph_string (struct glyph_string *s)
3208 /* --------------------------------------------------------------------------
3209       External (RIF): Main draw-text call.
3210    -------------------------------------------------------------------------- */
3212   /* TODO (optimize): focus for box and contents draw */
3213   NSRect r[2];
3214   int n;
3215   char box_drawn_p = 0;
3217   NSTRACE (ns_draw_glyph_string);
3219   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3220     {
3221       int width;
3222       struct glyph_string *next;
3224       for (width = 0, next = s->next;
3225            next && width < s->right_overhang;
3226            width += next->width, next = next->next)
3227         if (next->first_glyph->type != IMAGE_GLYPH)
3228           {
3229             if (next->first_glyph->type != STRETCH_GLYPH)
3230               {
3231                 n = ns_get_glyph_string_clip_rect (s->next, r);
3232                 ns_focus (s->f, r, n);
3233                 ns_maybe_dumpglyphs_background (s->next, 1);
3234                 ns_unfocus (s->f);
3235               }
3236             else
3237               {
3238                 ns_dumpglyphs_stretch (s->next);
3239               }
3240             next->num_clips = 0;
3241           }
3242     }
3244   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3245         && (s->first_glyph->type == CHAR_GLYPH
3246             || s->first_glyph->type == COMPOSITE_GLYPH))
3247     {
3248       n = ns_get_glyph_string_clip_rect (s, r);
3249       ns_focus (s->f, r, n);
3250       ns_maybe_dumpglyphs_background (s, 1);
3251       ns_dumpglyphs_box_or_relief (s);
3252       ns_unfocus (s->f);
3253       box_drawn_p = 1;
3254     }
3256   switch (s->first_glyph->type)
3257     {
3259     case IMAGE_GLYPH:
3260       n = ns_get_glyph_string_clip_rect (s, r);
3261       ns_focus (s->f, r, n);
3262       ns_dumpglyphs_image (s, r[0]);
3263       ns_unfocus (s->f);
3264       break;
3266     case STRETCH_GLYPH:
3267       ns_dumpglyphs_stretch (s);
3268       break;
3270     case CHAR_GLYPH:
3271     case COMPOSITE_GLYPH:
3272       n = ns_get_glyph_string_clip_rect (s, r);
3273       ns_focus (s->f, r, n);
3275       if (s->for_overlaps || (s->cmp_from > 0
3276                               && ! s->first_glyph->u.cmp.automatic))
3277         s->background_filled_p = 1;
3278       else
3279         ns_maybe_dumpglyphs_background
3280           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3282       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3283                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3284                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3285                       NS_DUMPGLYPH_NORMAL));
3286       ns_tmp_font = (struct nsfont_info *)s->face->font;
3287       if (ns_tmp_font == NULL)
3288           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3290       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3291         {
3292           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3293           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3294           NS_FACE_FOREGROUND (s->face) = tmp;
3295         }
3297       ns_tmp_font->font.driver->draw
3298         (s, 0, s->nchars, s->x, s->y,
3299          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3300          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3302       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3303         {
3304           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3305           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3306           NS_FACE_FOREGROUND (s->face) = tmp;
3307         }
3309       ns_unfocus (s->f);
3310       break;
3312     case GLYPHLESS_GLYPH:
3313       n = ns_get_glyph_string_clip_rect (s, r);
3314       ns_focus (s->f, r, n);
3316       if (s->for_overlaps || (s->cmp_from > 0
3317                               && ! s->first_glyph->u.cmp.automatic))
3318         s->background_filled_p = 1;
3319       else
3320         ns_maybe_dumpglyphs_background
3321           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3322       /* ... */
3323       /* Not yet implemented.  */
3324       /* ... */
3325       ns_unfocus (s->f);
3326       break;
3328     default:
3329       abort ();
3330     }
3332   /* Draw box if not done already. */
3333   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3334     {
3335       n = ns_get_glyph_string_clip_rect (s, r);
3336       ns_focus (s->f, r, n);
3337       ns_dumpglyphs_box_or_relief (s);
3338       ns_unfocus (s->f);
3339     }
3341   s->num_clips = 0;
3346 /* ==========================================================================
3348     Event loop
3350    ========================================================================== */
3353 static void
3354 ns_send_appdefined (int value)
3355 /* --------------------------------------------------------------------------
3356     Internal: post an appdefined event which EmacsApp-sendEvent will
3357               recognize and take as a command to halt the event loop.
3358    -------------------------------------------------------------------------- */
3360   /*NSTRACE (ns_send_appdefined); */
3362   /* Only post this event if we haven't already posted one.  This will end
3363        the [NXApp run] main loop after having processed all events queued at
3364        this moment.  */
3365   if (send_appdefined)
3366     {
3367       NSEvent *nxev;
3369       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3370       send_appdefined = NO;
3372       /* Don't need wakeup timer any more */
3373       if (timed_entry)
3374         {
3375           [timed_entry invalidate];
3376           [timed_entry release];
3377           timed_entry = nil;
3378         }
3380       /* Ditto for file descriptor poller */
3381       if (fd_entry)
3382         {
3383           [fd_entry invalidate];
3384           [fd_entry release];
3385           fd_entry = nil;
3386         }
3388       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3389                                 location: NSMakePoint (0, 0)
3390                            modifierFlags: 0
3391                                timestamp: 0
3392                             windowNumber: [[NSApp mainWindow] windowNumber]
3393                                  context: [NSApp context]
3394                                  subtype: 0
3395                                    data1: value
3396                                    data2: 0];
3398       /* Post an application defined event on the event queue.  When this is
3399          received the [NXApp run] will return, thus having processed all
3400          events which are currently queued.  */
3401       [NSApp postEvent: nxev atStart: NO];
3402     }
3406 static int
3407 ns_read_socket (struct terminal *terminal, int expected,
3408                 struct input_event *hold_quit)
3409 /* --------------------------------------------------------------------------
3410      External (hook): Post an event to ourself and keep reading events until
3411      we read it back again.  In effect process all events which were waiting.
3412      From 21+ we have to manage the event buffer ourselves.
3413    -------------------------------------------------------------------------- */
3415   struct input_event ev;
3416   int nevents;
3418 /* NSTRACE (ns_read_socket); */
3420   if ([NSApp modalWindow] != nil)
3421     return -1;
3423   if (interrupt_input_blocked)
3424     {
3425       interrupt_input_pending = 1;
3426 #ifdef SYNC_INPUT
3427       pending_signals = 1;
3428 #endif
3429       return -1;
3430     }
3432   interrupt_input_pending = 0;
3433 #ifdef SYNC_INPUT
3434   pending_signals = pending_atimers;
3435 #endif
3437   BLOCK_INPUT;
3438   n_emacs_events_pending = 0;
3439   EVENT_INIT (ev);
3440   emacs_event = &ev;
3441   q_event_ptr = hold_quit;
3443   /* we manage autorelease pools by allocate/reallocate each time around
3444      the loop; strict nesting is occasionally violated but seems not to
3445      matter.. earlier methods using full nesting caused major memory leaks */
3446   [outerpool release];
3447   outerpool = [[NSAutoreleasePool alloc] init];
3449   /* If have pending open-file requests, attend to the next one of those. */
3450   if (ns_pending_files && [ns_pending_files count] != 0
3451       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3452     {
3453       [ns_pending_files removeObjectAtIndex: 0];
3454     }
3455   /* Deal with pending service requests. */
3456   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3457     && [(EmacsApp *)
3458          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3459                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3460     {
3461       [ns_pending_service_names removeObjectAtIndex: 0];
3462       [ns_pending_service_args removeObjectAtIndex: 0];
3463     }
3464   else
3465     {
3466       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3467          to ourself, otherwise [NXApp run] will never exit.  */
3468       send_appdefined = YES;
3470       /* If called via ns_select, this is called once with expected=1,
3471          because we expect either the timeout or file descriptor activity.
3472          In this case the first event through will either be real input or
3473          one of these.  read_avail_input() then calls once more with expected=0
3474          and in that case we need to return quickly if there is nothing.
3475          If we're being called outside of that, it's also OK to return quickly
3476          after one iteration through the event loop, since other terms do
3477          this and emacs expects it. */
3478       if (!(inNsSelect && expected))
3479         {
3480           /* Post an application defined event on the event queue.  When this is
3481              received the [NXApp run] will return, thus having processed all
3482              events which are currently queued, if any.  */
3483           ns_send_appdefined (-1);
3484         }
3486       [NSApp run];
3487     }
3489   nevents = n_emacs_events_pending;
3490   n_emacs_events_pending = 0;
3491   emacs_event = q_event_ptr = NULL;
3492   UNBLOCK_INPUT;
3494   return nevents;
3499 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3500            fd_set *exceptfds, EMACS_TIME *timeout, sigset_t *sigmask)
3501 /* --------------------------------------------------------------------------
3502      Replacement for select, checking for events
3503    -------------------------------------------------------------------------- */
3505   int result;
3506   double time;
3507   NSEvent *ev;
3508   struct timespec select_timeout;
3510 /*  NSTRACE (ns_select); */
3512   if (NSApp == nil || inNsSelect == 1 /* || ([NSApp isActive] == NO &&
3513                       [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil
3514  inMode:NSDefaultRunLoopMode dequeue:NO] == nil) */)
3515     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3517   /* Save file descriptor set, which gets overwritten in calls to select ()
3518      Note, this is called from process.c, and only readfds is ever set */
3519   if (readfds)
3520     {
3521       memcpy (&select_readfds, readfds, sizeof (fd_set));
3522       select_nfds = nfds;
3523     }
3524   else
3525     select_nfds = 0;
3527     /* Try an initial select for pending data on input files */
3528   select_timeout.tv_sec = select_timeout.tv_nsec = 0;
3529   result = pselect (nfds, readfds, writefds, exceptfds,
3530                     &select_timeout, sigmask);
3531   if (result)
3532     return result;
3534   /* if (!timeout || timed_entry || fd_entry)
3535        fprintf (stderr, "assertion failed: timeout null or timed_entry/fd_entry non-null in ns_select\n"); */
3537     /* set a timeout and run the main AppKit event loop while continuing
3538        to monitor the files */
3539   time = EMACS_TIME_TO_DOUBLE (*timeout);
3540   timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3541                                            target: NSApp
3542                                          selector: @selector (timeout_handler:)
3543                                          userInfo: 0
3544                                           repeats: YES] /* for safe removal */
3545                                                          retain];
3547   /* set a periodic task to try the pselect () again */
3548   fd_entry = [[NSTimer scheduledTimerWithTimeInterval: 0.1
3549                                                target: NSApp
3550                                              selector: @selector (fd_handler:)
3551                                              userInfo: 0
3552                                               repeats: YES]
3553                retain];
3555   /* Let Application dispatch events until it receives an event of the type
3556      NX_APPDEFINED, which should only be sent by timeout_handler.
3557      We tell read_avail_input() that input is "expected" because we do expect
3558      either the timeout or fd handler to fire, and if they don't, the original
3559      call from process.c that got us here expects us to wait until some input
3560      comes. */
3561   inNsSelect = 1;
3562   gobble_input (1);
3563   ev = last_appdefined_event;
3564   inNsSelect = 0;
3566   if (ev)
3567     {
3568       int t;
3569       if ([ev type] != NSApplicationDefined)
3570         abort ();
3572       t = [ev data1];
3573       last_appdefined_event = 0;
3575       if (t == -2)
3576         {
3577           /* The NX_APPDEFINED event we received was a timeout. */
3578           return 0;
3579         }
3580       else if (t == -1)
3581         {
3582           /* The NX_APPDEFINED event we received was the result of
3583              at least one real input event arriving.  */
3584           errno = EINTR;
3585           return -1;
3586         }
3587       else
3588         {
3589           /* Received back from pselect () in fd_handler; copy the results */
3590           if (readfds)
3591             memcpy (readfds, &select_readfds, sizeof (fd_set));
3592           return t;
3593         }
3594     }
3595   /* never reached, shut compiler up */
3596   return 0;
3601 /* ==========================================================================
3603     Scrollbar handling
3605    ========================================================================== */
3608 static void
3609 ns_set_vertical_scroll_bar (struct window *window,
3610                            int portion, int whole, int position)
3611 /* --------------------------------------------------------------------------
3612       External (hook): Update or add scrollbar
3613    -------------------------------------------------------------------------- */
3615   Lisp_Object win;
3616   NSRect r, v;
3617   struct frame *f = XFRAME (WINDOW_FRAME (window));
3618   EmacsView *view = FRAME_NS_VIEW (f);
3619   int window_y, window_height;
3620   BOOL barOnVeryLeft, barOnVeryRight;
3621   int top, left, height, width, sb_width, sb_left;
3622   EmacsScroller *bar;
3624   /* optimization; display engine sends WAY too many of these.. */
3625   if (!NILP (window->vertical_scroll_bar))
3626     {
3627       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3628       if ([bar checkSamePosition: position portion: portion whole: whole])
3629         {
3630           if (view->scrollbarsNeedingUpdate == 0)
3631             {
3632               if (!windows_or_buffers_changed)
3633                   return;
3634             }
3635           else
3636             view->scrollbarsNeedingUpdate--;
3637         }
3638     }
3640   NSTRACE (ns_set_vertical_scroll_bar);
3642   /* Get dimensions.  */
3643   window_box (window, -1, 0, &window_y, 0, &window_height);
3644   top = window_y;
3645   height = window_height;
3646   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3647   left = WINDOW_SCROLL_BAR_AREA_X (window);
3649   if (top < 5) /* top scrollbar adjustment */
3650     {
3651       top -= FRAME_INTERNAL_BORDER_WIDTH (f);
3652       height += FRAME_INTERNAL_BORDER_WIDTH (f);
3653     }
3655   /* allow for displaying a skinnier scrollbar than char area allotted */
3656   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3657     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3659   barOnVeryLeft = left < 5;
3660   barOnVeryRight = FRAME_PIXEL_WIDTH (f) - left - width < 5;
3661   sb_left = left + FRAME_INTERNAL_BORDER_WIDTH (f)
3662       * (barOnVeryLeft ? -1 : (barOnVeryRight ? 1 : 0));
3664   r = NSMakeRect (sb_left, top, sb_width, height);
3665   /* the parent view is flipped, so we need to flip y value */
3666   v = [view frame];
3667   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3669   XSETWINDOW (win, window);
3670   BLOCK_INPUT;
3672   /* we want at least 5 lines to display a scrollbar */
3673   if (WINDOW_TOTAL_LINES (window) < 5)
3674     {
3675       if (!NILP (window->vertical_scroll_bar))
3676         {
3677           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3678           [bar removeFromSuperview];
3679           WSET (window, vertical_scroll_bar, Qnil);
3680         }
3681       ns_clear_frame_area (f, sb_left, top, width, height);
3682       UNBLOCK_INPUT;
3683       return;
3684     }
3686   if (NILP (window->vertical_scroll_bar))
3687     {
3688       ns_clear_frame_area (f, sb_left, top, width, height);
3689       bar = [[EmacsScroller alloc] initFrame: r window: win];
3690       WSET (window, vertical_scroll_bar, make_save_value (bar, 0));
3691     }
3692   else
3693     {
3694       NSRect oldRect;
3695       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3696       oldRect = [bar frame];
3697       r.size.width = oldRect.size.width;
3698       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3699         {
3700           if (oldRect.origin.x != r.origin.x)
3701               ns_clear_frame_area (f, sb_left, top, width, height);
3702           [bar setFrame: r];
3703         }
3704     }
3706   [bar setPosition: position portion: portion whole: whole];
3707   UNBLOCK_INPUT;
3711 static void
3712 ns_condemn_scroll_bars (struct frame *f)
3713 /* --------------------------------------------------------------------------
3714      External (hook): arrange for all frame's scrollbars to be removed
3715      at next call to judge_scroll_bars, except for those redeemed.
3716    -------------------------------------------------------------------------- */
3718   int i;
3719   id view;
3720   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3722   NSTRACE (ns_condemn_scroll_bars);
3724   for (i =[subviews count]-1; i >= 0; i--)
3725     {
3726       view = [subviews objectAtIndex: i];
3727       if ([view isKindOfClass: [EmacsScroller class]])
3728         [view condemn];
3729     }
3733 static void
3734 ns_redeem_scroll_bar (struct window *window)
3735 /* --------------------------------------------------------------------------
3736      External (hook): arrange to spare this window's scrollbar
3737      at next call to judge_scroll_bars.
3738    -------------------------------------------------------------------------- */
3740   id bar;
3741   NSTRACE (ns_redeem_scroll_bar);
3742   if (!NILP (window->vertical_scroll_bar))
3743     {
3744       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3745       [bar reprieve];
3746     }
3750 static void
3751 ns_judge_scroll_bars (struct frame *f)
3752 /* --------------------------------------------------------------------------
3753      External (hook): destroy all scrollbars on frame that weren't
3754      redeemed after call to condemn_scroll_bars.
3755    -------------------------------------------------------------------------- */
3757   int i;
3758   id view;
3759   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3760   NSTRACE (ns_judge_scroll_bars);
3761   for (i =[subviews count]-1; i >= 0; i--)
3762     {
3763       view = [subviews objectAtIndex: i];
3764       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3765       [view judge];
3766     }
3770 void
3771 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3773   /* XXX irrelevant under NS */
3778 /* ==========================================================================
3780     Initialization
3782    ========================================================================== */
3785 x_display_pixel_height (struct ns_display_info *dpyinfo)
3787   NSScreen *screen = [NSScreen mainScreen];
3788   return [screen frame].size.height;
3792 x_display_pixel_width (struct ns_display_info *dpyinfo)
3794   NSScreen *screen = [NSScreen mainScreen];
3795   return [screen frame].size.width;
3799 static Lisp_Object ns_string_to_lispmod (const char *s)
3800 /* --------------------------------------------------------------------------
3801      Convert modifier name to lisp symbol
3802    -------------------------------------------------------------------------- */
3804   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3805     return Qmeta;
3806   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3807     return Qsuper;
3808   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3809     return Qcontrol;
3810   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3811     return Qalt;
3812   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3813     return Qhyper;
3814   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3815     return Qnone;
3816   else
3817     return Qnil;
3821 static void
3822 ns_default (const char *parameter, Lisp_Object *result,
3823            Lisp_Object yesval, Lisp_Object noval,
3824            BOOL is_float, BOOL is_modstring)
3825 /* --------------------------------------------------------------------------
3826       Check a parameter value in user's preferences
3827    -------------------------------------------------------------------------- */
3829   const char *value = ns_get_defaults_value (parameter);
3831   if (value)
3832     {
3833       double f;
3834       char *pos;
3835       if (c_strcasecmp (value, "YES") == 0)
3836         *result = yesval;
3837       else if (c_strcasecmp (value, "NO") == 0)
3838         *result = noval;
3839       else if (is_float && (f = strtod (value, &pos), pos != value))
3840         *result = make_float (f);
3841       else if (is_modstring && value)
3842         *result = ns_string_to_lispmod (value);
3843       else fprintf (stderr,
3844                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3845     }
3849 static void
3850 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3851 /* --------------------------------------------------------------------------
3852       Initialize global info and storage for display.
3853    -------------------------------------------------------------------------- */
3855     NSScreen *screen = [NSScreen mainScreen];
3856     NSWindowDepth depth = [screen depth];
3857     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3859     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3860     dpyinfo->resy = 72.27;
3861     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3862                                                   NSColorSpaceFromDepth (depth)]
3863                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3864                                                  NSColorSpaceFromDepth (depth)];
3865     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3866     dpyinfo->image_cache = make_image_cache ();
3867     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
3868     dpyinfo->color_table->colors = NULL;
3869     dpyinfo->root_window = 42; /* a placeholder.. */
3871     hlinfo->mouse_face_mouse_frame = NULL;
3872     hlinfo->mouse_face_deferred_gc = 0;
3873     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3874     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3875     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3876     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3877     hlinfo->mouse_face_hidden = 0;
3879     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3880     hlinfo->mouse_face_defer = 0;
3882     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3884     dpyinfo->n_fonts = 0;
3885     dpyinfo->smallest_font_height = 1;
3886     dpyinfo->smallest_char_width = 1;
3890 /* This and next define (many of the) public functions in this file. */
3891 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3892          with using despite presence in the "system dependent" redisplay
3893          interface.  In addition, many of the ns_ methods have code that is
3894          shared with all terms, indicating need for further refactoring. */
3895 extern frame_parm_handler ns_frame_parm_handlers[];
3896 static struct redisplay_interface ns_redisplay_interface =
3898   ns_frame_parm_handlers,
3899   x_produce_glyphs,
3900   x_write_glyphs,
3901   x_insert_glyphs,
3902   x_clear_end_of_line,
3903   ns_scroll_run,
3904   ns_after_update_window_line,
3905   ns_update_window_begin,
3906   ns_update_window_end,
3907   x_cursor_to,
3908   ns_flush,
3909   0, /* flush_display_optional */
3910   x_clear_window_mouse_face,
3911   x_get_glyph_overhangs,
3912   x_fix_overlapping_area,
3913   ns_draw_fringe_bitmap,
3914   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3915   0, /* destroy_fringe_bitmap */
3916   ns_compute_glyph_string_overhangs,
3917   ns_draw_glyph_string, /* interface to nsfont.m */
3918   ns_define_frame_cursor,
3919   ns_clear_frame_area,
3920   ns_draw_window_cursor,
3921   ns_draw_vertical_window_border,
3922   ns_shift_glyphs_for_insert
3926 static void
3927 ns_delete_display (struct ns_display_info *dpyinfo)
3929   /* TODO... */
3933 /* This function is called when the last frame on a display is deleted. */
3934 static void
3935 ns_delete_terminal (struct terminal *terminal)
3937   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3939   /* Protect against recursive calls.  delete_frame in
3940      delete_terminal calls us back when it deletes our last frame.  */
3941   if (!terminal->name)
3942     return;
3944   BLOCK_INPUT;
3946   x_destroy_all_bitmaps (dpyinfo);
3947   ns_delete_display (dpyinfo);
3948   UNBLOCK_INPUT;
3952 static struct terminal *
3953 ns_create_terminal (struct ns_display_info *dpyinfo)
3954 /* --------------------------------------------------------------------------
3955       Set up use of NS before we make the first connection.
3956    -------------------------------------------------------------------------- */
3958   struct terminal *terminal;
3960   NSTRACE (ns_create_terminal);
3962   terminal = create_terminal ();
3964   terminal->type = output_ns;
3965   terminal->display_info.ns = dpyinfo;
3966   dpyinfo->terminal = terminal;
3968   terminal->rif = &ns_redisplay_interface;
3970   terminal->clear_frame_hook = ns_clear_frame;
3971   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3972   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3973   terminal->ring_bell_hook = ns_ring_bell;
3974   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3975   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3976   terminal->update_begin_hook = ns_update_begin;
3977   terminal->update_end_hook = ns_update_end;
3978   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
3979   terminal->read_socket_hook = ns_read_socket;
3980   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3981   terminal->mouse_position_hook = ns_mouse_position;
3982   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3983   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3985   terminal->fullscreen_hook = 0; /* see XTfullscreen_hook */
3987   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3988   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3989   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3990   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3992   terminal->delete_frame_hook = x_destroy_window;
3993   terminal->delete_terminal_hook = ns_delete_terminal;
3995   terminal->scroll_region_ok = 1;
3996   terminal->char_ins_del_ok = 1;
3997   terminal->line_ins_del_ok = 1;
3998   terminal->fast_clear_end_of_line = 1;
3999   terminal->memory_below_frame = 0;
4001   return terminal;
4005 struct ns_display_info *
4006 ns_term_init (Lisp_Object display_name)
4007 /* --------------------------------------------------------------------------
4008      Start the Application and get things rolling.
4009    -------------------------------------------------------------------------- */
4011   struct terminal *terminal;
4012   struct ns_display_info *dpyinfo;
4013   static int ns_initialized = 0;
4014   Lisp_Object tmp;
4016   NSTRACE (ns_term_init);
4018   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4019   /*GSDebugAllocationActive (YES); */
4020   BLOCK_INPUT;
4021   handling_signal = 0;
4023   if (!ns_initialized)
4024     {
4025       baud_rate = 38400;
4026       Fset_input_interrupt_mode (Qnil);
4027       ns_initialized = 1;
4028     }
4030   ns_pending_files = [[NSMutableArray alloc] init];
4031   ns_pending_service_names = [[NSMutableArray alloc] init];
4032   ns_pending_service_args = [[NSMutableArray alloc] init];
4034 /* Start app and create the main menu, window, view.
4035      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4036      The view will then ask the NSApp to stop and return to Emacs. */
4037   [EmacsApp sharedApplication];
4038   if (NSApp == nil)
4039     return NULL;
4040   [NSApp setDelegate: NSApp];
4042   /* debugging: log all notifications */
4043   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4044                                          selector: @selector (logNotification:)
4045                                              name: nil object: nil]; */
4047   dpyinfo = xzalloc (sizeof *dpyinfo);
4049   ns_initialize_display_info (dpyinfo);
4050   terminal = ns_create_terminal (dpyinfo);
4052   terminal->kboard = xmalloc (sizeof *terminal->kboard);
4053   init_kboard (terminal->kboard);
4054   KSET (terminal->kboard, Vwindow_system, Qns);
4055   terminal->kboard->next_kboard = all_kboards;
4056   all_kboards = terminal->kboard;
4057   /* Don't let the initial kboard remain current longer than necessary.
4058      That would cause problems if a file loaded on startup tries to
4059      prompt in the mini-buffer.  */
4060   if (current_kboard == initial_kboard)
4061     current_kboard = terminal->kboard;
4062   terminal->kboard->reference_count++;
4064   dpyinfo->next = x_display_list;
4065   x_display_list = dpyinfo;
4067   /* Put it on ns_display_name_list */
4068   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4069                                 ns_display_name_list);
4070   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4072   terminal->name = xstrdup (SSDATA (display_name));
4074   UNBLOCK_INPUT;
4076   if (!inhibit_x_resources)
4077     {
4078       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4079                  Qt, Qnil, NO, NO);
4080       tmp = Qnil;
4081       /* this is a standard variable */
4082       ns_default ("AppleAntiAliasingThreshold", &tmp,
4083                  make_float (10.0), make_float (6.0), YES, NO);
4084       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4085     }
4087   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4088                          stringForKey: @"AppleHighlightColor"];
4089   if (ns_selection_color == nil)
4090     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4092   {
4093     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4095     if ( cl == nil )
4096       {
4097         Lisp_Object color_file, color_map, color;
4098         unsigned long c;
4099         char *name;
4101         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4102                          Fsymbol_value (intern ("data-directory")));
4103         if (NILP (Ffile_readable_p (color_file)))
4104           fatal ("Could not find %s.\n", SDATA (color_file));
4106         color_map = Fx_load_color_file (color_file);
4107         if (NILP (color_map))
4108           fatal ("Could not read %s.\n", SDATA (color_file));
4110         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4111         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4112           {
4113             color = XCAR (color_map);
4114             name = SSDATA (XCAR (color));
4115             c = XINT (XCDR (color));
4116             [cl setColor:
4117                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4118                                             green: GREEN_FROM_ULONG (c) / 255.0
4119                                              blue: BLUE_FROM_ULONG (c) / 255.0
4120                                             alpha: 1.0]
4121                   forKey: [NSString stringWithUTF8String: name]];
4122           }
4123         [cl writeToFile: nil];
4124       }
4125   }
4127   {
4128 #ifdef NS_IMPL_GNUSTEP
4129     Vwindow_system_version = build_string (gnustep_base_version);
4130 #else
4131     /*PSnextrelease (128, c); */
4132     char c[DBL_BUFSIZE_BOUND];
4133     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4134     Vwindow_system_version = make_unibyte_string (c, len);
4135 #endif
4136   }
4138   delete_keyboard_wait_descriptor (0);
4140   ns_app_name = [[NSProcessInfo processInfo] processName];
4142 /* Set up OS X app menu */
4143 #ifdef NS_IMPL_COCOA
4144   {
4145     NSMenu *appMenu;
4146     NSMenuItem *item;
4147     /* set up the application menu */
4148     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4149     [svcsMenu setAutoenablesItems: NO];
4150     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4151     [appMenu setAutoenablesItems: NO];
4152     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4153     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4155     [appMenu insertItemWithTitle: @"About Emacs"
4156                           action: @selector (orderFrontStandardAboutPanel:)
4157                    keyEquivalent: @""
4158                          atIndex: 0];
4159     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4160     [appMenu insertItemWithTitle: @"Preferences..."
4161                           action: @selector (showPreferencesWindow:)
4162                    keyEquivalent: @","
4163                          atIndex: 2];
4164     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4165     item = [appMenu insertItemWithTitle: @"Services"
4166                                  action: @selector (menuDown:)
4167                           keyEquivalent: @""
4168                                 atIndex: 4];
4169     [appMenu setSubmenu: svcsMenu forItem: item];
4170     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4171     [appMenu insertItemWithTitle: @"Hide Emacs"
4172                           action: @selector (hide:)
4173                    keyEquivalent: @"h"
4174                          atIndex: 6];
4175     item =  [appMenu insertItemWithTitle: @"Hide Others"
4176                           action: @selector (hideOtherApplications:)
4177                    keyEquivalent: @"h"
4178                          atIndex: 7];
4179     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4180     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4181     [appMenu insertItemWithTitle: @"Quit Emacs"
4182                           action: @selector (terminate:)
4183                    keyEquivalent: @"q"
4184                          atIndex: 9];
4186     item = [mainMenu insertItemWithTitle: ns_app_name
4187                                   action: @selector (menuDown:)
4188                            keyEquivalent: @""
4189                                  atIndex: 0];
4190     [mainMenu setSubmenu: appMenu forItem: item];
4191     [dockMenu insertItemWithTitle: @"New Frame"
4192                            action: @selector (newFrame:)
4193                     keyEquivalent: @""
4194                           atIndex: 0];
4196     [NSApp setMainMenu: mainMenu];
4197     [NSApp setAppleMenu: appMenu];
4198     [NSApp setServicesMenu: svcsMenu];
4199     /* Needed at least on Cocoa, to get dock menu to show windows */
4200     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4202     [[NSNotificationCenter defaultCenter]
4203       addObserver: mainMenu
4204          selector: @selector (trackingNotification:)
4205              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4206     [[NSNotificationCenter defaultCenter]
4207       addObserver: mainMenu
4208          selector: @selector (trackingNotification:)
4209              name: NSMenuDidEndTrackingNotification object: mainMenu];
4210   }
4211 #endif /* MAC OS X menu setup */
4213   [NSApp run];
4214   ns_do_open_file = YES;
4215   return dpyinfo;
4219 void
4220 ns_term_shutdown (int sig)
4222   [[NSUserDefaults standardUserDefaults] synchronize];
4224   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4225   if (STRINGP (Vauto_save_list_file_name))
4226     unlink (SSDATA (Vauto_save_list_file_name));
4228   if (sig == 0 || sig == SIGTERM)
4229     {
4230       [NSApp terminate: NSApp];
4231     }
4232   else // force a stack trace to happen
4233     {
4234       abort();
4235     }
4239 /* ==========================================================================
4241     EmacsApp implementation
4243    ========================================================================== */
4246 @implementation EmacsApp
4248 - (void)logNotification: (NSNotification *)notification
4250   const char *name = [[notification name] UTF8String];
4251   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4252       && !strstr (name, "WindowNumber"))
4253     NSLog (@"notification: '%@'", [notification name]);
4257 - (void)sendEvent: (NSEvent *)theEvent
4258 /* --------------------------------------------------------------------------
4259      Called when NSApp is running for each event received.  Used to stop
4260      the loop when we choose, since there's no way to just run one iteration.
4261    -------------------------------------------------------------------------- */
4263   int type = [theEvent type];
4264   NSWindow *window = [theEvent window];
4265 /*  NSTRACE (sendEvent); */
4266 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4268 #ifdef NS_IMPL_COCOA
4269   if (type == NSApplicationDefined
4270       && [theEvent data2] == NSAPP_DATA2_RUNASSCRIPT)
4271     {
4272       ns_run_ascript ();
4273       [self stop: self];
4274       return;
4275     }
4276 #endif
4278   if (type == NSCursorUpdate && window == nil)
4279     {
4280       fprintf (stderr, "Dropping external cursor update event.\n");
4281       return;
4282     }
4284 #ifdef NS_IMPL_COCOA
4285   /* pass mouse down in resize handle and subsequent drags directly to
4286      EmacsWindow so we can generate continuous redisplays */
4287   if (ns_in_resize)
4288     {
4289       if (type == NSLeftMouseDragged)
4290         {
4291           [window mouseDragged: theEvent];
4292           return;
4293         }
4294       else if (type == NSLeftMouseUp)
4295         {
4296           [window mouseUp: theEvent];
4297           return;
4298         }
4299     }
4300   else if (type == NSLeftMouseDown)
4301     {
4302       NSRect r = ns_resize_handle_rect (window);
4303       if (NSPointInRect ([theEvent locationInWindow], r))
4304         {
4305           ns_in_resize = YES;
4306           [window mouseDown: theEvent];
4307           return;
4308         }
4309     }
4310 #endif
4312   if (type == NSApplicationDefined)
4313     {
4314       /* Events posted by ns_send_appdefined interrupt the run loop here.
4315          But, if a modal window is up, an appdefined can still come through,
4316          (e.g., from a makeKeyWindow event) but stopping self also stops the
4317          modal loop. Just defer it until later. */
4318       if ([NSApp modalWindow] == nil)
4319         {
4320           last_appdefined_event = theEvent;
4321           [self stop: self];
4322         }
4323       else
4324         {
4325           send_appdefined = YES;
4326         }
4327     }
4329   [super sendEvent: theEvent];
4333 - (void)showPreferencesWindow: (id)sender
4335   struct frame *emacsframe = SELECTED_FRAME ();
4336   NSEvent *theEvent = [NSApp currentEvent];
4338   if (!emacs_event)
4339     return;
4340   emacs_event->kind = NS_NONKEY_EVENT;
4341   emacs_event->code = KEY_NS_SHOW_PREFS;
4342   emacs_event->modifiers = 0;
4343   EV_TRAILER (theEvent);
4347 - (void)newFrame: (id)sender
4349   struct frame *emacsframe = SELECTED_FRAME ();
4350   NSEvent *theEvent = [NSApp currentEvent];
4352   if (!emacs_event)
4353     return;
4354   emacs_event->kind = NS_NONKEY_EVENT;
4355   emacs_event->code = KEY_NS_NEW_FRAME;
4356   emacs_event->modifiers = 0;
4357   EV_TRAILER (theEvent);
4361 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4362 - (BOOL) openFile: (NSString *)fileName
4364   struct frame *emacsframe = SELECTED_FRAME ();
4365   NSEvent *theEvent = [NSApp currentEvent];
4367   if (!emacs_event)
4368     return NO;
4370   emacs_event->kind = NS_NONKEY_EVENT;
4371   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4372   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4373   ns_input_line = Qnil; /* can be start or cons start,end */
4374   emacs_event->modifiers =0;
4375   EV_TRAILER (theEvent);
4377   return YES;
4381 /* **************************************************************************
4383       EmacsApp delegate implementation
4385    ************************************************************************** */
4387 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4388 /* --------------------------------------------------------------------------
4389      When application is loaded, terminate event loop in ns_term_init
4390    -------------------------------------------------------------------------- */
4392   NSTRACE (applicationDidFinishLaunching);
4393   [NSApp setServicesProvider: NSApp];
4394   ns_send_appdefined (-2);
4398 /* Termination sequences:
4399     C-x C-c:
4400     Cmd-Q:
4401     MenuBar | File | Exit:
4402     Select Quit from App menubar:
4403         -terminate
4404         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4405         ns_term_shutdown()
4407     Select Quit from Dock menu:
4408     Logout attempt:
4409         -appShouldTerminate
4410           Cancel -> Nothing else
4411           Accept ->
4413           -terminate
4414           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4415           ns_term_shutdown()
4419 - (void) terminate: (id)sender
4421   struct frame *emacsframe = SELECTED_FRAME ();
4423   if (!emacs_event)
4424     return;
4426   emacs_event->kind = NS_NONKEY_EVENT;
4427   emacs_event->code = KEY_NS_POWER_OFF;
4428   emacs_event->arg = Qt; /* mark as non-key event */
4429   EV_TRAILER ((id)nil);
4433 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4435   int ret;
4437   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4438     return NSTerminateNow;
4440     ret = NSRunAlertPanel(ns_app_name,
4441                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4442                           @"Save Buffers and Exit", @"Cancel", nil);
4444     if (ret == NSAlertDefaultReturn)
4445         return NSTerminateNow;
4446     else if (ret == NSAlertAlternateReturn)
4447         return NSTerminateCancel;
4448     return NSTerminateNow;  /* just in case */
4451 static int
4452 not_in_argv (NSString *arg)
4454   int k;
4455   const char *a = [arg UTF8String];
4456   for (k = 1; k < initial_argc; ++k)
4457     if (strcmp (a, initial_argv[k]) == 0) return 0;
4458   return 1;
4461 /*   Notification from the Workspace to open a file */
4462 - (BOOL)application: sender openFile: (NSString *)file
4464   if (ns_do_open_file || not_in_argv (file))
4465     [ns_pending_files addObject: file];
4466   return YES;
4470 /*   Open a file as a temporary file */
4471 - (BOOL)application: sender openTempFile: (NSString *)file
4473   if (ns_do_open_file || not_in_argv (file))
4474     [ns_pending_files addObject: file];
4475   return YES;
4479 /*   Notification from the Workspace to open a file noninteractively (?) */
4480 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4482   if (ns_do_open_file || not_in_argv (file))
4483     [ns_pending_files addObject: file];
4484   return YES;
4487 /*   Notification from the Workspace to open multiple files */
4488 - (void)application: sender openFiles: (NSArray *)fileList
4490   NSEnumerator *files = [fileList objectEnumerator];
4491   NSString *file;
4492   /* Don't open files from the command line unconditionally,
4493      Cocoa parses the command line wrong, --option value tries to open value
4494      if --option is the last option.  */
4495   while ((file = [files nextObject]) != nil) 
4496     if (ns_do_open_file || not_in_argv (file))
4497       [ns_pending_files addObject: file];
4498   
4499   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4504 /* Handle dock menu requests.  */
4505 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4507   return dockMenu;
4511 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4512 - (void)applicationWillBecomeActive: (NSNotification *)notification
4514   //ns_app_active=YES;
4516 - (void)applicationDidBecomeActive: (NSNotification *)notification
4518   NSTRACE (applicationDidBecomeActive);
4520   //ns_app_active=YES;
4522   ns_update_auto_hide_menu_bar ();
4523   // No constraining takes place when the application is not active.
4524   ns_constrain_all_frames ();
4526 - (void)applicationDidResignActive: (NSNotification *)notification
4528   //ns_app_active=NO;
4529   ns_send_appdefined (-1);
4534 /* ==========================================================================
4536     EmacsApp aux handlers for managing event loop
4538    ========================================================================== */
4541 - (void)timeout_handler: (NSTimer *)timedEntry
4542 /* --------------------------------------------------------------------------
4543      The timeout specified to ns_select has passed.
4544    -------------------------------------------------------------------------- */
4546   /*NSTRACE (timeout_handler); */
4547   ns_send_appdefined (-2);
4550 - (void)fd_handler: (NSTimer *) fdEntry
4551 /* --------------------------------------------------------------------------
4552      Check data waiting on file descriptors and terminate if so
4553    -------------------------------------------------------------------------- */
4555   int result;
4556   struct timespec select_timeout;
4557   /* NSTRACE (fd_handler); */
4559   if (select_nfds == 0)
4560     return;
4562   memcpy (&t_readfds, &select_readfds, sizeof (fd_set));
4564   select_timeout.tv_sec = select_timeout.tv_nsec = 0;
4565   result = pselect (select_nfds, &t_readfds, NULL, NULL, &select_timeout, NULL);
4566   if (result)
4567     {
4568       memcpy (&select_readfds, &t_readfds, sizeof (fd_set));
4569       ns_send_appdefined (result);
4570     }
4575 /* ==========================================================================
4577     Service provision
4579    ========================================================================== */
4581 /* called from system: queue for next pass through event loop */
4582 - (void)requestService: (NSPasteboard *)pboard
4583               userData: (NSString *)userData
4584                  error: (NSString **)error
4586   [ns_pending_service_names addObject: userData];
4587   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4588       SSDATA (ns_string_from_pasteboard (pboard))]];
4592 /* called from ns_read_socket to clear queue */
4593 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4595   struct frame *emacsframe = SELECTED_FRAME ();
4596   NSEvent *theEvent = [NSApp currentEvent];
4598   if (!emacs_event)
4599     return NO;
4601   emacs_event->kind = NS_NONKEY_EVENT;
4602   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4603   ns_input_spi_name = build_string ([name UTF8String]);
4604   ns_input_spi_arg = build_string ([arg UTF8String]);
4605   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4606   EV_TRAILER (theEvent);
4608   return YES;
4612 @end  /* EmacsApp */
4616 /* ==========================================================================
4618     EmacsView implementation
4620    ========================================================================== */
4623 @implementation EmacsView
4625 /* needed to inform when window closed from LISP */
4626 - (void) setWindowClosing: (BOOL)closing
4628   windowClosing = closing;
4632 - (void)dealloc
4634   NSTRACE (EmacsView_dealloc);
4635   [toolbar release];
4636   [super dealloc];
4640 /* called on font panel selection */
4641 - (void)changeFont: (id)sender
4643   NSEvent *e =[[self window] currentEvent];
4644   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4645   id newFont;
4646   float size;
4648   NSTRACE (changeFont);
4649   if (!emacs_event)
4650     return;
4652   if ((newFont = [sender convertFont:
4653                            ((struct nsfont_info *)face->font)->nsfont]))
4654     {
4655       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4657       emacs_event->kind = NS_NONKEY_EVENT;
4658       emacs_event->modifiers = 0;
4659       emacs_event->code = KEY_NS_CHANGE_FONT;
4661       size = [newFont pointSize];
4662       ns_input_fontsize = make_number (lrint (size));
4663       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4664       EV_TRAILER (e);
4665     }
4669 - (BOOL)acceptsFirstResponder
4671   NSTRACE (acceptsFirstResponder);
4672   return YES;
4676 - (void)resetCursorRects
4678   NSRect visible = [self visibleRect];
4679   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4680   NSTRACE (resetCursorRects);
4682   if (currentCursor == nil)
4683     currentCursor = [NSCursor arrowCursor];
4685   if (!NSIsEmptyRect (visible))
4686     [self addCursorRect: visible cursor: currentCursor];
4687   [currentCursor setOnMouseEntered: YES];
4692 /*****************************************************************************/
4693 /* Keyboard handling. */
4694 #define NS_KEYLOG 0
4696 - (void)keyDown: (NSEvent *)theEvent
4698   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4699   int code;
4700   unsigned fnKeysym = 0;
4701   int flags;
4702   static NSMutableArray *nsEvArray;
4703 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4704   static BOOL firstTime = YES;
4705 #endif
4706   int left_is_none;
4708   NSTRACE (keyDown);
4710   /* Rhapsody and OS X give up and down events for the arrow keys */
4711   if (ns_fake_keydown == YES)
4712     ns_fake_keydown = NO;
4713   else if ([theEvent type] != NSKeyDown)
4714     return;
4716   if (!emacs_event)
4717     return;
4719  if (![[self window] isKeyWindow]
4720      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4721      /* we must avoid an infinite loop here. */
4722      && (EmacsView *)[[theEvent window] delegate] != self)
4723    {
4724      /* XXX: There is an occasional condition in which, when Emacs display
4725          updates a different frame from the current one, and temporarily
4726          selects it, then processes some interrupt-driven input
4727          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4728          for some reason that window has its first responder set to the NSView
4729          most recently updated (I guess), which is not the correct one. */
4730      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4731      return;
4732    }
4734   if (nsEvArray == nil)
4735     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4737   [NSCursor setHiddenUntilMouseMoves: YES];
4739   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4740     {
4741       clear_mouse_face (hlinfo);
4742       hlinfo->mouse_face_hidden = 1;
4743     }
4745   if (!processingCompose)
4746     {
4747       /* When using screen sharing, no left or right information is sent,
4748          so use Left key in those cases.  */
4749       int is_left_key, is_right_key;
4751       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4752         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4754       /* (Carbon way: [theEvent keyCode]) */
4756       /* is it a "function key"? */
4757       fnKeysym = ns_convert_key (code);
4758       if (fnKeysym)
4759         {
4760           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4761              because Emacs treats Delete and KP-Delete same (in simple.el). */
4762           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4763             code = 0xFF08; /* backspace */
4764           else
4765             code = fnKeysym;
4766         }
4768       /* are there modifiers? */
4769       emacs_event->modifiers = 0;
4770       flags = [theEvent modifierFlags];
4772       if (flags & NSHelpKeyMask)
4773           emacs_event->modifiers |= hyper_modifier;
4775       if (flags & NSShiftKeyMask)
4776         emacs_event->modifiers |= shift_modifier;
4778       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
4779       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
4780         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
4781       
4782       if (is_right_key)
4783         emacs_event->modifiers |= parse_solitary_modifier
4784           (EQ (ns_right_command_modifier, Qleft)
4785            ? ns_command_modifier
4786            : ns_right_command_modifier);
4788       if (is_left_key)
4789         {
4790           emacs_event->modifiers |= parse_solitary_modifier
4791             (ns_command_modifier);
4793           /* if super (default), take input manager's word so things like
4794              dvorak / qwerty layout work */
4795           if (EQ (ns_command_modifier, Qsuper)
4796               && !fnKeysym
4797               && [[theEvent characters] length] != 0)
4798             {
4799               /* XXX: the code we get will be unshifted, so if we have
4800                  a shift modifier, must convert ourselves */
4801               if (!(flags & NSShiftKeyMask))
4802                 code = [[theEvent characters] characterAtIndex: 0];
4803 #if 0
4804               /* this is ugly and also requires linking w/Carbon framework
4805                  (for LMGetKbdType) so for now leave this rare (?) case
4806                  undealt with.. in future look into CGEvent methods */
4807               else
4808                 {
4809                   long smv = GetScriptManagerVariable (smKeyScript);
4810                   Handle uchrHandle = GetResource
4811                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4812                   UInt32 dummy = 0;
4813                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4814                                  [[theEvent characters] characterAtIndex: 0],
4815                                  kUCKeyActionDisplay,
4816                                  (flags & ~NSCommandKeyMask) >> 8,
4817                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4818                                  &dummy, 1, &dummy, &code);
4819                   code &= 0xFF;
4820                 }
4821 #endif
4822             }
4823         }
4825       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
4826       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
4827         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
4829       if (is_right_key)
4830           emacs_event->modifiers |= parse_solitary_modifier
4831               (EQ (ns_right_control_modifier, Qleft)
4832                ? ns_control_modifier
4833                : ns_right_control_modifier);
4835       if (is_left_key)
4836         emacs_event->modifiers |= parse_solitary_modifier
4837           (ns_control_modifier);
4839       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4840           emacs_event->modifiers |=
4841             parse_solitary_modifier (ns_function_modifier);
4843       left_is_none = NILP (ns_alternate_modifier)
4844         || EQ (ns_alternate_modifier, Qnone);
4846       is_right_key = (flags & NSRightAlternateKeyMask)
4847         == NSRightAlternateKeyMask;
4848       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
4849         || (! is_right_key
4850             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
4852       if (is_right_key)
4853         {
4854           if ((NILP (ns_right_alternate_modifier)
4855                || EQ (ns_right_alternate_modifier, Qnone)
4856                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4857               && !fnKeysym)
4858             {   /* accept pre-interp alt comb */
4859               if ([[theEvent characters] length] > 0)
4860                 code = [[theEvent characters] characterAtIndex: 0];
4861               /*HACK: clear lone shift modifier to stop next if from firing */
4862               if (emacs_event->modifiers == shift_modifier)
4863                 emacs_event->modifiers = 0;
4864             }
4865           else
4866             emacs_event->modifiers |= parse_solitary_modifier
4867               (EQ (ns_right_alternate_modifier, Qleft)
4868                ? ns_alternate_modifier
4869                : ns_right_alternate_modifier);
4870         }
4872       if (is_left_key) /* default = meta */
4873         {
4874           if (left_is_none && !fnKeysym)
4875             {   /* accept pre-interp alt comb */
4876               if ([[theEvent characters] length] > 0)
4877                 code = [[theEvent characters] characterAtIndex: 0];
4878               /*HACK: clear lone shift modifier to stop next if from firing */
4879               if (emacs_event->modifiers == shift_modifier)
4880                 emacs_event->modifiers = 0;
4881             }
4882           else
4883               emacs_event->modifiers |=
4884                 parse_solitary_modifier (ns_alternate_modifier);
4885         }
4887   if (NS_KEYLOG)
4888     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4889              code, fnKeysym, flags, emacs_event->modifiers);
4891       /* if it was a function key or had modifiers, pass it directly to emacs */
4892       if (fnKeysym || (emacs_event->modifiers
4893                        && (emacs_event->modifiers != shift_modifier)
4894                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4895 /*[[theEvent characters] length] */
4896         {
4897           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4898           if (code < 0x20)
4899             code |= (1<<28)|(3<<16);
4900           else if (code == 0x7f)
4901             code |= (1<<28)|(3<<16);
4902           else if (!fnKeysym)
4903             emacs_event->kind = code > 0xFF
4904               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4906           emacs_event->code = code;
4907           EV_TRAILER (theEvent);
4908           return;
4909         }
4910     }
4913 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4914   /* if we get here we should send the key for input manager processing */
4915   if (firstTime && [[NSInputManager currentInputManager]
4916                      wantsToDelayTextChangeNotifications] == NO)
4917     fprintf (stderr,
4918           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4919   firstTime = NO;
4920 #endif
4921   if (NS_KEYLOG && !processingCompose)
4922     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4924   processingCompose = YES;
4925   [nsEvArray addObject: theEvent];
4926   [self interpretKeyEvents: nsEvArray];
4927   [nsEvArray removeObject: theEvent];
4931 #ifdef NS_IMPL_COCOA
4932 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4933    decided not to send key-down for.
4934    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4935    This only applies on Tiger and earlier.
4936    If it matches one of these, send it on to keyDown. */
4937 -(void)keyUp: (NSEvent *)theEvent
4939   int flags = [theEvent modifierFlags];
4940   int code = [theEvent keyCode];
4941   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
4942       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4943     {
4944       if (NS_KEYLOG)
4945         fprintf (stderr, "keyUp: passed test");
4946       ns_fake_keydown = YES;
4947       [self keyDown: theEvent];
4948     }
4950 #endif
4953 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
4956 /* <NSTextInput>: called when done composing;
4957    NOTE: also called when we delete over working text, followed immed.
4958          by doCommandBySelector: deleteBackward: */
4959 - (void)insertText: (id)aString
4961   int code;
4962   int len = [(NSString *)aString length];
4963   int i;
4965   if (NS_KEYLOG)
4966     NSLog (@"insertText '%@'\tlen = %d", aString, len);
4967   processingCompose = NO;
4969   if (!emacs_event)
4970     return;
4972   /* first, clear any working text */
4973   if (workingText != nil)
4974     [self deleteWorkingText];
4976   /* now insert the string as keystrokes */
4977   for (i =0; i<len; i++)
4978     {
4979       code = [aString characterAtIndex: i];
4980       /* TODO: still need this? */
4981       if (code == 0x2DC)
4982         code = '~'; /* 0x7E */
4983       emacs_event->modifiers = 0;
4984       emacs_event->kind
4985         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4986       emacs_event->code = code;
4987       EV_TRAILER ((id)nil);
4988     }
4992 /* <NSTextInput>: inserts display of composing characters */
4993 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
4995   NSString *str = [aString respondsToSelector: @selector (string)] ?
4996     [aString string] : aString;
4997   if (NS_KEYLOG)
4998     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
4999            selRange.length, selRange.location);
5001   if (workingText != nil)
5002     [self deleteWorkingText];
5003   if ([str length] == 0)
5004     return;
5006   if (!emacs_event)
5007     return;
5009   processingCompose = YES;
5010   workingText = [str copy];
5011   ns_working_text = build_string ([workingText UTF8String]);
5013   emacs_event->kind = NS_TEXT_EVENT;
5014   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5015   EV_TRAILER ((id)nil);
5019 /* delete display of composing characters [not in <NSTextInput>] */
5020 - (void)deleteWorkingText
5022   if (workingText == nil)
5023     return;
5024   if (NS_KEYLOG)
5025     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
5026   [workingText release];
5027   workingText = nil;
5028   processingCompose = NO;
5030   if (!emacs_event)
5031     return;
5033   emacs_event->kind = NS_TEXT_EVENT;
5034   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5035   EV_TRAILER ((id)nil);
5039 - (BOOL)hasMarkedText
5041   return workingText != nil;
5045 - (NSRange)markedRange
5047   NSRange rng = workingText != nil
5048     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5049   if (NS_KEYLOG)
5050     NSLog (@"markedRange request");
5051   return rng;
5055 - (void)unmarkText
5057   if (NS_KEYLOG)
5058     NSLog (@"unmark (accept) text");
5059   [self deleteWorkingText];
5060   processingCompose = NO;
5064 /* used to position char selection windows, etc. */
5065 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5067   NSRect rect;
5068   NSPoint pt;
5069   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5070   if (NS_KEYLOG)
5071     NSLog (@"firstRectForCharRange request");
5073   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5074   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5075   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5076   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5077                                        +FRAME_LINE_HEIGHT (emacsframe));
5079   pt = [self convertPoint: pt toView: nil];
5080   pt = [[self window] convertBaseToScreen: pt];
5081   rect.origin = pt;
5082   return rect;
5086 - (NSInteger)conversationIdentifier
5088   return (NSInteger)self;
5092 - (void)doCommandBySelector: (SEL)aSelector
5094   if (NS_KEYLOG)
5095     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5097   if (aSelector == @selector (deleteBackward:))
5098     {
5099       /* happens when user backspaces over an ongoing composition:
5100          throw a 'delete' into the event queue */
5101       if (!emacs_event)
5102         return;
5103       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5104       emacs_event->code = 0xFF08;
5105       EV_TRAILER ((id)nil);
5106     }
5109 - (NSArray *)validAttributesForMarkedText
5111   static NSArray *arr = nil;
5112   if (arr == nil) arr = [NSArray new];
5113  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5114   return arr;
5117 - (NSRange)selectedRange
5119   if (NS_KEYLOG)
5120     NSLog (@"selectedRange request");
5121   return NSMakeRange (NSNotFound, 0);
5124 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5126   if (NS_KEYLOG)
5127     NSLog (@"characterIndexForPoint request");
5128   return 0;
5131 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5133   static NSAttributedString *str = nil;
5134   if (str == nil) str = [NSAttributedString new];
5135   if (NS_KEYLOG)
5136     NSLog (@"attributedSubstringFromRange request");
5137   return str;
5140 /* End <NSTextInput> impl. */
5141 /*****************************************************************************/
5144 /* This is what happens when the user presses a mouse button.  */
5145 - (void)mouseDown: (NSEvent *)theEvent
5147   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5149   NSTRACE (mouseDown);
5151   [self deleteWorkingText];
5153   if (!emacs_event)
5154     return;
5156   last_mouse_frame = emacsframe;
5157   /* appears to be needed to prevent spurious movement events generated on
5158      button clicks */
5159   last_mouse_frame->mouse_moved = 0;
5161   if ([theEvent type] == NSScrollWheel)
5162     {
5163       float delta = [theEvent deltaY];
5164       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5165       if (delta == 0)
5166         return;
5167       emacs_event->kind = WHEEL_EVENT;
5168       emacs_event->code = 0;
5169       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5170         ((delta > 0) ? up_modifier : down_modifier);
5171     }
5172   else
5173     {
5174       emacs_event->kind = MOUSE_CLICK_EVENT;
5175       emacs_event->code = EV_BUTTON (theEvent);
5176       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5177                              | EV_UDMODIFIERS (theEvent);
5178     }
5179   XSETINT (emacs_event->x, lrint (p.x));
5180   XSETINT (emacs_event->y, lrint (p.y));
5181   EV_TRAILER (theEvent);
5185 - (void)rightMouseDown: (NSEvent *)theEvent
5187   NSTRACE (rightMouseDown);
5188   [self mouseDown: theEvent];
5192 - (void)otherMouseDown: (NSEvent *)theEvent
5194   NSTRACE (otherMouseDown);
5195   [self mouseDown: theEvent];
5199 - (void)mouseUp: (NSEvent *)theEvent
5201   NSTRACE (mouseUp);
5202   [self mouseDown: theEvent];
5206 - (void)rightMouseUp: (NSEvent *)theEvent
5208   NSTRACE (rightMouseUp);
5209   [self mouseDown: theEvent];
5213 - (void)otherMouseUp: (NSEvent *)theEvent
5215   NSTRACE (otherMouseUp);
5216   [self mouseDown: theEvent];
5220 - (void) scrollWheel: (NSEvent *)theEvent
5222   NSTRACE (scrollWheel);
5223   [self mouseDown: theEvent];
5227 /* Tell emacs the mouse has moved. */
5228 - (void)mouseMoved: (NSEvent *)e
5230   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5231   Lisp_Object frame;
5233 //  NSTRACE (mouseMoved);
5235   last_mouse_movement_time = EV_TIMESTAMP (e);
5236   last_mouse_motion_position
5237     = [self convertPoint: [e locationInWindow] fromView: nil];
5239   /* update any mouse face */
5240   if (hlinfo->mouse_face_hidden)
5241     {
5242       hlinfo->mouse_face_hidden = 0;
5243       clear_mouse_face (hlinfo);
5244     }
5246   /* tooltip handling */
5247   previous_help_echo_string = help_echo_string;
5248   help_echo_string = Qnil;
5250   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5251                             last_mouse_motion_position.y))
5252     help_echo_string = previous_help_echo_string;
5254   XSETFRAME (frame, emacsframe);
5255   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5256     {
5257       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5258          (note_mouse_highlight), which is called through the
5259          note_mouse_movement () call above */
5260       gen_help_event (help_echo_string, frame, help_echo_window,
5261                       help_echo_object, help_echo_pos);
5262     }
5263   else
5264     {
5265       help_echo_string = Qnil;
5266       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5267     }
5269   if (emacsframe->mouse_moved && send_appdefined)
5270     ns_send_appdefined (-1);
5274 - (void)mouseDragged: (NSEvent *)e
5276   NSTRACE (mouseDragged);
5277   [self mouseMoved: e];
5281 - (void)rightMouseDragged: (NSEvent *)e
5283   NSTRACE (rightMouseDragged);
5284   [self mouseMoved: e];
5288 - (void)otherMouseDragged: (NSEvent *)e
5290   NSTRACE (otherMouseDragged);
5291   [self mouseMoved: e];
5295 - (BOOL)windowShouldClose: (id)sender
5297   NSEvent *e =[[self window] currentEvent];
5299   NSTRACE (windowShouldClose);
5300   windowClosing = YES;
5301   if (!emacs_event)
5302     return NO;
5303   emacs_event->kind = DELETE_WINDOW_EVENT;
5304   emacs_event->modifiers = 0;
5305   emacs_event->code = 0;
5306   EV_TRAILER (e);
5307   /* Don't close this window, let this be done from lisp code.  */
5308   return NO;
5312 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5313 /* normalize frame to gridded text size */
5315   NSTRACE (windowWillResize);
5316 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5318   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5319 #ifdef NS_IMPL_GNUSTEP
5320                                         frameSize.width + 3);
5321 #else
5322                                         frameSize.width);
5323 #endif
5324   if (cols < MINWIDTH)
5325     cols = MINWIDTH;
5327   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
5328 #ifdef NS_IMPL_GNUSTEP
5329       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
5330         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5331 #else
5332       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5333         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5334 #endif
5335   if (rows < MINHEIGHT)
5336     rows = MINHEIGHT;
5337 #ifdef NS_IMPL_COCOA
5338   {
5339     /* this sets window title to have size in it; the wm does this under GS */
5340     NSRect r = [[self window] frame];
5341     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5342       {
5343         if (old_title != 0)
5344           {
5345             xfree (old_title);
5346             old_title = 0;
5347           }
5348       }
5349     else
5350       {
5351         char *size_title;
5352         NSWindow *window = [self window];
5353         if (old_title == 0)
5354           {
5355             const char *t = [[[self window] title] UTF8String];
5356             char *pos = strstr (t, "  â€”  ");
5357             if (pos)
5358               *pos = '\0';
5359             old_title = xstrdup (t);
5360           }
5361         size_title = xmalloc (strlen (old_title) + 40);
5362         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5363         [window setTitle: [NSString stringWithUTF8String: size_title]];
5364         [window display];
5365         xfree (size_title);
5366       }
5367   }
5368 #endif /* NS_IMPL_COCOA */
5369 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5371   return frameSize;
5375 - (void)windowDidResize: (NSNotification *)notification
5377 #ifdef NS_IMPL_GNUSTEP
5378   NSWindow *theWindow = [notification object];
5380    /* in GNUstep, at least currently, it's possible to get a didResize
5381       without getting a willResize.. therefore we need to act as if we got
5382       the willResize now */
5383   NSSize sz = [theWindow frame].size;
5384   sz = [self windowWillResize: theWindow toSize: sz];
5385 #endif /* NS_IMPL_GNUSTEP */
5387   NSTRACE (windowDidResize);
5388 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5390 #ifdef NS_IMPL_COCOA
5391   if (old_title != 0)
5392     {
5393       xfree (old_title);
5394       old_title = 0;
5395     }
5396 #endif /* NS_IMPL_COCOA */
5398   /* Avoid loop under GNUstep due to call at beginning of this function.
5399      (x_set_window_size causes a resize which causes
5400      a "windowDidResize" which calls x_set_window_size).  */
5401 #ifndef NS_IMPL_GNUSTEP
5402   if (cols > 0 && rows > 0)
5403     {
5404       if (ns_in_resize)
5405         x_set_window_size (emacsframe, 0, cols, rows);
5406       else
5407         {
5408           NSWindow *window = [self window];
5409           NSRect wr = [window frame];
5410           FRAME_PIXEL_WIDTH (emacsframe) = (int)wr.size.width
5411             - emacsframe->border_width;
5412           FRAME_PIXEL_HEIGHT (emacsframe) = (int)wr.size.height
5413             - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5414             - FRAME_TOOLBAR_HEIGHT (emacsframe);
5415           change_frame_size (emacsframe, rows, cols, 0, 0, 1);
5416           SET_FRAME_GARBAGED (emacsframe);
5417           cancel_mouse_face (emacsframe);
5418         }
5419     }
5420 #endif
5422   ns_send_appdefined (-1);
5426 - (void)windowDidBecomeKey: (NSNotification *)notification
5427 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5429   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5430   struct frame *old_focus = dpyinfo->x_focus_frame;
5432   NSTRACE (windowDidBecomeKey);
5434   if (emacsframe != old_focus)
5435     dpyinfo->x_focus_frame = emacsframe;
5437   ns_frame_rehighlight (emacsframe);
5439   if (emacs_event)
5440     {
5441       emacs_event->kind = FOCUS_IN_EVENT;
5442       EV_TRAILER ((id)nil);
5443     }
5447 - (void)windowDidResignKey: (NSNotification *)notification
5448 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5450   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5451   NSTRACE (windowDidResignKey);
5453   if (dpyinfo->x_focus_frame == emacsframe)
5454     dpyinfo->x_focus_frame = 0;
5456   ns_frame_rehighlight (emacsframe);
5458   /* FIXME: for some reason needed on second and subsequent clicks away
5459             from sole-frame Emacs to get hollow box to show */
5460   if (!windowClosing && [[self window] isVisible] == YES)
5461     {
5462       x_update_cursor (emacsframe, 1);
5463       x_set_frame_alpha (emacsframe);
5464     }
5466   if (emacs_event)
5467     {
5468       [self deleteWorkingText];
5469       emacs_event->kind = FOCUS_IN_EVENT;
5470       EV_TRAILER ((id)nil);
5471     }
5475 - (void)windowWillMiniaturize: sender
5477   NSTRACE (windowWillMiniaturize);
5481 - (BOOL)isFlipped
5483   return YES;
5487 - (BOOL)isOpaque
5489   return NO;
5493 - initFrameFromEmacs: (struct frame *)f
5495   NSRect r, wr;
5496   Lisp_Object tem;
5497   NSWindow *win;
5498   NSButton *toggleButton;
5499   NSSize sz;
5500   NSColor *col;
5501   NSString *name;
5503   NSTRACE (initFrameFromEmacs);
5505   windowClosing = NO;
5506   processingCompose = NO;
5507   scrollbarsNeedingUpdate = 0;
5509 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5511   ns_userRect = NSMakeRect (0, 0, 0, 0);
5512   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5513                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5514   [self initWithFrame: r];
5515   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5517   FRAME_NS_VIEW (f) = self;
5518   emacsframe = f;
5519   old_title = 0;
5521   win = [[EmacsWindow alloc]
5522             initWithContentRect: r
5523                       styleMask: (NSResizableWindowMask |
5524 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5525                                   NSTitledWindowMask |
5526 #endif
5527                                   NSMiniaturizableWindowMask |
5528                                   NSClosableWindowMask)
5529                         backing: NSBackingStoreBuffered
5530                           defer: YES];
5532   wr = [win frame];
5533   f->border_width = wr.size.width - r.size.width;
5534   FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5536   [win setAcceptsMouseMovedEvents: YES];
5537   [win setDelegate: self];
5538   [win useOptimizedDrawing: YES];
5540   sz.width = FRAME_COLUMN_WIDTH (f);
5541   sz.height = FRAME_LINE_HEIGHT (f);
5542   [win setResizeIncrements: sz];
5544   [[win contentView] addSubview: self];
5546   if (ns_drag_types)
5547     [self registerForDraggedTypes: ns_drag_types];
5549   tem = f->name;
5550   name = [NSString stringWithUTF8String:
5551                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5552   [win setTitle: name];
5554   /* toolbar support */
5555   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5556                          [NSString stringWithFormat: @"Emacs Frame %d",
5557                                    ns_window_num]];
5558   [win setToolbar: toolbar];
5559   [toolbar setVisible: NO];
5560 #ifdef NS_IMPL_COCOA
5561   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5562   [toggleButton setTarget: self];
5563   [toggleButton setAction: @selector (toggleToolbar: )];
5564 #endif
5565   FRAME_TOOLBAR_HEIGHT (f) = 0;
5567   tem = f->icon_name;
5568   if (!NILP (tem))
5569     [win setMiniwindowTitle:
5570            [NSString stringWithUTF8String: SSDATA (tem)]];
5572   {
5573     NSScreen *screen = [win screen];
5575     if (screen != 0)
5576       [win setFrameTopLeftPoint: NSMakePoint
5577            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5578             IN_BOUND (-SCREENMAX,
5579                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5580   }
5582   [win makeFirstResponder: self];
5584   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5585                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5586   [win setBackgroundColor: col];
5587   if ([col alphaComponent] != 1.0)
5588     [win setOpaque: NO];
5590   [self allocateGState];
5592   [NSApp registerServicesMenuSendTypes: ns_send_types
5593                            returnTypes: nil];
5595   ns_window_num++;
5596   return self;
5600 - (void)windowDidMove: sender
5602   NSWindow *win = [self window];
5603   NSRect r = [win frame];
5604   NSArray *screens = [NSScreen screens];
5605   NSScreen *screen = [screens objectAtIndex: 0];
5607   NSTRACE (windowDidMove);
5609   if (!emacsframe->output_data.ns)
5610     return;
5611   if (screen != nil)
5612     {
5613       emacsframe->left_pos = r.origin.x;
5614       emacsframe->top_pos =
5615         [screen frame].size.height - (r.origin.y + r.size.height);
5616     }
5620 /* Called AFTER method below, but before our windowWillResize call there leads
5621    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5622    location so set_window_size moves the frame. */
5623 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5625   emacsframe->output_data.ns->zooming = 1;
5626   return YES;
5630 /* Override to do something slightly nonstandard, but nice.  First click on
5631    zoom button will zoom vertically.  Second will zoom completely.  Third
5632    returns to original. */
5633 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5634                         defaultFrame:(NSRect)defaultFrame
5636   NSRect result = [sender frame];
5638   NSTRACE (windowWillUseStandardFrame);
5640   if (abs (defaultFrame.size.height - result.size.height)
5641       > FRAME_LINE_HEIGHT (emacsframe))
5642     {
5643       /* first click */
5644       ns_userRect = result;
5645       result.size.height = defaultFrame.size.height;
5646       result.origin.y = defaultFrame.origin.y;
5647     }
5648   else
5649     {
5650       if (abs (defaultFrame.size.width - result.size.width)
5651           > FRAME_COLUMN_WIDTH (emacsframe))
5652         result = defaultFrame;  /* second click */
5653       else
5654         {
5655           /* restore */
5656           result = ns_userRect.size.height ? ns_userRect : result;
5657           ns_userRect = NSMakeRect (0, 0, 0, 0);
5658         }
5659     }
5661   [self windowWillResize: sender toSize: result.size];
5662   return result;
5666 - (void)windowDidDeminiaturize: sender
5668   NSTRACE (windowDidDeminiaturize);
5669   if (!emacsframe->output_data.ns)
5670     return;
5671   emacsframe->async_iconified = 0;
5672   emacsframe->async_visible   = 1;
5673   windows_or_buffers_changed++;
5675   if (emacs_event)
5676     {
5677       emacs_event->kind = ICONIFY_EVENT;
5678       EV_TRAILER ((id)nil);
5679     }
5683 - (void)windowDidExpose: sender
5685   NSTRACE (windowDidExpose);
5686   if (!emacsframe->output_data.ns)
5687     return;
5688   emacsframe->async_visible = 1;
5689   SET_FRAME_GARBAGED (emacsframe);
5691   if (send_appdefined)
5692     ns_send_appdefined (-1);
5696 - (void)windowDidMiniaturize: sender
5698   NSTRACE (windowDidMiniaturize);
5699   if (!emacsframe->output_data.ns)
5700     return;
5702   emacsframe->async_iconified = 1;
5703   emacsframe->async_visible = 0;
5705   if (emacs_event)
5706     {
5707       emacs_event->kind = ICONIFY_EVENT;
5708       EV_TRAILER ((id)nil);
5709     }
5713 - (void)mouseEntered: (NSEvent *)theEvent
5715   NSTRACE (mouseEntered);
5716   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5720 - (void)mouseExited: (NSEvent *)theEvent
5722   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
5724   NSTRACE (mouseExited);
5726   if (!hlinfo)
5727     return;
5729   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
5731   if (emacsframe == hlinfo->mouse_face_mouse_frame)
5732     {
5733       clear_mouse_face (hlinfo);
5734       hlinfo->mouse_face_mouse_frame = 0;
5735     }
5739 - menuDown: sender
5741   NSTRACE (menuDown);
5742   if (context_menu_value == -1)
5743     context_menu_value = [sender tag];
5744   else 
5745     {
5746       NSInteger tag = [sender tag];
5747       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
5748                                     emacsframe->menu_bar_vector,
5749                                     (void *)tag);
5750     }
5752   ns_send_appdefined (-1);
5753   return self;
5757 - (EmacsToolbar *)toolbar
5759   return toolbar;
5763 /* this gets called on toolbar button click */
5764 - toolbarClicked: (id)item
5766   NSEvent *theEvent;
5767   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
5769   NSTRACE (toolbarClicked);
5771   if (!emacs_event)
5772     return self;
5774   /* send first event (for some reason two needed) */
5775   theEvent = [[self window] currentEvent];
5776   emacs_event->kind = TOOL_BAR_EVENT;
5777   XSETFRAME (emacs_event->arg, emacsframe);
5778   EV_TRAILER (theEvent);
5780   emacs_event->kind = TOOL_BAR_EVENT;
5781 /*   XSETINT (emacs_event->code, 0); */
5782   emacs_event->arg = AREF (emacsframe->tool_bar_items,
5783                            idx + TOOL_BAR_ITEM_KEY);
5784   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5785   EV_TRAILER (theEvent);
5786   return self;
5790 - toggleToolbar: (id)sender
5792   if (!emacs_event)
5793     return self;
5795   emacs_event->kind = NS_NONKEY_EVENT;
5796   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
5797   EV_TRAILER ((id)nil);
5798   return self;
5802 - (void)drawRect: (NSRect)rect
5804   int x = NSMinX (rect), y = NSMinY (rect);
5805   int width = NSWidth (rect), height = NSHeight (rect);
5807   NSTRACE (drawRect);
5809   if (!emacsframe || !emacsframe->output_data.ns || ns_in_resize)
5810     return;
5812   ns_clear_frame_area (emacsframe, x, y, width, height);
5813   expose_frame (emacsframe, x, y, width, height);
5815   /*
5816     drawRect: may be called (at least in OS X 10.5) for invisible
5817     views as well for some reason.  Thus, do not infer visibility
5818     here.
5820     emacsframe->async_visible = 1;
5821     emacsframe->async_iconified = 0;
5822   */
5826 /* NSDraggingDestination protocol methods.  Actually this is not really a
5827    protocol, but a category of Object.  O well...  */
5829 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
5831   NSTRACE (draggingEntered);
5832   return NSDragOperationGeneric;
5836 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
5838   return YES;
5842 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
5844   id pb;
5845   int x, y;
5846   NSString *type;
5847   NSEvent *theEvent = [[self window] currentEvent];
5848   NSPoint position;
5850   NSTRACE (performDragOperation);
5852   if (!emacs_event)
5853     return NO;
5855   position = [self convertPoint: [sender draggingLocation] fromView: nil];
5856   x = lrint (position.x);  y = lrint (position.y);
5858   pb = [sender draggingPasteboard];
5859   type = [pb availableTypeFromArray: ns_drag_types];
5860   if (type == 0)
5861     {
5862       return NO;
5863     }
5864   else if ([type isEqualToString: NSFilenamesPboardType])
5865     {
5866       NSArray *files;
5867       NSEnumerator *fenum;
5868       NSString *file;
5870       if (!(files = [pb propertyListForType: type]))
5871         return NO;
5873       fenum = [files objectEnumerator];
5874       while ( (file = [fenum nextObject]) )
5875         {
5876           emacs_event->kind = NS_NONKEY_EVENT;
5877           emacs_event->code = KEY_NS_DRAG_FILE;
5878           XSETINT (emacs_event->x, x);
5879           XSETINT (emacs_event->y, y);
5880           ns_input_file = append2 (ns_input_file,
5881                                    build_string ([file UTF8String]));
5882           emacs_event->modifiers = EV_MODIFIERS (theEvent);
5883           EV_TRAILER (theEvent);
5884         }
5885       return YES;
5886     }
5887   else if ([type isEqualToString: NSURLPboardType])
5888     {
5889       NSString *file;
5890       NSURL *fileURL;
5892       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
5893           [fileURL isFileURL] == NO)
5894         return NO;
5896       file = [fileURL path];
5897       emacs_event->kind = NS_NONKEY_EVENT;
5898       emacs_event->code = KEY_NS_DRAG_FILE;
5899       XSETINT (emacs_event->x, x);
5900       XSETINT (emacs_event->y, y);
5901       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
5902       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5903       EV_TRAILER (theEvent);
5904       return YES;
5905     }
5906   else if ([type isEqualToString: NSStringPboardType]
5907            || [type isEqualToString: NSTabularTextPboardType])
5908     {
5909       NSString *data;
5911       if (! (data = [pb stringForType: type]))
5912         return NO;
5914       emacs_event->kind = NS_NONKEY_EVENT;
5915       emacs_event->code = KEY_NS_DRAG_TEXT;
5916       XSETINT (emacs_event->x, x);
5917       XSETINT (emacs_event->y, y);
5918       ns_input_text = build_string ([data UTF8String]);
5919       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5920       EV_TRAILER (theEvent);
5921       return YES;
5922     }
5923   else if ([type isEqualToString: NSColorPboardType])
5924     {
5925       NSColor *c = [NSColor colorFromPasteboard: pb];
5926       emacs_event->kind = NS_NONKEY_EVENT;
5927       emacs_event->code = KEY_NS_DRAG_COLOR;
5928       XSETINT (emacs_event->x, x);
5929       XSETINT (emacs_event->y, y);
5930       ns_input_color = ns_color_to_lisp (c);
5931       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5932       EV_TRAILER (theEvent);
5933       return YES;
5934     }
5935   else if ([type isEqualToString: NSFontPboardType])
5936     {
5937       /* impl based on GNUstep NSTextView.m */
5938       NSData *data = [pb dataForType: NSFontPboardType];
5939       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
5940       NSFont *font = [dict objectForKey: NSFontAttributeName];
5941       char fontSize[10];
5943       if (font == nil)
5944         return NO;
5946       emacs_event->kind = NS_NONKEY_EVENT;
5947       emacs_event->code = KEY_NS_CHANGE_FONT;
5948       XSETINT (emacs_event->x, x);
5949       XSETINT (emacs_event->y, y);
5950       ns_input_font = build_string ([[font fontName] UTF8String]);
5951       snprintf (fontSize, 10, "%f", [font pointSize]);
5952       ns_input_fontsize = build_string (fontSize);
5953       emacs_event->modifiers = EV_MODIFIERS (theEvent);
5954       EV_TRAILER (theEvent);
5955       return YES;
5956     }
5957   else
5958     {
5959       error ("Invalid data type in dragging pasteboard.");
5960       return NO;
5961     }
5965 - (id) validRequestorForSendType: (NSString *)typeSent
5966                       returnType: (NSString *)typeReturned
5968   NSTRACE (validRequestorForSendType);
5969   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
5970       && typeReturned == nil)
5971     {
5972       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
5973         return self;
5974     }
5976   return [super validRequestorForSendType: typeSent
5977                                returnType: typeReturned];
5981 /* The next two methods are part of NSServicesRequests informal protocol,
5982    supposedly called when a services menu item is chosen from this app.
5983    But this should not happen because we override the services menu with our
5984    own entries which call ns-perform-service.
5985    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
5986    So let's at least stub them out until further investigation can be done. */
5988 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
5990   /* we could call ns_string_from_pasteboard(pboard) here but then it should
5991      be written into the buffer in place of the existing selection..
5992      ordinary service calls go through functions defined in ns-win.el */
5993   return NO;
5996 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
5998   NSArray *typesDeclared;
5999   Lisp_Object val;
6001   /* We only support NSStringPboardType */
6002   if ([types containsObject:NSStringPboardType] == NO) {
6003     return NO;
6004   }
6006   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6007   if (CONSP (val) && SYMBOLP (XCAR (val)))
6008     {
6009       val = XCDR (val);
6010       if (CONSP (val) && NILP (XCDR (val)))
6011         val = XCAR (val);
6012     }
6013   if (! STRINGP (val))
6014     return NO;
6016   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6017   [pb declareTypes:typesDeclared owner:nil];
6018   ns_string_to_pasteboard (pb, val);
6019   return YES;
6023 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6024    (gives a miniaturized version of the window); currently we use the latter for
6025    frames whose active buffer doesn't correspond to any file
6026    (e.g., '*scratch*') */
6027 - setMiniwindowImage: (BOOL) setMini
6029   id image = [[self window] miniwindowImage];
6030   NSTRACE (setMiniwindowImage);
6032   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6033      about "AppleDockIconEnabled" notwithstanding, however the set message
6034      below has its effect nonetheless. */
6035   if (image != emacsframe->output_data.ns->miniimage)
6036     {
6037       if (image && [image isKindOfClass: [EmacsImage class]])
6038         [image release];
6039       [[self window] setMiniwindowImage:
6040                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6041     }
6043   return self;
6047 - (void) setRows: (int) r andColumns: (int) c
6049   rows = r;
6050   cols = c;
6053 @end  /* EmacsView */
6057 /* ==========================================================================
6059     EmacsWindow implementation
6061    ========================================================================== */
6063 @implementation EmacsWindow
6065 #ifdef NS_IMPL_COCOA
6066 - (id)accessibilityAttributeValue:(NSString *)attribute
6068   Lisp_Object str = Qnil;
6069   struct frame *f = SELECTED_FRAME ();
6070   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->buffer);
6072   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6073     return NSAccessibilityTextFieldRole;
6075   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6076       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6077     {
6078       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6079     }
6080   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6081     {
6082       if (! NILP (BVAR (curbuf, mark_active)))
6083           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6084       
6085       if (NILP (str))
6086         {
6087           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6088           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6089           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6090           
6091           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6092             str = make_uninit_multibyte_string (range, byte_range);
6093           else
6094             str = make_uninit_string (range);
6095           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6096              Is this a problem?  */
6097           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6098         }
6099     }
6100   
6101   
6102   if (! NILP (str)) 
6103     {
6104       if (CONSP (str) && SYMBOLP (XCAR (str)))
6105         {
6106           str = XCDR (str);
6107           if (CONSP (str) && NILP (XCDR (str)))
6108             str = XCAR (str);
6109         }
6110       if (STRINGP (str))
6111         {
6112           const char *utfStr = SSDATA (str);
6113           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6114           return nsStr;
6115         }
6116     }
6117   
6118   return [super accessibilityAttributeValue:attribute];
6120 #endif /* NS_IMPL_COCOA */
6122 /* If we have multiple monitors, one above the other, we don't want to
6123    restrict the height to just one monitor.  So we override this.  */
6124 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6126   /* When making the frame visible for the first time or if there is just
6127      one screen, we want to constrain.  Other times not.  */
6128   NSUInteger nr_screens = [[NSScreen screens] count];
6129   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6130   NSTRACE (constrainFrameRect);
6132   if (nr_screens == 1)
6133     return [super constrainFrameRect:frameRect toScreen:screen];
6135   if (f->output_data.ns->dont_constrain
6136       || ns_menu_bar_should_be_hidden ())
6137     return frameRect;
6139   f->output_data.ns->dont_constrain = 1;
6140   return [super constrainFrameRect:frameRect toScreen:screen];
6144 /* called only on resize clicks by special case in EmacsApp-sendEvent */
6145 - (void)mouseDown: (NSEvent *)theEvent
6147   if (ns_in_resize)
6148     {
6149       NSSize size = [[theEvent window] frame].size;
6150       grabOffset = [theEvent locationInWindow];
6151       grabOffset.x = size.width - grabOffset.x;
6152     }
6153   else
6154     [super mouseDown: theEvent];
6158 /* stop resizing */
6159 - (void)mouseUp: (NSEvent *)theEvent
6161   if (ns_in_resize)
6162     {
6163       struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6164       ns_in_resize = NO;
6165       ns_set_name_as_filename (f);
6166       [self display];
6167       ns_send_appdefined (-1);
6168     }
6169   else
6170     [super mouseUp: theEvent];
6174 /* send resize events */
6175 - (void)mouseDragged: (NSEvent *)theEvent
6177   if (ns_in_resize)
6178     {
6179       NSPoint p = [theEvent locationInWindow];
6180       NSSize size, vettedSize, origSize = [self frame].size;
6182       size.width = p.x + grabOffset.x;
6183       size.height = origSize.height - p.y + grabOffset.y;
6185       if (size.width == origSize.width && size.height == origSize.height)
6186         return;
6188       vettedSize = [[self delegate] windowWillResize: self toSize: size];
6189       [[NSNotificationCenter defaultCenter]
6190             postNotificationName: NSWindowDidResizeNotification
6191                           object: self];
6192     }
6193   else
6194     [super mouseDragged: theEvent];
6197 @end /* EmacsWindow */
6200 /* ==========================================================================
6202     EmacsScroller implementation
6204    ========================================================================== */
6207 @implementation EmacsScroller
6209 /* for repeat button push */
6210 #define SCROLL_BAR_FIRST_DELAY 0.5
6211 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6213 + (CGFloat) scrollerWidth
6215   /* TODO: if we want to allow variable widths, this is the place to do it,
6216            however neither GNUstep nor Cocoa support it very well */
6217   return [NSScroller scrollerWidth];
6221 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6223   NSTRACE (EmacsScroller_initFrame);
6225   r.size.width = [EmacsScroller scrollerWidth];
6226   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6227   [self setContinuous: YES];
6228   [self setEnabled: YES];
6230   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6231      locked against the top and bottom edges, and right edge on OS X, where
6232      scrollers are on right. */
6233 #ifdef NS_IMPL_GNUSTEP
6234   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6235 #else
6236   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6237 #endif
6239   win = nwin;
6240   condemned = NO;
6241   pixel_height = NSHeight (r);
6242   if (pixel_height == 0) pixel_height = 1;
6243   min_portion = 20 / pixel_height;
6245   frame = XFRAME (XWINDOW (win)->frame);
6246   if (FRAME_LIVE_P (frame))
6247     {
6248       int i;
6249       EmacsView *view = FRAME_NS_VIEW (frame);
6250       NSView *sview = [[view window] contentView];
6251       NSArray *subs = [sview subviews];
6253       /* disable optimization stopping redraw of other scrollbars */
6254       view->scrollbarsNeedingUpdate = 0;
6255       for (i =[subs count]-1; i >= 0; i--)
6256         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6257           view->scrollbarsNeedingUpdate++;
6258       [sview addSubview: self];
6259     }
6261 /*  [self setFrame: r]; */
6263   return self;
6267 - (void)setFrame: (NSRect)newRect
6269   NSTRACE (EmacsScroller_setFrame);
6270 /*  BLOCK_INPUT; */
6271   pixel_height = NSHeight (newRect);
6272   if (pixel_height == 0) pixel_height = 1;
6273   min_portion = 20 / pixel_height;
6274   [super setFrame: newRect];
6275   [self display];
6276 /*  UNBLOCK_INPUT; */
6280 - (void)dealloc
6282   NSTRACE (EmacsScroller_dealloc);
6283   if (!NILP (win))
6284     WSET (XWINDOW (win), vertical_scroll_bar, Qnil);
6285   [super dealloc];
6289 - condemn
6291   NSTRACE (condemn);
6292   condemned =YES;
6293   return self;
6297 - reprieve
6299   NSTRACE (reprieve);
6300   condemned =NO;
6301   return self;
6305 - judge
6307   NSTRACE (judge);
6308   if (condemned)
6309     {
6310       EmacsView *view;
6311       BLOCK_INPUT;
6312       /* ensure other scrollbar updates after deletion */
6313       view = (EmacsView *)FRAME_NS_VIEW (frame);
6314       if (view != nil)
6315         view->scrollbarsNeedingUpdate++;
6316       [self removeFromSuperview];
6317       [self release];
6318       UNBLOCK_INPUT;
6319     }
6320   return self;
6324 - (void)resetCursorRects
6326   NSRect visible = [self visibleRect];
6327   NSTRACE (resetCursorRects);
6329   if (!NSIsEmptyRect (visible))
6330     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6331   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6335 - (int) checkSamePosition: (int) position portion: (int) portion
6336                     whole: (int) whole
6338   return em_position ==position && em_portion ==portion && em_whole ==whole
6339     && portion != whole; /* needed for resize empty buf */
6343 - setPosition: (int)position portion: (int)portion whole: (int)whole
6345   NSTRACE (setPosition);
6347   em_position = position;
6348   em_portion = portion;
6349   em_whole = whole;
6351   if (portion >= whole)
6352     {
6353 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6354       [self setKnobProportion: 1.0];
6355       [self setDoubleValue: 1.0];
6356 #else
6357       [self setFloatValue: 0.0 knobProportion: 1.0];
6358 #endif
6359     }
6360   else
6361     {
6362       float pos, por;
6363       portion = max ((float)whole*min_portion/pixel_height, portion);
6364       pos = (float)position / (whole - portion);
6365       por = (float)portion/whole;
6366 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6367       [self setKnobProportion: por];
6368       [self setDoubleValue: pos];
6369 #else
6370       [self setFloatValue: pos knobProportion: por];
6371 #endif
6372     }
6373   return self;
6376 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6377      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6378 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6379                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6381   *part = last_hit_part;
6382   *window = win;
6383   XSETINT (*y, pixel_height);
6384   if ([self floatValue] > 0.999)
6385     XSETINT (*x, pixel_height);
6386   else
6387     XSETINT (*x, pixel_height * [self floatValue]);
6391 /* set up emacs_event */
6392 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6394   if (!emacs_event)
6395     return;
6397   emacs_event->part = last_hit_part;
6398   emacs_event->code = 0;
6399   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6400   emacs_event->frame_or_window = win;
6401   emacs_event->timestamp = EV_TIMESTAMP (e);
6402   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6403   emacs_event->arg = Qnil;
6404   XSETINT (emacs_event->x, loc * pixel_height);
6405   XSETINT (emacs_event->y, pixel_height-20);
6407   n_emacs_events_pending++;
6408   kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6409   EVENT_INIT (*emacs_event);
6410   ns_send_appdefined (-1);
6414 /* called manually thru timer to implement repeated button action w/hold-down */
6415 - repeatScroll: (NSTimer *)scrollEntry
6417   NSEvent *e = [[self window] currentEvent];
6418   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6419   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6421   /* clear timer if need be */
6422   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6423     {
6424         [scroll_repeat_entry invalidate];
6425         [scroll_repeat_entry release];
6426         scroll_repeat_entry = nil;
6428         if (inKnob)
6429           return self;
6431         scroll_repeat_entry
6432           = [[NSTimer scheduledTimerWithTimeInterval:
6433                         SCROLL_BAR_CONTINUOUS_DELAY
6434                                             target: self
6435                                           selector: @selector (repeatScroll:)
6436                                           userInfo: 0
6437                                            repeats: YES]
6438               retain];
6439     }
6441   [self sendScrollEventAtLoc: 0 fromEvent: e];
6442   return self;
6446 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6447    mouseDragged events without going into a modal loop. */
6448 - (void)mouseDown: (NSEvent *)e
6450   NSRect sr, kr;
6451   /* hitPart is only updated AFTER event is passed on */
6452   NSScrollerPart part = [self testPart: [e locationInWindow]];
6453   double inc = 0.0, loc, kloc, pos;
6454   int edge = 0;
6456   NSTRACE (EmacsScroller_mouseDown);
6458   switch (part)
6459     {
6460     case NSScrollerDecrementPage:
6461         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6462     case NSScrollerIncrementPage:
6463         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6464     case NSScrollerDecrementLine:
6465       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6466     case NSScrollerIncrementLine:
6467       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6468     case NSScrollerKnob:
6469       last_hit_part = scroll_bar_handle; break;
6470     case NSScrollerKnobSlot:  /* GNUstep-only */
6471       last_hit_part = scroll_bar_move_ratio; break;
6472     default:  /* NSScrollerNoPart? */
6473       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6474                (long) part);
6475       return;
6476     }
6478   if (inc != 0.0)
6479     {
6480       pos = 0;      /* ignored */
6482       /* set a timer to repeat, as we can't let superclass do this modally */
6483       scroll_repeat_entry
6484         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6485                                             target: self
6486                                           selector: @selector (repeatScroll:)
6487                                           userInfo: 0
6488                                            repeats: YES]
6489             retain];
6490     }
6491   else
6492     {
6493       /* handle, or on GNUstep possibly slot */
6494       NSEvent *fake_event;
6496       /* compute float loc in slot and mouse offset on knob */
6497       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6498                       toView: nil];
6499       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6500       if (loc <= 0.0)
6501         {
6502           loc = 0.0;
6503           edge = -1;
6504         }
6505       else if (loc >= NSHeight (sr))
6506         {
6507           loc = NSHeight (sr);
6508           edge = 1;
6509         }
6511       if (edge)
6512         kloc = 0.5 * edge;
6513       else
6514         {
6515           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6516                           toView: nil];
6517           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6518         }
6519       last_mouse_offset = kloc;
6521       /* if knob, tell emacs a location offset by knob pos
6522          (to indicate top of handle) */
6523       if (part == NSScrollerKnob)
6524           pos = (loc - last_mouse_offset) / NSHeight (sr);
6525       else
6526         /* else this is a slot click on GNUstep: go straight there */
6527         pos = loc / NSHeight (sr);
6529       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6530       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6531                                       location: [e locationInWindow]
6532                                  modifierFlags: [e modifierFlags]
6533                                      timestamp: [e timestamp]
6534                                   windowNumber: [e windowNumber]
6535                                        context: [e context]
6536                                    eventNumber: [e eventNumber]
6537                                     clickCount: [e clickCount]
6538                                       pressure: [e pressure]];
6539       [super mouseUp: fake_event];
6540     }
6542   if (part != NSScrollerKnob)
6543     [self sendScrollEventAtLoc: pos fromEvent: e];
6547 /* Called as we manually track scroller drags, rather than superclass. */
6548 - (void)mouseDragged: (NSEvent *)e
6550     NSRect sr;
6551     double loc, pos;
6552     int edge = 0;
6554     NSTRACE (EmacsScroller_mouseDragged);
6556       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6557                       toView: nil];
6558       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6560       if (loc <= 0.0)
6561         {
6562           loc = 0.0;
6563           edge = -1;
6564         }
6565       else if (loc >= NSHeight (sr) + last_mouse_offset)
6566         {
6567           loc = NSHeight (sr) + last_mouse_offset;
6568           edge = 1;
6569         }
6571       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6572       [self sendScrollEventAtLoc: pos fromEvent: e];
6576 - (void)mouseUp: (NSEvent *)e
6578   if (scroll_repeat_entry)
6579     {
6580       [scroll_repeat_entry invalidate];
6581       [scroll_repeat_entry release];
6582       scroll_repeat_entry = nil;
6583     }
6584   last_hit_part = 0;
6588 /* treat scrollwheel events in the bar as though they were in the main window */
6589 - (void) scrollWheel: (NSEvent *)theEvent
6591   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6592   [view mouseDown: theEvent];
6595 @end  /* EmacsScroller */
6600 /* ==========================================================================
6602    Font-related functions; these used to be in nsfaces.m
6604    ========================================================================== */
6607 Lisp_Object
6608 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6610   struct font *font = XFONT_OBJECT (font_object);
6612   if (fontset < 0)
6613     fontset = fontset_from_font (font_object);
6614   FRAME_FONTSET (f) = fontset;
6616   if (FRAME_FONT (f) == font)
6617     /* This font is already set in frame F.  There's nothing more to
6618        do.  */
6619     return font_object;
6621   FRAME_FONT (f) = font;
6623   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6624   FRAME_COLUMN_WIDTH (f) = font->average_width;
6625   FRAME_SPACE_WIDTH (f) = font->space_width;
6626   FRAME_LINE_HEIGHT (f) = font->height;
6628   compute_fringe_widths (f, 1);
6630   /* Compute the scroll bar width in character columns.  */
6631   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6632     {
6633       int wid = FRAME_COLUMN_WIDTH (f);
6634       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6635         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6636     }
6637   else
6638     {
6639       int wid = FRAME_COLUMN_WIDTH (f);
6640       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6641     }
6643   /* Now make the frame display the given font.  */
6644   if (FRAME_NS_WINDOW (f) != 0)
6645         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6647   return font_object;
6651 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6652 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6653          in 1.43. */
6655 const char *
6656 ns_xlfd_to_fontname (const char *xlfd)
6657 /* --------------------------------------------------------------------------
6658     Convert an X font name (XLFD) to an NS font name.
6659     Only family is used.
6660     The string returned is temporarily allocated.
6661    -------------------------------------------------------------------------- */
6663   char *name = xmalloc (180);
6664   int i, len;
6665   const char *ret;
6667   if (!strncmp (xlfd, "--", 2))
6668     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6669   else
6670     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6672   /* stopgap for malformed XLFD input */
6673   if (strlen (name) == 0)
6674     strcpy (name, "Monaco");
6676   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6677      also uppercase after '-' or ' ' */
6678   name[0] = toupper (name[0]);
6679   for (len =strlen (name), i =0; i<len; i++)
6680     {
6681       if (name[i] == '$')
6682         {
6683           name[i] = '-';
6684           if (i+1<len)
6685             name[i+1] = toupper (name[i+1]);
6686         }
6687       else if (name[i] == '_')
6688         {
6689           name[i] = ' ';
6690           if (i+1<len)
6691             name[i+1] = toupper (name[i+1]);
6692         }
6693     }
6694 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
6695   ret = [[NSString stringWithUTF8String: name] UTF8String];
6696   xfree (name);
6697   return ret;
6701 void
6702 syms_of_nsterm (void)
6704   NSTRACE (syms_of_nsterm);
6706   ns_antialias_threshold = 10.0;
6708   /* from 23+ we need to tell emacs what modifiers there are.. */
6709   DEFSYM (Qmodifier_value, "modifier-value");
6710   DEFSYM (Qalt, "alt");
6711   DEFSYM (Qhyper, "hyper");
6712   DEFSYM (Qmeta, "meta");
6713   DEFSYM (Qsuper, "super");
6714   DEFSYM (Qcontrol, "control");
6715   DEFSYM (QUTF8_STRING, "UTF8_STRING");
6717   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
6718   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
6719   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
6720   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
6721   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
6723   DEFVAR_LISP ("ns-input-file", ns_input_file,
6724               "The file specified in the last NS event.");
6725   ns_input_file =Qnil;
6727   DEFVAR_LISP ("ns-input-text", ns_input_text,
6728               "The data received in the last NS text drag event.");
6729   ns_input_text =Qnil;
6731   DEFVAR_LISP ("ns-working-text", ns_working_text,
6732               "String for visualizing working composition sequence.");
6733   ns_working_text =Qnil;
6735   DEFVAR_LISP ("ns-input-font", ns_input_font,
6736               "The font specified in the last NS event.");
6737   ns_input_font =Qnil;
6739   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
6740               "The fontsize specified in the last NS event.");
6741   ns_input_fontsize =Qnil;
6743   DEFVAR_LISP ("ns-input-line", ns_input_line,
6744                "The line specified in the last NS event.");
6745   ns_input_line =Qnil;
6747   DEFVAR_LISP ("ns-input-color", ns_input_color,
6748                "The color specified in the last NS event.");
6749   ns_input_color =Qnil;
6751   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
6752                "The service name specified in the last NS event.");
6753   ns_input_spi_name =Qnil;
6755   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
6756                "The service argument specified in the last NS event.");
6757   ns_input_spi_arg =Qnil;
6759   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
6760                "This variable describes the behavior of the alternate or option key.\n\
6761 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6762 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6763 at all, allowing it to be used at a lower level for accented character entry.");
6764   ns_alternate_modifier = Qmeta;
6766   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
6767                "This variable describes the behavior of the right alternate or option key.\n\
6768 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6769 Set to left means be the same key as `ns-alternate-modifier'.\n\
6770 Set to none means that the alternate / option key is not interpreted by Emacs\n\
6771 at all, allowing it to be used at a lower level for accented character entry.");
6772   ns_right_alternate_modifier = Qleft;
6774   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
6775                "This variable describes the behavior of the command key.\n\
6776 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6777   ns_command_modifier = Qsuper;
6779   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
6780                "This variable describes the behavior of the right command key.\n\
6781 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6782 Set to left means be the same key as `ns-command-modifier'.\n\
6783 Set to none means that the command / option key is not interpreted by Emacs\n\
6784 at all, allowing it to be used at a lower level for accented character entry.");
6785   ns_right_command_modifier = Qleft;
6787   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
6788                "This variable describes the behavior of the control key.\n\
6789 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
6790   ns_control_modifier = Qcontrol;
6792   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
6793                "This variable describes the behavior of the right control key.\n\
6794 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6795 Set to left means be the same key as `ns-control-modifier'.\n\
6796 Set to none means that the control / option key is not interpreted by Emacs\n\
6797 at all, allowing it to be used at a lower level for accented character entry.");
6798   ns_right_control_modifier = Qleft;
6800   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
6801                "This variable describes the behavior of the function key (on laptops).\n\
6802 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
6803 Set to none means that the function key is not interpreted by Emacs at all,\n\
6804 allowing it to be used at a lower level for accented character entry.");
6805   ns_function_modifier = Qnone;
6807   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
6808                "Non-nil (the default) means to render text antialiased. Only has an effect on OS X Panther and above.");
6809   ns_antialias_text = Qt;
6811   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
6812                "Whether to confirm application quit using dialog.");
6813   ns_confirm_quit = Qnil;
6815   staticpro (&ns_display_name_list);
6816   ns_display_name_list = Qnil;
6818   staticpro (&last_mouse_motion_frame);
6819   last_mouse_motion_frame = Qnil;
6821   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
6822                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
6823 Only works on OSX 10.6 or later.  */);
6824   ns_auto_hide_menu_bar = Qnil;
6826   /* TODO: move to common code */
6827   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
6828                doc: /* Which toolkit scroll bars Emacs uses, if any.
6829 A value of nil means Emacs doesn't use toolkit scroll bars.
6830 With the X Window system, the value is a symbol describing the
6831 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
6832 With MS Windows or Nextstep, the value is t.  */);
6833   Vx_toolkit_scroll_bars = Qt;
6835   DEFVAR_BOOL ("x-use-underline-position-properties",
6836                x_use_underline_position_properties,
6837      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
6838 A value of nil means ignore them.  If you encounter fonts with bogus
6839 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
6840 to 4.1, set this to nil. */);
6841   x_use_underline_position_properties = 0;
6843   DEFVAR_BOOL ("x-underline-at-descent-line",
6844                x_underline_at_descent_line,
6845      doc: /* Non-nil means to draw the underline at the same place as the descent line.
6846 A value of nil means to draw the underline according to the value of the
6847 variable `x-use-underline-position-properties', which is usually at the
6848 baseline level.  The default value is nil.  */);
6849   x_underline_at_descent_line = 0;
6851   /* Tell emacs about this window system. */
6852   Fprovide (intern ("ns"), Qnil);